Skip to content
Merged
11 changes: 9 additions & 2 deletions .github/workflows/claude-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,17 @@ jobs:
# .github/workflows/<file> portion; strip the directory to get just
# the filename `gh workflow run` expects.
WF_FILE=$(basename "$WF_PATH")
echo "Dispatching $WF_FILE to review PR #$PR_NUMBER (/review comment)."
# This job never checks out the repo, so the PR's head branch has to
# be looked up explicitly. --ref pins the dispatched run's check-runs
# to that branch instead of the default branch workflow_dispatch
# falls back to when no ref is given (#285) --- without it,
# `require-review`'s check-run lands on the wrong commit and never
# supersedes a stale cancelled run tied to the PR's real head SHA.
PR_BRANCH=$(gh api "repos/$REPO/pulls/$PR_NUMBER" --jq '.head.ref')
echo "Dispatching $WF_FILE to review PR #$PR_NUMBER ($PR_BRANCH) (/review comment)."
# --repo is required: this job doesn't check out the repo, so gh has no
# git remote to infer it from (and gh doesn't read GITHUB_REPOSITORY).
gh workflow run "$WF_FILE" --repo "$REPO" -f pr_number="$PR_NUMBER"
gh workflow run "$WF_FILE" --repo "$REPO" --ref "$PR_BRANCH" -f pr_number="$PR_NUMBER"
gh issue comment "$PR_NUMBER" --repo "$REPO" \
--body ":mag: \`/review\` received — dispatched a Claude review of this PR (see the [dispatch run]($RUN_URL)). The review posts as its own comment when it finishes." \
|| echo "::warning::Could not acknowledge the /review comment."
Expand Down
44 changes: 36 additions & 8 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -875,11 +875,24 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REVIEW_WF: ${{ inputs.review-workflow-file }}
PR_BRANCH: ${{ steps.pr_checkout.outputs.branch }}
run: |
PR_NUMBER="${{ github.event.pull_request.number || github.event.issue.number }}"
echo "Dispatching $REVIEW_WF for PR #$PR_NUMBER (@claude review comment)."
gh workflow run "$REVIEW_WF" -f pr_number="$PR_NUMBER" \
|| echo "::warning::Could not dispatch $REVIEW_WF; review will not auto-run."
# --ref pins the dispatched run's check-runs to the PR's own head
# branch instead of the default branch workflow_dispatch falls back
# to when no ref is given (#285) --- without it, `require-review`'s
# check-run lands on the wrong commit and never supersedes a stale
# cancelled run tied to the PR's real head SHA. PR_BRANCH comes from
# the "Checkout PR branch" step above; if that step failed, this
# step still runs (always()), so skip rather than dispatch with an
# empty --ref.
if [ -z "$PR_BRANCH" ]; then
echo "::warning::PR_BRANCH is empty (checkout may have failed); skipping $REVIEW_WF dispatch."
else
gh workflow run "$REVIEW_WF" --ref "$PR_BRANCH" -f pr_number="$PR_NUMBER" \
|| echo "::warning::Could not dispatch $REVIEW_WF; review will not auto-run."
fi

# If an `@claude review` arrived as a LATE comment (posted after the
# trigger and absorbed by this session's polling), the dedup marks it so
Expand All @@ -905,6 +918,7 @@ jobs:
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
TRIGGER_TS: ${{ github.event.comment.created_at || github.event.review.submitted_at || github.event.issue.created_at }}
REVIEW_WF: ${{ inputs.review-workflow-file }}
PR_BRANCH: ${{ steps.pr_checkout.outputs.branch }}
run: |
# `|| late=0` keeps the default `-e` from aborting on a transient gh
# api error, degrading to "no late review found" rather than failing.
Expand All @@ -916,8 +930,14 @@ jobs:
'[.[] | select((((.created_at // .submitted_at) // "") > $ts) and ((.body // "") | test("@claude review")) and ((.user.type // "") != "Bot"))] | length' ) || late=0
if [ "${late:-0}" -gt 0 ]; then
echo "Found $late late @claude review request(s) newer than $TRIGGER_TS; dispatching review."
gh workflow run "$REVIEW_WF" -f pr_number="$PR_NUMBER" \
|| echo "::warning::Could not dispatch $REVIEW_WF for the late review request."
# --ref: see the comment on the earlier dispatch step above (#285).
# Skip rather than dispatch with an empty --ref if checkout failed.
if [ -z "$PR_BRANCH" ]; then
echo "::warning::PR_BRANCH is empty (checkout may have failed); skipping $REVIEW_WF dispatch."
else
gh workflow run "$REVIEW_WF" --ref "$PR_BRANCH" -f pr_number="$PR_NUMBER" \
|| echo "::warning::Could not dispatch $REVIEW_WF for the late review request."
fi
else
echo "No late @claude review requests."
fi
Expand All @@ -936,6 +956,7 @@ jobs:
MARK_READY: ${{ inputs.mark-ready-for-review }}
CLAUDE_OUTCOME: ${{ steps.claude.outcome }}
COST_USD: ${{ steps.cost.outputs.cost }}
PR_BRANCH: ${{ steps.pr_checkout.outputs.branch }}
run: |
PR_NUMBER="${{ github.event.pull_request.number || github.event.issue.number }}"
echo "before=$SHA_BEFORE after=$SHA_AFTER"
Expand All @@ -945,8 +966,14 @@ jobs:
gh api -X POST "repos/${{ github.repository }}/pulls/$PR_NUMBER/requested_reviewers" -f "reviewers[]=$REVIEWER" \
|| echo "::warning::Could not re-request $REVIEWER as reviewer."
fi
gh workflow run "$REVIEW_WF" -f pr_number="$PR_NUMBER" \
|| echo "::warning::Could not dispatch $REVIEW_WF."
# --ref: see the comment on the earlier dispatch step above (#285).
# Skip rather than dispatch with an empty --ref if checkout failed.
if [ -z "$PR_BRANCH" ]; then
echo "::warning::PR_BRANCH is empty (checkout may have failed); skipping $REVIEW_WF dispatch."
else
gh workflow run "$REVIEW_WF" --ref "$PR_BRANCH" -f pr_number="$PR_NUMBER" \
|| echo "::warning::Could not dispatch $REVIEW_WF."
fi
# Claude finished successfully with new commits: take the PR out of
# draft so a human knows it's ready to review. `gh pr ready` is a
# no-op on an already-ready PR.
Expand Down Expand Up @@ -1055,8 +1082,9 @@ jobs:
PR_VERB="pushed new commits to draft PR"
fi
# Dispatch a review on the new commits (the review's own concurrency
# group dedupes a redundant dispatch).
gh workflow run "$REVIEW_WF" -f pr_number="${PR_URL##*/}" \
# group dedupes a redundant dispatch). --ref: see the comment on the
# earlier dispatch steps above (#285).
gh workflow run "$REVIEW_WF" --ref "$BRANCH" -f pr_number="${PR_URL##*/}" \
|| echo "::warning::Could not dispatch $REVIEW_WF."
# Claude finished successfully with committed code: take the draft PR
# out of draft so a human knows it's ready to review. Gated on Claude's
Expand Down
10 changes: 10 additions & 0 deletions changelog.d/fix-review-dispatch-wrong-sha.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
- **`claude.yml`'s and `claude-review.yml`'s `gh workflow run` dispatches of the
review workflow now pass an explicit `--ref`** pointing at the PR's own head
branch (#285). Without it, `workflow_dispatch` silently defaults the
dispatched run's associated commit to the repository's default branch, so
the resulting `require-review` check-run lands on the wrong SHA and never
supersedes a stale, cancelled run tied to the PR's real head commit -- a PR
could show a fully clean, current review comment while its actual head
commit's required-status-check view stayed red. The consumer-facing
`examples/claude-code-review.yml` `/review`-comment dispatcher gets the same
fix for consistency.
10 changes: 8 additions & 2 deletions examples/claude-code-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,16 @@ jobs:
# This workflow's filename, so the dispatch resolves whatever you
# name the file — WF_PATH is the .github/workflows/<file> portion.
WF_FILE=$(basename "$WF_PATH")
echo "Dispatching $WF_FILE to review PR #$PR_NUMBER (/review comment)."
# This job never checks out the repo, so the PR's head branch has to
# be looked up explicitly. --ref pins the dispatched run's check-runs
# to that branch instead of the default branch workflow_dispatch
# falls back to when no ref is given --- without it, a required
# review check-run can land on the wrong commit.
PR_BRANCH=$(gh api "repos/$REPO/pulls/$PR_NUMBER" --jq '.head.ref')
echo "Dispatching $WF_FILE to review PR #$PR_NUMBER ($PR_BRANCH) (/review comment)."
# --repo is required: this job doesn't check out the repo, so gh has no
# git remote to infer it from (and gh doesn't read GITHUB_REPOSITORY).
gh workflow run "$WF_FILE" --repo "$REPO" -f pr_number="$PR_NUMBER"
gh workflow run "$WF_FILE" --repo "$REPO" --ref "$PR_BRANCH" -f pr_number="$PR_NUMBER"
gh issue comment "$PR_NUMBER" --repo "$REPO" \
--body ":mag: \`/review\` received — dispatched a Claude review of this PR (see the [dispatch run]($RUN_URL)). The review posts as its own comment when it finishes." \
|| echo "::warning::Could not acknowledge the /review comment."
Expand Down
Loading