Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 49 additions & 31 deletions .github/workflows/doc-orchestrator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# Installation:
# 1. Copy this file to .github/workflows/doc-orchestrator.yml in your target repository
# 2. Configure these GitHub Secrets in the target repository (Settings > Secrets):
# - ANTHROPIC_API_KEY: For AI processing (Stage 1 & 3)
# - ANTHROPIC_API_KEY: For the VoltAgent stages (3 & 4); Stages 1 and 2 call Claude through the hub
# - OPENAI_API_KEY: For CodeWiki (Stage 2)
# - DOC_ORCH_WEBHOOK_SECRET: For callback authentication
# - DOC_ORCH_GITHUB_PAT: (Optional) For private dependency access
Expand Down Expand Up @@ -192,10 +192,14 @@ jobs:
env:
WEBHOOK_SECRET: ${{ secrets.DOC_ORCH_WEBHOOK_SECRET }}
run: |
SCRIPTS_BASE_URL="${HUB_BASE_URL}/api/ci/scripts"

# Function to download and verify script
SCRIPT_MANIFEST=/tmp/flamingo-script-manifest.json
# WEBHOOK_SECRET reaches curl through a 0600 config file, never argv β€” see
# curlAuthPreamble, which always traps the removal.
CURL_CFG=$(mktemp) && chmod 600 "$CURL_CFG"
trap 'rm -f "$CURL_CFG"' EXIT
printf 'header = "Authorization: Bearer %s"\n' "$WEBHOOK_SECRET" > "$CURL_CFG"
# The canonical scripts surface and the pre-rename one. load_script_manifest
# picks whichever this deployment actually serves and pins SCRIPTS_BASE_URL.
CI_SCRIPTS_URL="${HUB_BASE_URL%/}/api/ci/scripts"
Expand All @@ -205,7 +209,7 @@ jobs:
_try_manifest() {
local base="$1" code
code=$(curl -sS -w '%{http_code}' -o "$SCRIPT_MANIFEST" \
-H "Authorization: Bearer $WEBHOOK_SECRET" \
-K "$CURL_CFG" \
"$base/manifest.json") || code="000"

if [ "$code" = "404" ]; then rm -f "$SCRIPT_MANIFEST"; return 1; fi
Expand Down Expand Up @@ -283,7 +287,7 @@ jobs:
fi

curl -fsSL "$SCRIPTS_BASE_URL/$script_name" \
-H "Authorization: Bearer $WEBHOOK_SECRET" \
-K "$CURL_CFG" \
-o "$output_path"

local actual_hash=$(shasum -a 256 "$output_path" | cut -d' ' -f1)
Expand Down Expand Up @@ -364,12 +368,13 @@ jobs:
run: |
echo "πŸ“₯ Downloading workflow scripts..."

# Construct URLs from hub base URL β€” see /api/ci/scripts/[name] route
SCRIPTS_BASE_URL="${HUB_BASE_URL}/api/ci/scripts"
CALLBACK_URL="${HUB_BASE_URL}/api/doc-orchestrator/webhook"

# Function to download and verify script
SCRIPT_MANIFEST=/tmp/flamingo-script-manifest.json
# WEBHOOK_SECRET reaches curl through a 0600 config file, never argv β€” see
# curlAuthPreamble, which always traps the removal.
CURL_CFG=$(mktemp) && chmod 600 "$CURL_CFG"
trap 'rm -f "$CURL_CFG"' EXIT
printf 'header = "Authorization: Bearer %s"\n' "$WEBHOOK_SECRET" > "$CURL_CFG"
# The canonical scripts surface and the pre-rename one. load_script_manifest
# picks whichever this deployment actually serves and pins SCRIPTS_BASE_URL.
CI_SCRIPTS_URL="${HUB_BASE_URL%/}/api/ci/scripts"
Expand All @@ -379,7 +384,7 @@ jobs:
_try_manifest() {
local base="$1" code
code=$(curl -sS -w '%{http_code}' -o "$SCRIPT_MANIFEST" \
-H "Authorization: Bearer $WEBHOOK_SECRET" \
-K "$CURL_CFG" \
"$base/manifest.json") || code="000"

if [ "$code" = "404" ]; then rm -f "$SCRIPT_MANIFEST"; return 1; fi
Expand Down Expand Up @@ -457,7 +462,7 @@ jobs:
fi

curl -fsSL "$SCRIPTS_BASE_URL/$script_name" \
-H "Authorization: Bearer $WEBHOOK_SECRET" \
-K "$CURL_CFG" \
-o "$output_path"

local actual_hash=$(shasum -a 256 "$output_path" | cut -d' ' -f1)
Expand Down Expand Up @@ -513,9 +518,10 @@ jobs:
echo ""
echo "πŸ“‹ Downloading Flamingo Markdown Guidelines..."
GUIDELINES_URL="${HUB_BASE_URL}/api/doc-orchestrator/guidelines"
# Same 0600 config file the download block above set up.
HTTP_CODE=$(curl -fsSL -w "%{http_code}" \
"$GUIDELINES_URL" \
-H "Authorization: Bearer $WEBHOOK_SECRET" \
-K "$CURL_CFG" \
-o "/tmp/flamingo-markdown-guidelines.md" 2>/dev/null) || HTTP_CODE="failed"

if [ "$HTTP_CODE" = "200" ]; then
Expand Down Expand Up @@ -1556,21 +1562,23 @@ jobs:
# commit step below reads it to know work was already pushed.
rm -f "$STAGE1_PUSH_MARKER"

# Run with unified timeout helper (12 hours default)
# Script already downloaded to /tmp/ in setup step
run_with_timeout "Stage 1" "$STAGE1_TIMEOUT_HOURS" node /tmp/generate-inline-docs.cjs || true
# Continue - don't fail the workflow, preserve partial results
# Script already downloaded to /tmp/ in setup step. run_stage records
# the outcome as stage1_status β€” see its note in workflow-helpers.sh.
run_stage "Stage 1" "$STAGE1_TIMEOUT_HOURS" stage1_status node /tmp/generate-inline-docs.cjs

# Count generated files (hidden .*.md files)
INLINE_DOCS=$(find . -name ".*.md" -newer .git -type f -not -path "./node_modules/*" -not -path "./.git/*" | wc -l)
set_output "stage1_files" "$INLINE_DOCS"
set_output "stage1_status" "completed"

# =========================================================================
# COMMIT STAGE 1 RESULTS (Progressive PR)
# =========================================================================
# `!= ''`, not `== 'completed'`: runs on a FAILED stage too β€” see run_stage
# in workflow-helpers.sh (partial output is worth committing; the status
# is what reports the truth home). The build gate holds every run_stage
# commit step to this predicate.
- name: Commit and Push Stage 1 Results
if: always() && steps.stage1.outputs.stage1_status == 'completed'
if: always() && steps.stage1.outputs.stage1_status != ''
id: commit-stage1
env:
BRANCH_NAME: ${{ steps.create-pr-branch.outputs.branch_name }}
Expand Down Expand Up @@ -1622,6 +1630,9 @@ jobs:
# Runs immediately after Stage 1 to clean up orphaned inline docs
# Orphan = .*.md file where source file was deleted
# =========================================================================
# `== 'completed'` HERE IS DELIBERATE, unlike the commit steps: deleting
# "orphaned" docs after a stage that FAILED would delete docs whose
# sources were never re-examined.
- name: Clean Up Orphaned Inline Documentation Files
if: always() && steps.stage1.outputs.stage1_status == 'completed'
id: orphan-detection-inline
Expand Down Expand Up @@ -2312,10 +2323,9 @@ jobs:

echo "πŸ€– Stage 3: VoltAgent Tutorial Generator starting..."

# Run with unified timeout helper (6 hours default)
# Script already downloaded to /tmp/ in setup step
run_with_timeout "Stage 3" "$STAGE3_TIMEOUT_HOURS" node /tmp/generate-tutorials-voltagent.cjs || true
# Continue - don't fail the workflow, preserve partial results
# Script already downloaded to /tmp/ in setup step. run_stage records
# the outcome as stage3_status β€” see its note in workflow-helpers.sh.
run_stage "Stage 3" "$STAGE3_TIMEOUT_HOURS" stage3_status node /tmp/generate-tutorials-voltagent.cjs

# Count files from both OSS Tenant Structure directories
GETTING_STARTED_FILES=$(count_markdown_files "${GETTING_STARTED_OUTPUT_PATH}")
Expand All @@ -2325,13 +2335,13 @@ jobs:
echo " Development: $DEVELOPMENT_FILES files"
echo " Total Stage 3: $TUTORIAL_FILES files"
set_output "stage3_files" "$TUTORIAL_FILES"
set_output "stage3_status" "completed"

# =========================================================================
# COMMIT STAGE 3 RESULTS (Progressive PR)
# =========================================================================
# `!= ''` β€” the run_stage commit rule, stated once at Stage 1.
- name: Commit and Push Stage 3 Results
if: always() && steps.stage3.outputs.stage3_status == 'completed'
if: always() && steps.stage3.outputs.stage3_status != ''
id: commit-stage3
env:
BRANCH_NAME: ${{ steps.create-pr-branch.outputs.branch_name }}
Expand Down Expand Up @@ -2522,7 +2532,11 @@ jobs:
echo ""
echo "πŸ€– Generating repository documentation with VoltAgent..."
# Script already downloaded to /tmp/ in Download Workflow Scripts step
run_with_timeout "Stage 4" "$STAGE4_TIMEOUT_HOURS" node /tmp/generate-repo-docs.cjs || true
# run_stage records the outcome as stage4_status β€” see its note in
# workflow-helpers.sh. The file count below is REPORTING, not a
# status: inferring "completed" from it meant a crashed run that left
# a previous commit's README standing reported success.
run_stage "Stage 4" "$STAGE4_TIMEOUT_HOURS" stage4_status node /tmp/generate-repo-docs.cjs

# === STEP 4: Count results ===
echo ""
Expand All @@ -2538,20 +2552,19 @@ jobs:

set_output "stage4_files" "$REPO_DOCS"
if [ "$REPO_DOCS" -gt 0 ]; then
set_output "stage4_status" "completed"
echo ""
echo "βœ… Stage 4 completed: $REPO_DOCS repository documentation files"
echo "βœ… Stage 4 produced $REPO_DOCS repository documentation file(s)"
else
set_output "stage4_status" "skipped"
echo ""
echo "⚠️ Stage 4 skipped: No repository documentation files generated"
echo "⚠️ Stage 4 produced no repository documentation files"
fi

# =========================================================================
# COMMIT STAGE 4 RESULTS (Progressive PR)
# =========================================================================
# `!= ''` β€” the run_stage commit rule, stated once at Stage 1.
- name: Commit and Push Stage 4 Results
if: always() && steps.stage4.outputs.stage4_status == 'completed'
if: always() && steps.stage4.outputs.stage4_status != ''
id: commit-stage4
env:
BRANCH_NAME: ${{ steps.create-pr-branch.outputs.branch_name }}
Expand Down Expand Up @@ -2888,8 +2901,13 @@ jobs:
# it so the hub's run row fails NOW instead of waiting for the reaper.
if [ ! -f /tmp/workflow-helpers.sh ]; then
echo "::error::workflow-helpers.sh missing β€” sending bootstrap-failure callback"
curl -sS --max-time 30 -X POST "${HUB_BASE_URL}/api/doc-orchestrator/webhook" \
-H "Content-Type: application/json" -H "Authorization: Bearer $WEBHOOK_SECRET" \
# The bearer goes through a 0600 config file, never argv β€” see
# curlAuthPreamble in lib/config/workflow-scripts-bootstrap.ts.
CURL_CFG=$(mktemp) && chmod 600 "$CURL_CFG"
trap 'rm -f "$CURL_CFG"' EXIT
printf 'header = "Authorization: Bearer %s"\n' "$WEBHOOK_SECRET" > "$CURL_CFG"
curl -sS --max-time 30 -K "$CURL_CFG" -X POST "${HUB_BASE_URL}/api/doc-orchestrator/webhook" \
-H "Content-Type: application/json" \
-d "{\"run_id\":\"$RUN_ID\",\"repo_id\":\"$REPO_ID\",\"status\":\"failure\",\"workflow_run_id\":$WORKFLOW_RUN_ID,\"workflow_url\":\"$WORKFLOW_URL\",\"error\":\"Script bootstrap failed: workflow-helpers.sh never downloaded from the hub.\"}" || true
exit 1
fi
Expand Down