Function name changes #133
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 | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, ready_for_review, reopened] | |
| # Optional: Only run on specific file changes | |
| # paths: | |
| # - "src/**/*.ts" | |
| # - "src/**/*.tsx" | |
| # - "src/**/*.js" | |
| # - "src/**/*.jsx" | |
| # Serialize runs per PR. The stash/restore reviewer dance below assumes | |
| # only one run is mutating the PR's reviewer list at a time; without | |
| # this, an overlapping second run reads an already-cleared list, stashes | |
| # [], and on restore wipes the original reviewers permanently. Cancel | |
| # the in-flight run on a new push so the freshest diff wins. | |
| concurrency: | |
| group: claude-review-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| claude-review: | |
| # Optional: Filter by PR author | |
| # if: | | |
| # github.event.pull_request.user.login == 'external-contributor' || | |
| # github.event.pull_request.user.login == 'new-developer' || | |
| # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| id-token: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| # The reviewer stash/restore is a serialization signal: we clear the | |
| # human reviewers before Claude runs so they aren't notified mid-run, | |
| # then re-add them when Claude finishes so the re-add fires a fresh | |
| # GitHub notification — letting the human see Claude's review before | |
| # they start their own. We also snapshot the PR head SHA so the | |
| # post-Claude step can detect whether Claude pushed any commits and | |
| # route the re-request accordingly (human assignees vs. original | |
| # reviewer set). The restore is load-bearing for the notification | |
| # signal, so it must NOT silently swallow errors (see restore step | |
| # below). | |
| - name: Stash and clear reviewers; record starting head SHA | |
| id: stash | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| run: | | |
| HEAD_SHA=$(gh api "repos/$REPO/pulls/$PR_NUMBER" --jq '.head.sha') | |
| echo "head_before=$HEAD_SHA" >> "$GITHUB_OUTPUT" | |
| echo "Starting PR head: $HEAD_SHA" | |
| REVIEWERS_JSON=$(gh api "repos/$REPO/pulls/$PR_NUMBER/requested_reviewers") | |
| USERS=$(echo "$REVIEWERS_JSON" | jq -c '[.users[].login]') | |
| TEAMS=$(echo "$REVIEWERS_JSON" | jq -c '[.teams[].slug]') | |
| echo "users=$USERS" >> "$GITHUB_OUTPUT" | |
| echo "teams=$TEAMS" >> "$GITHUB_OUTPUT" | |
| echo "Stashed users: $USERS" | |
| echo "Stashed teams: $TEAMS" | |
| if [ "$USERS" != "[]" ] || [ "$TEAMS" != "[]" ]; then | |
| # `|| true` is intentional and asymmetric with the restore step: | |
| # a failed stash leaves reviewers in place, which only causes a | |
| # mid-run notification (recoverable). A failed restore would | |
| # silently drop them entirely (not recoverable) — see that step. | |
| jq -n --argjson users "$USERS" --argjson teams "$TEAMS" \ | |
| '{reviewers: $users, team_reviewers: $teams}' \ | |
| | gh api -X DELETE \ | |
| "repos/$REPO/pulls/$PR_NUMBER/requested_reviewers" \ | |
| --input - || true | |
| fi | |
| - name: Run Claude Code Review | |
| id: claude-review | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' | |
| plugins: 'code-review@claude-code-plugins' | |
| prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}' | |
| # Force tag mode (anthropics/claude-code-action src/modes/detector.ts). | |
| # In the default agent mode for pull_request events, the action never | |
| # posts any non-inline PR comment by itself (src/modes/agent/index.ts: | |
| # "No tracking comment in agent mode", commentId: undefined). The | |
| # code-review plugin will only post a top-level comment if it finds | |
| # issues scoring >= 80, so silent runs are common on small/mechanical | |
| # PRs. track_progress forces tag mode, which creates a tracking | |
| # comment up front via createInitialComment() and updates it at the | |
| # end — guaranteeing a PR comment regardless of plugin output. | |
| track_progress: 'true' | |
| # Bundle the tracking comment into a single sticky per PR rather than | |
| # a new comment each run. (Only consulted in tag mode.) Each new run | |
| # updates the same comment in place — the latest review is always | |
| # visible, and prior reviews from `@claude review` invocations (which | |
| # post as separate non-sticky comments) are left untouched. | |
| use_sticky_comment: 'true' | |
| # Also archive the formatted report to the Actions step summary page | |
| # (does not affect PR comments). | |
| display_report: 'true' | |
| # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md | |
| # or https://code.claude.com/docs/en/cli-reference for available options | |
| - name: Re-assign reviewers after Claude finishes | |
| if: always() && steps.stash.outcome == 'success' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| HEAD_BEFORE: ${{ steps.stash.outputs.head_before }} | |
| USERS_BEFORE: ${{ steps.stash.outputs.users }} | |
| TEAMS_BEFORE: ${{ steps.stash.outputs.teams }} | |
| run: | | |
| PR_JSON=$(gh api "repos/$REPO/pulls/$PR_NUMBER") | |
| HEAD_AFTER=$(echo "$PR_JSON" | jq -r '.head.sha') | |
| echo "Head before Claude: $HEAD_BEFORE" | |
| echo "Head after Claude: $HEAD_AFTER" | |
| if [ "$HEAD_AFTER" = "$HEAD_BEFORE" ]; then | |
| # No new commits — restore the original reviewer set. | |
| USERS=${USERS_BEFORE:-[]} | |
| TEAMS=${TEAMS_BEFORE:-[]} | |
| if [ "$USERS" = "[]" ] && [ "$TEAMS" = "[]" ]; then | |
| echo "Claude made no commits and no reviewers were originally requested." | |
| exit 0 | |
| fi | |
| echo "Claude made no commits; restoring original reviewers." | |
| # Do NOT add `|| true` here. A failed restore means the human | |
| # reviewer was silently dropped from the PR and never gets the | |
| # post-Claude notification — fail loudly so it can be re-added | |
| # manually instead of vanishing. | |
| jq -n --argjson users "$USERS" --argjson teams "$TEAMS" \ | |
| '{reviewers: $users, team_reviewers: $teams}' \ | |
| | gh api -X POST \ | |
| "repos/$REPO/pulls/$PR_NUMBER/requested_reviewers" \ | |
| --input - | |
| exit 0 | |
| fi | |
| # Claude pushed commits: route the re-request to the PR's human | |
| # assignees so they can review Claude's changes and delegate | |
| # further reviews. Bot assignees (e.g. copilot-swe-agent) are | |
| # filtered out. | |
| ASSIGNEES=$(echo "$PR_JSON" | jq -c '[.assignees[] | select(.type == "User") | .login]') | |
| echo "Human assignees: $ASSIGNEES" | |
| if [ "$ASSIGNEES" = "[]" ]; then | |
| echo "Claude added commits but PR has no human assignees; leaving reviewers cleared." | |
| exit 0 | |
| fi | |
| # Same no-`|| true` rule as above — failure here drops the human | |
| # assignee silently, so let it surface. | |
| jq -n --argjson users "$ASSIGNEES" '{reviewers: $users}' \ | |
| | gh api -X POST \ | |
| "repos/$REPO/pulls/$PR_NUMBER/requested_reviewers" \ | |
| --input - |