Repository navigation
ci(claude-review): stop silent no-comment review runs #344
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" | |
| jobs: | |
| claude-review: | |
| # Skip PRs we shouldn't (or can't) review: | |
| # - Dependabot / forks: no CLAUDE_CODE_OAUTH_TOKEN, so the action would fail. | |
| # - release-please release PRs: just version bumps + changelog — nothing to | |
| # review, and it must never block a release. | |
| # - Back-merge PRs (production -> dev, opened by release-please.yml): only | |
| # carry code already reviewed on its way through dev, and the action | |
| # rejects their bot actor ("Workflow initiated by non-human actor"), | |
| # which blocks the merge since claude-review is a required check. | |
| if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' && !startsWith(github.head_ref, 'release-please--') && !startsWith(github.head_ref, 'chore/back-merge-') }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| # write so the review agent can post its inline comments — with read it | |
| # reviews successfully but every posting attempt is denied and the PR | |
| # gets nothing (the action still exits 0). | |
| pull-requests: write | |
| issues: read | |
| id-token: write | |
| steps: | |
| - name: Record start time | |
| run: echo "REVIEW_STARTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV" | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 1 | |
| - 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' | |
| # --comment is required for the review to be posted to the PR: the | |
| # code-review plugin's spec says "If --comment was NOT provided, | |
| # stop here. Do not post any GitHub comments." Without it the review | |
| # runs and is discarded (the log doesn't even show it unless | |
| # show_full_output is enabled). | |
| prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }} --comment' | |
| # Explicitly allow the posting tools (mirrors the plugin command's | |
| # allowed-tools frontmatter). In headless mode the frontmatter grant | |
| # doesn't reach the inline-comment MCP tool: PR #9's review hit 46 | |
| # permission denials and posted nothing despite finding issues. | |
| claude_args: | | |
| --model claude-opus-5-5 --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)" --append-system-prompt "You are running non-interactively. Never run subagents in the background and never schedule wakeups: ending your turn ends the session. Wait for every reviewer to finish, then post the review comment before you stop." | |
| # 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 | |
| # The action exits green even when Claude ends its turn before posting | |
| # anything (e.g. it backgrounded its reviewer subagents and stopped to | |
| # "wait" for them). Fail loudly instead of leaving a silent green check. | |
| - name: Check a review comment was posted | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| REPO: ${{ github.repository }} | |
| PR: ${{ github.event.pull_request.number }} | |
| run: | | |
| count=$( | |
| { | |
| gh api "repos/$REPO/issues/$PR/comments" --paginate \ | |
| --jq ".[] | select(.user.login == \"claude[bot]\" and .created_at >= \"$REVIEW_STARTED_AT\") | .id" | |
| gh api "repos/$REPO/pulls/$PR/comments" --paginate \ | |
| --jq ".[] | select(.user.login == \"claude[bot]\" and .created_at >= \"$REVIEW_STARTED_AT\") | .id" | |
| } | wc -l | |
| ) | |
| if [ "$count" -eq 0 ]; then | |
| echo "::error::Claude finished without posting a review comment on this PR." | |
| exit 1 | |
| fi | |
| echo "Claude posted $count comment(s)." |