diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index d2292f3..7cbc630 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -13,7 +13,12 @@ name: Claude Code Review # read context (persist-credentials: false) and never build or execute PR code. on: pull_request_target: - types: [opened, synchronize, reopened, ready_for_review] + # labeled: lets adding the claude-debug label (see the "Check for + # claude-debug label" step below) kick off a fresh run by itself, with no + # push/re-run needed. Scoped in the job's `if:` below to only actually + # proceed when the label added IS claude-debug -- otherwise every + # unrelated label added to a PR would trigger another paid review. + types: [opened, synchronize, reopened, ready_for_review, labeled] concurrency: group: claude-review-${{ github.event.pull_request.number }} @@ -33,7 +38,8 @@ jobs: # fork-checkout step's safety. if: >- github.event.pull_request.draft == false && - github.event.pull_request.head.repo.owner.login == 'jnasbyupgrade' + github.event.pull_request.head.repo.owner.login == 'jnasbyupgrade' && + (github.event.action != 'labeled' || github.event.label.name == 'claude-debug') runs-on: ubuntu-latest timeout-minutes: 60 permissions: @@ -48,6 +54,28 @@ jobs: # existing trusted-fork-owner gate below, not instead of it. actions: write steps: + # DEBUG MODE: add the "claude-debug" label to a PR to (a) skip the cost + # gate below entirely -- a debug session shouldn't wait 5-20+ min per + # iteration on sibling CI -- and (b) get show_full_output: true on the + # Run Claude Code Review step, dumping the full raw Claude Code JSON + # transcript (including tool results -- see that input's own WARNING + # below) to the job log. This is how you'd catch something like a + # silently-swallowed `--comment` flag (see that step's other comment). + # Queried live via `gh pr view`, not the static event payload, so + # adding the label and clicking "Re-run jobs" on an existing run picks + # it up without needing a new push. + - name: Check for claude-debug label + id: debug + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + PR: ${{ github.event.pull_request.number }} + run: | + enabled=$(gh pr view "$PR" --repo "$REPO" --json labels \ + --jq 'any(.labels[]; .name == "claude-debug")') + echo "enabled=$enabled" >> "$GITHUB_OUTPUT" + echo "claude-debug label present: $enabled" + # 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 @@ -63,6 +91,7 @@ jobs: # gate never waits on or fails because of itself. - name: Wait for CI; skip the paid review if any check failed id: gate + if: steps.debug.outputs.enabled != 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.repository }} @@ -90,7 +119,7 @@ jobs: echo "gate decision: $decision" - name: Check out PR head (read-only context) - if: steps.gate.outputs.decision == 'run' + if: steps.debug.outputs.enabled == 'true' || 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@v6 @@ -107,10 +136,15 @@ jobs: allow-unsafe-pr-checkout: true - name: Run Claude Code Review - if: steps.gate.outputs.decision == 'run' + if: steps.debug.outputs.enabled == 'true' || steps.gate.outputs.decision == 'run' uses: anthropics/claude-code-action@v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + # See the "Check for claude-debug label" step above -- WARNING (from + # this input's own description): outputs ALL Claude messages + # including tool execution results, which may contain secrets, and + # these logs are publicly visible in GitHub Actions. + show_full_output: ${{ steps.debug.outputs.enabled == 'true' }} # 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