main
yml 147 lines 6.12 KB
Raw
1 name: Trigger podcast generation
2
3 on:
4 workflow_dispatch:
5 # checkov:skip=CKV_GHA_7:Operational dispatch workflow (not a release build). Inputs select the target week/run-id and optional breaking-news context; they do not alter published build artifacts. Inputs are required for manual operation.
6 inputs:
7 week:
8 description: 'Week slug, e.g. 2026-W25'
9 required: true
10 type: string
11 publish_run_id:
12 description: 'Optional: crawl-and-publish workflow run ID that produced the manifest. If omitted, uses the most recent.'
13 required: false
14 type: string
15 breaking_news:
16 description: 'Optional last-moment news or important information to include in this podcast episode.'
17 required: false
18 type: string
19
20 permissions:
21 contents: read
22
23 concurrency:
24 group: ${{ github.workflow }}-${{ github.ref }}
25 cancel-in-progress: false
26
27 jobs:
28 trigger-podcast:
29 runs-on: ubuntu-latest
30 permissions:
31 contents: read
32
33 steps:
34 - name: Check out repository
35 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
36 with:
37 persist-credentials: false
38
39 - name: Set up Python
40 uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
41 with:
42 python-version: '3.12'
43
44 - name: Derive paths from week slug
45 id: derive
46 env:
47 WEEK: ${{ inputs.week }}
48 run: |
49 set -euo pipefail
50 if [[ ! "$WEEK" =~ ^[0-9]{4}-W[0-9]{2}$ ]]; then
51 echo "::error::week must match YYYY-WNN (two-digit week), e.g. 2026-W25 (got: $WEEK)"
52 exit 1
53 fi
54
55 # 2026-W25 → year=2026, short=W25
56 YEAR="${WEEK%%-*}"
57 SHORT="${WEEK##*-}"
58 echo "article_path=content/weekly/${YEAR}/${SHORT}.md" >> "$GITHUB_OUTPUT"
59 echo "article_url=https://claracle.com/weekly/${YEAR}/${SHORT}/" >> "$GITHUB_OUTPUT"
60
61 - name: Locate publish manifest from crawl-and-publish
62 id: manifest-locate
63 env:
64 WEEK: ${{ inputs.week }}
65 PUBLISH_RUN_ID_INPUT: ${{ inputs.publish_run_id }}
66 run: |
67 set -euo pipefail
68 if ! git fetch origin publish 2>/dev/null; then
69 echo "::error::Could not fetch publish branch. Has crawl-and-publish run yet?"
70 exit 1
71 fi
72 git checkout origin/publish -- data/candidates/ 2>/dev/null || true
73
74 if [ -n "$PUBLISH_RUN_ID_INPUT" ]; then
75 # Use specified run ID
76 if ! [[ "$PUBLISH_RUN_ID_INPUT" =~ ^[0-9]+$ ]]; then
77 echo "::error::publish_run_id must be a numeric workflow run ID (got: $PUBLISH_RUN_ID_INPUT)"
78 exit 1
79 fi
80 MANIFEST="data/candidates/${WEEK}/${PUBLISH_RUN_ID_INPUT}/publish-manifest.json"
81 if [ ! -f "$MANIFEST" ]; then
82 echo "::error::Manifest not found at $MANIFEST for specified run $PUBLISH_RUN_ID_INPUT"
83 exit 1
84 fi
85 echo "manifest_path=$MANIFEST" >> "$GITHUB_OUTPUT"
86 echo "publish_run_id=$PUBLISH_RUN_ID_INPUT" >> "$GITHUB_OUTPUT"
87 echo "::notice::Using manifest from specified run: $PUBLISH_RUN_ID_INPUT"
88 else
89 # Find the most recent manifest for this week
90 MANIFEST=$(find "data/candidates/${WEEK}" -name 'publish-manifest.json' -type f 2>/dev/null | sort -V | tail -1)
91 if [ -z "$MANIFEST" ]; then
92 echo "::error::No manifest found for week $WEEK in data/candidates/. Has crawl-and-publish completed for this week?"
93 exit 1
94 fi
95 # Extract run ID from path: data/candidates/WEEK/RUN_ID/publish-manifest.json
96 RUN_ID="$(basename "$(dirname "$MANIFEST")")"
97 echo "manifest_path=$MANIFEST" >> "$GITHUB_OUTPUT"
98 echo "publish_run_id=$RUN_ID" >> "$GITHUB_OUTPUT"
99 echo "::notice::Using manifest from most recent run: $RUN_ID"
100 fi
101
102 - name: Trigger podcast generation with existing manifest
103 env:
104 PODCASTER_ENDPOINT: ${{ vars.PODCASTER_ENDPOINT }}
105 PODCASTER_API_KEY: ${{ secrets.PODCASTER_API_KEY }}
106 WEEK: ${{ inputs.week }}
107 ARTICLE_URL: ${{ steps.derive.outputs.article_url }}
108 ARTICLE_PATH: ${{ steps.derive.outputs.article_path }}
109 MANIFEST_FILE: ${{ steps.manifest-locate.outputs.manifest_path }}
110 PUBLISH_RUN_ID: ${{ steps.manifest-locate.outputs.publish_run_id }}
111 TRIGGER_RUN_ID: ${{ github.run_id }}
112 BREAKING_NEWS: ${{ inputs.breaking_news || '' }}
113 run: |
114 set -euo pipefail
115 if [ -z "$PODCASTER_ENDPOINT" ] || [ -z "$PODCASTER_API_KEY" ]; then
116 echo "::error::Requires PODCASTER_ENDPOINT variable and PODCASTER_API_KEY secret."
117 exit 1
118 fi
119 if [ ! -f "$ARTICLE_PATH" ]; then
120 # Article may already be published on the publish branch but not yet
121 # merged into main via the sync PR. Fall back to the publish branch.
122 git checkout origin/publish -- "$ARTICLE_PATH" 2>/dev/null || {
123 echo "::error::Article '$ARTICLE_PATH' does not exist on main or the publish branch."
124 exit 1
125 }
126 fi
127 if [ ! -f "$MANIFEST_FILE" ]; then
128 echo "::error::Manifest file not found: $MANIFEST_FILE"
129 exit 1
130 fi
131 echo "::notice::Using manifest from crawl-and-publish run $PUBLISH_RUN_ID ($(date -r "$MANIFEST_FILE" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo 'date unknown'))"
132
133 BREAKING_ARGS=()
134 if [ -n "$BREAKING_NEWS" ]; then
135 BREAKING_ARGS=(--breaking-news "$BREAKING_NEWS")
136 fi
137
138 # Trigger real podcast generation using the existing validated manifest
139 python3 scripts/podcaster_handoff.py \
140 --week "$WEEK" \
141 --article-url "$ARTICLE_URL" \
142 --article-path "$ARTICLE_PATH" \
143 --publish-run-id "$PUBLISH_RUN_ID" \
144 --publish-mode normal \
145 --manifest "$MANIFEST_FILE" \
146 --podcast-config config/podcast.json \
147 "${BREAKING_ARGS[@]}"