Skip to content

Commit 536421a

Browse files
committed
test(ci): smoke-run the review workflow in CI
1 parent 8b04393 commit 536421a

2 files changed

Lines changed: 74 additions & 3 deletions

File tree

‎.github/workflows/claude-pr-review.yml‎

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,31 @@ name: Claude PR Review
33
on:
44
pull_request:
55
types: [opened, synchronize, ready_for_review, reopened]
6-
6+
# Callable so this repository's own CI can run this file and prove it starts. That is not a
7+
# theoretical worry: an org ruleset injects this workflow into every repo resolved from
8+
# `main`, so a pull request here is reviewed by main's copy and never by the copy it is
9+
# changing. Twice in one day a file that Actions refuses to parse merged green -- an empty
10+
# expression delimiter in a shell comment, then a `run:` block past the 21,000-character
11+
# expression limit -- because nothing in CI had ever executed the version under review.
12+
#
13+
# tests.yml calls this with `uses: ./...`, which resolves from the calling commit, so the
14+
# smoke run is the pull request's copy. A copy Actions cannot load fails the caller too, which
15+
# is the whole point: "does it start" is exactly what both outages got wrong.
16+
workflow_call:
17+
inputs:
18+
dry_run:
19+
description: >-
20+
Everything except the review itself. Set by tests.yml, never on the production path,
21+
where `inputs` is empty and this reads as false.
22+
type: boolean
23+
default: false
24+
25+
# Distinct groups for the smoke run and the live review, because a called workflow inherits the
26+
# caller's `github` context: both would otherwise compute pr-review-<same number> on the same
27+
# pull request, and cancel-in-progress would have each cancelling the other. A smoke test that
28+
# kills real reviews is worse than no smoke test.
729
concurrency:
8-
group: pr-review-${{ github.event.pull_request.number }}
30+
group: pr-review-${{ inputs.dry_run && 'smoke' || 'live' }}-${{ github.event.pull_request.number }}
931
cancel-in-progress: true
1032

1133
jobs:
@@ -509,8 +531,19 @@ jobs:
509531
PR_TITLE: ${{ github.event.pull_request.title }}
510532
PR_BODY: ${{ github.event.pull_request.body }}
511533

534+
# The only step a dry run skips, and the only one it needs to: every step after this one
535+
# is already gated on this step's outcome or its outputs, so skipping it silences the whole
536+
# write side of the workflow without a second condition anywhere.
537+
#
538+
# Reduce execution log -- needs steps.review.outputs.execution_file, empty when skipped
539+
# Upload tool usage -- needs steps.tool-usage.outcome == 'success', which is 'skipped'
540+
# Notify on failure -- needs outcome 'failure' or 'cancelled', and this is 'skipped'
541+
#
542+
# So a smoke run posts no review, no comment and no artifact. Everything before this step
543+
# still runs against the live API: the app token, the cross-repo prompt checkout, and the
544+
# nine context reads with the job's real permissions.
512545
- uses: anthropics/claude-code-action@v1
513-
if: github.event.pull_request.user.login != 'dependabot[bot]'
546+
if: github.event.pull_request.user.login != 'dependabot[bot]' && !inputs.dry_run
514547
id: review
515548
continue-on-error: true
516549
with:

‎.github/workflows/tests.yml‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,41 @@ jobs:
5454

5555
- name: Context step end to end
5656
run: tests/context-step-test.sh
57+
58+
# Runs claude-pr-review.yml itself, from this commit, with the review step skipped. The checks
59+
# above all read the workflow as text; this one hands it to Actions and asks whether it starts.
60+
#
61+
# That is the gap the last two outages went through. An org ruleset injects the review workflow
62+
# into every repo resolved from `main`, so the review on a pull request here comes from main's
63+
# copy -- never from the copy the pull request is changing. Both times, a file Actions refuses
64+
# to parse merged with this suite green, and the org lost reviews until someone noticed: an
65+
# empty expression delimiter inside a shell comment, then a `run:` block over the
66+
# 21,000-character expression limit. Neither is visible to yaml.safe_load, to bash, or to
67+
# actionlint, and enumerating the next limit ahead of time is a game with no end. Executing the
68+
# file has no such gap -- if Actions will not load it, this job cannot start, and CI is red.
69+
#
70+
# `uses: ./` resolves from the calling commit rather than from the default branch, which is what
71+
# makes this the pull request's copy and not main's.
72+
smoke:
73+
name: Review workflow starts
74+
# The same set the called job declares. A caller cannot grant a reusable workflow more than
75+
# it holds, and the point of this job is to exercise the real thing: the nine context reads
76+
# each need their permission, and a missing one degrades silently into a "could not read"
77+
# sentence rather than failing. pull-requests: write is unused on this path -- the only two
78+
# steps that write are skipped with the review step -- but it is what production runs with,
79+
# and a smoke test that runs with a different token is testing a different workflow.
80+
permissions:
81+
contents: read
82+
pull-requests: write
83+
id-token: write
84+
actions: read
85+
issues: read
86+
checks: read
87+
statuses: read
88+
uses: ./.github/workflows/claude-pr-review.yml
89+
with:
90+
dry_run: true
91+
# The GitHub App private key, for the token step and the cross-repo prompt checkout. Both run
92+
# in a dry run, so a broken sparse-checkout or an expired key surfaces here rather than in the
93+
# org.
94+
secrets: inherit

0 commit comments

Comments
 (0)