Add testing of pg_upgrade #273
Workflow file for this run
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: Claude Code Review | |
| # Runs on PRs INTO this repo. We use pull_request_target (not pull_request) so | |
| # that the workflow definition always comes from the base branch, never from | |
| # the PR's own head - a plain `pull_request` run uses whatever workflow file | |
| # is on the PR branch itself, which a same-repo feature branch could modify to | |
| # steal secrets before this ever runs. | |
| # | |
| # SECURITY: pull_request_target runs in the BASE repo with secrets and a | |
| # write-capable token. The job is gated to PRs authored by jnasbyupgrade only | |
| # — CLAUDE_CODE_OAUTH_TOKEN is tied to their personal Claude account, and this | |
| # repo has other collaborators (e.g. decibel) whose PRs shouldn't burn it. | |
| # github.event.pull_request.user.login is the PR's original author and can't | |
| # be spoofed by PR content, so this check holds regardless of whether the PR | |
| # head lives in this repo or an external fork (an arbitrary external fork | |
| # still can't trigger this secret-bearing job unless it's actually | |
| # jnasbyupgrade's own fork). The workflow file always comes from the base | |
| # branch (master), so a PR cannot modify the reviewer that runs on it. We | |
| # check out the PR head only for read context (persist-credentials: false) | |
| # and never build or execute PR code. | |
| on: | |
| pull_request_target: | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| concurrency: | |
| group: claude-review-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| claude-review: | |
| # jnasbyupgrade's own PRs only, and skip drafts (don't spend API/CI on | |
| # unfinished PRs). | |
| if: >- | |
| github.event.pull_request.draft == false && | |
| github.event.pull_request.user.login == 'jnasbyupgrade' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| permissions: | |
| contents: read | |
| pull-requests: write # post the review comments | |
| checks: read # read sibling check-runs for the cost gate | |
| steps: | |
| # COST GATE: the paid Claude review is the last thing to run. Wait for the | |
| # PR head's OTHER check-runs to finish and only proceed if they are clean. | |
| # If any sibling check failed we skip the review to avoid spending money | |
| # reviewing a PR that is already known-broken. Uniform across all repos: | |
| # it discovers sibling checks dynamically (no per-repo workflow names). | |
| # - decision=run : all sibling checks completed with a good conclusion, | |
| # OR no sibling checks exist after a short grace window | |
| # (nothing to gate on), OR the poll timed out is treated | |
| # as skip (see below). | |
| # - decision=skip : at least one sibling check failed/cancelled/etc, or | |
| # we timed out waiting for still-pending checks. | |
| # We exclude this workflow's own check-run (job name `claude-review`) so the | |
| # gate never waits on or fails because of itself. | |
| - name: Wait for CI; skip the paid review if any check failed | |
| id: gate | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| SHA: ${{ github.event.pull_request.head.sha }} | |
| run: | | |
| decision=skip | |
| for i in $(seq 1 72); do # ~24 min max | |
| json=$(gh api "repos/$REPO/commits/$SHA/check-runs" --paginate \ | |
| --jq '[.check_runs[] | select(.name != "claude-review")]' 2>/dev/null) || json='' | |
| [ -z "$json" ] && { sleep 20; continue; } | |
| total=$(jq 'length' <<<"$json") | |
| if [ "$total" -eq 0 ]; then | |
| [ "$i" -ge 9 ] && { decision=run; break; } # ~3 min grace: nothing to gate on | |
| sleep 20; continue | |
| fi | |
| pending=$(jq '[.[]|select(.status!="completed")]|length' <<<"$json") | |
| if [ "$pending" -eq 0 ]; then | |
| bad=$(jq '[.[]|select((.conclusion//"")|test("^(failure|cancelled|timed_out|action_required|stale)$"))]|length' <<<"$json") | |
| [ "$bad" -eq 0 ] && decision=run || decision=skip | |
| break | |
| fi | |
| sleep 20 | |
| done | |
| echo "decision=$decision" >> "$GITHUB_OUTPUT" | |
| echo "gate decision: $decision" | |
| - name: Check out PR head (read-only context) | |
| if: steps.gate.outputs.decision == 'run' | |
| # Intentionally tracks the major-version tag (not a pinned SHA) so | |
| # upstream fixes are picked up automatically. | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ github.event.pull_request.head.repo.full_name }} | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| fetch-depth: 1 | |
| persist-credentials: false | |
| - name: Run Claude Code Review | |
| if: steps.gate.outputs.decision == 'run' | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| # Provide github_token so the action uses it directly for GitHub API | |
| # calls instead of the OIDC->GitHub-App-token exchange, which 401s under | |
| # pull_request_target. GITHUB_TOKEN is repo/workflow-scoped (independent | |
| # of the actor's role) and has pull-requests: write here. | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| # A `prompt:` input puts the action in "automation mode", which by | |
| # default posts nothing until the whole run finishes -- there's no | |
| # visibility into a review that runs long. track_progress forces a | |
| # tracking PR comment with a live checklist that updates as Claude | |
| # works, so a slow run is visible instead of silent. | |
| track_progress: true | |
| # NOTE: plugin_marketplaces can't be pinned — it tracks the | |
| # marketplace repo's default branch (upstream anthropics/claude-code). | |
| plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' | |
| plugins: 'code-review@claude-code-plugins' | |
| # --comment is required: without it, the code-review plugin only | |
| # prints its findings to the job log and never posts anything to | |
| # the PR (confirmed by capturing the hidden SDK transcript on a | |
| # canary PR in pgxntool-test: the review correctly found an | |
| # injected bug but ended with "No `--comment` argument was | |
| # provided, so no GitHub comments were posted"). Every review run | |
| # before this fix has been silently invisible on GitHub. | |
| prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }} --comment' |