Skip to content

Commit fe02bbf

Browse files
committed
fix(review): skip the review when context gathering fails
1 parent 2cf1da5 commit fe02bbf

2 files changed

Lines changed: 47 additions & 4 deletions

File tree

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

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,24 @@ jobs:
168168
#
169169
# Reduce execution log -- needs steps.review.outputs.execution_file, empty when skipped
170170
# Upload tool usage -- needs steps.tool-usage.outcome == 'success', which is 'skipped'
171-
# Notify on failure -- needs outcome 'failure' or 'cancelled', and this is 'skipped'
171+
# Notify on failure -- carries its own !inputs.dry_run, because it can now also fire
172+
# on a context failure rather than only on a review failure
172173
#
173174
# So a smoke run posts no review, no comment and no artifact. Everything before this step
174175
# still runs against the live API: the app token, the cross-repo prompt checkout, and the
175176
# nine context reads with the job's real permissions.
177+
#
178+
# steps.context.outcome, because the context step is continue-on-error and therefore fails
179+
# green. Anything that stops the script running -- a checkout that does not deliver it, a
180+
# renamed path, a sparse pattern that stops matching -- leaves pr_context, threads and
181+
# review_cycle unset, and an empty context is not a neutral one: a blank REVIEW CYCLE and an
182+
# empty prior-comments block read as cycle 1 with nothing raised before. That is a false
183+
# statement to the model, of exactly the kind the script's own guards exist to prevent, and
184+
# it would reach every consumer repo at once. No context, no review.
176185
- uses: anthropics/claude-code-action@v1
177-
if: github.event.pull_request.user.login != 'dependabot[bot]' && !inputs.dry_run
186+
if: >-
187+
github.event.pull_request.user.login != 'dependabot[bot]' && !inputs.dry_run
188+
&& steps.context.outcome == 'success'
178189
id: review
179190
continue-on-error: true
180191
with:
@@ -267,8 +278,15 @@ jobs:
267278
# (~100 review runs/week org-wide); the question is days-old, not quarters.
268279
retention-days: 14
269280

281+
# Also on a context failure, which now skips the review rather than feeding it an empty
282+
# context. Without this clause that path is the silent one: no review, no comment, green
283+
# check -- the shape of failure this workflow keeps being bitten by. !inputs.dry_run because
284+
# a smoke run reaches this step with the review skipped and must never write.
270285
- name: Notify on review failure
271-
if: github.event.pull_request.user.login != 'dependabot[bot]' && (steps.review.outcome == 'failure' || steps.review.outcome == 'cancelled')
272-
run: gh pr comment ${{ github.event.pull_request.number }} --body "Automated review unavailable (Claude step failed). Please review manually."
286+
if: >-
287+
github.event.pull_request.user.login != 'dependabot[bot]' && !inputs.dry_run
288+
&& (steps.review.outcome == 'failure' || steps.review.outcome == 'cancelled'
289+
|| steps.context.outcome == 'failure')
290+
run: gh pr comment ${{ github.event.pull_request.number }} --body "Automated review unavailable (the review step failed, or the context it needs could not be gathered). Please review manually."
273291
env:
274292
GH_TOKEN: ${{ github.token }}

‎tests/workflow-lint-test.sh‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,31 @@ check_permission "statusCheckRollup" statuses "the StatusContext half of the CI
162162
check_permission "/compare/" contents "the since-last-review comparison"
163163
check_permission "/pulls/" pull-requests "the PR reads"
164164

165+
# The context step is continue-on-error, so everything it can fail at -- a checkout that does not
166+
# deliver the script, a bad path, a rename that stops matching the sparse pattern -- leaves the run
167+
# green with pr_context, threads and review_cycle all unset. Ungated, the review step then runs on
168+
# that: a blank REVIEW CYCLE and an empty prior-comments block read as cycle 1 with nothing raised
169+
# before, which is a false statement rather than a missing one, and it reaches every consumer repo
170+
# at once. The script's own guards exist to stop exactly that claim, and they cannot help if the
171+
# script never ran. So the review must be gated on the context step having succeeded.
172+
# The condition is a folded block, so collect its continuation lines too: everything indented
173+
# past the `if:` key, up to the next key of the step.
174+
review_gate=$(awk '/^ - uses: anthropics\/claude-code-action/ { found = 1; next }
175+
found && /^ if:/ { print; in_if = 1; next }
176+
in_if && /^ / { print; next }
177+
in_if { exit }' "$WORKFLOW_FILE")
178+
if [ -z "$review_gate" ]; then
179+
echo "FAIL could not find the review step's if: in $WORKFLOW_FILE; this check proves nothing"
180+
failures=$((failures + 1))
181+
elif ! printf '%s\n' "$review_gate" | grep -q "steps\.context\.outcome == 'success'"; then
182+
echo "FAIL the review step does not require the context step to have succeeded, so a failed"
183+
echo " context read sends the model an empty context that reads as a clean cycle 1:"
184+
printf '%s\n' "$review_gate" | sed 's/^/ /'
185+
failures=$((failures + 1))
186+
else
187+
echo "ok the review step runs only when the context step succeeded"
188+
fi
189+
165190
# The table above forces a new API call in the context step to declare its permission on the
166191
# review job. That does nothing for the smoke job in tests.yml, which calls the review workflow
167192
# and has to grant the same set by hand: a caller cannot give a reusable workflow more than it

0 commit comments

Comments
 (0)