Audit Upstream Updates #20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Audit Upstream Updates | |
| on: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "0 9 * * 1" # Every Monday at 9 AM | |
| permissions: | |
| contents: read | |
| id-token: write | |
| issues: write | |
| jobs: | |
| audit-updates: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: false | |
| - name: Run phase-1 upstream audit (bash only) | |
| id: audit | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| ./tools/audit_upstream.sh | tee audit_table.md | |
| { | |
| echo "# Weekly upstream audit" | |
| echo | |
| cat audit_table.md | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| items=$(wc -l < audit_upstream_items.ndjson | awk '{print $1}') | |
| echo "items=${items:-0}" >> "$GITHUB_OUTPUT" | |
| # Ensure the upstream-update label exists so phase-2 doesn't spend | |
| # turns creating it. | |
| gh label create upstream-update \ | |
| --color A0DCFB --description "Pinned submodule is behind upstream" \ | |
| 2>/dev/null || true | |
| - name: Classify changes and file issues (Claude) | |
| if: steps.audit.outputs.items != '0' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| prompt: | | |
| audit_upstream_items.ndjson in the repo root contains one JSON | |
| object per submodule that is behind upstream. Each object has: | |
| path, owner, repo, branch, pinned, upstream, behind, pinned_date, | |
| upstream_date, days_stale, existing_issue, existing_state. | |
| `existing_issue` is the number of an already-filed | |
| "Upstream update available: <path>" issue (or empty string if | |
| none). `existing_state` is "OPEN" or "CLOSED" when present. | |
| For each item: | |
| 1. Fetch the commit list via | |
| `gh api repos/{owner}/{repo}/compare/{pinned}...{upstream} --jq '.commits[] | "\(.sha[0:7]) \(.commit.message | split("\n")[0])"'` | |
| 2. Classify the diff as: | |
| - minor : docs, CI, tests, whitespace, cosmetic only | |
| - moderate: bug fixes, small features, dep bumps | |
| - major : architecture/API/RTL-affecting changes, new deps | |
| 3. Decide what to do based on severity AND existing_issue: | |
| - MINOR + no existing_issue → do nothing. | |
| - MINOR + existing OPEN issue → `gh issue comment <n>` once | |
| noting the change is now classified minor; do not edit | |
| the body or close the issue (humans triage state). | |
| - MODERATE/MAJOR + no existing_issue → `gh issue create` | |
| with title "Upstream update available: <path>" and label | |
| `upstream-update`. | |
| - MODERATE/MAJOR + existing_issue (any state) → | |
| `gh issue edit <existing_issue> --body-file <file>` with | |
| refreshed contents. Do NOT reopen a CLOSED issue and do | |
| NOT change its state — humans control that. | |
| 4. The body (for create or edit) contains: | |
| - pinned → upstream SHAs and dates | |
| - commits behind, days stale | |
| - severity classification with justification | |
| - short bulleted summary of what changed | |
| - recommendation (update now / defer / ignore) | |
| - "Last refreshed: <UTC timestamp>" footer | |
| Never open more than one issue per submodule path. Keep per-item | |
| work bounded: a few gh api calls each. Do not clone repos, | |
| regenerate RTL, open PRs, or modify any files in the repo. | |
| claude_args: '--max-turns 60 --allowedTools Bash --allowedTools Read' | |
| - name: Upload audit artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: upstream-audit | |
| path: | | |
| audit_table.md | |
| audit_upstream_items.ndjson | |
| if-no-files-found: ignore |