Files
PSProxmoxVE/.github/workflows/claude-code-review.yml
T
Clint Branham ae3b14fe47 ci: fail the review job when no review actually ran
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 13:33:06 -05:00

107 lines
5.5 KiB
YAML

name: Claude Code Review
on:
pull_request:
types: [opened, synchronize, ready_for_review, reopened]
jobs:
claude-review:
if: ${{ !github.event.pull_request.draft }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
allowed_bots: 'dependabot[bot],goodolclint-claude[bot],goodolclint-codex[bot]'
track_progress: true
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
Review this pull request for the PSProxmoxVE PowerShell module.
Focus areas:
1. **DECISIONS.md compliance** — Check against the architectural
decisions (D001-D016). Any violation is a regression.
2. **Code quality** — Cmdlet conventions (sealed, OutputType,
ConfirmImpact.High for destructive, VmId ValidateRange),
SecureString for passwords, Uri.EscapeDataString on path params,
no bare catch blocks, Newtonsoft-only JSON.
3. **API correctness** — Parameter names and enum values must match
the PVE OpenAPI spec (see tests/PSProxmoxVE.Core.Tests/Fixtures/
pve-api-enums.pve*.json for valid values per PVE version).
4. **Tests** — New cmdlets should have xUnit service tests and
Pester parameter-validation tests.
5. **Security** — No hardcoded credentials, no secrets in logs,
TLS verification on by default.
Use inline comments for issues tied to specific lines. Skip
nitpicks unless they indicate a real problem.
You MUST end the review by submitting a formal review verdict with
`gh pr review`, because branch protection only recognises a review
state — plain PR comments and inline-only comments do not count:
- Nothing blocks merge:
`gh pr review ${{ github.event.pull_request.number }} --approve --body "<summary>"`
- Something must change before merge:
`gh pr review ${{ github.event.pull_request.number }} --request-changes --body "<summary>"`
Always pass a non-empty `--body`. If you cannot complete the
review for any reason, still submit
`gh pr review ${{ github.event.pull_request.number }} --comment --body "<why you could not review>"`
rather than staying silent.
claude_args: |
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr review:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh api:*)"
# claude-code-action self-skips (exit 0, step outcome "success") when the
# PR's copy of THIS workflow file differs from the default branch — its
# anti-tamper gate, keyed on this one file, so PRs changing ci.yml or
# publish.yml are reviewed normally. No review runs, so the verify step
# below is skipped and the job would otherwise go green unreviewed.
# `execution_file` is only set once Claude actually ran, so an empty
# value is the reliable "did not run" signal; `outcome` is not. It is
# cause-agnostic: it also stays empty when the action dies before Claude
# starts (token exchange, write permission, install failure), which is
# why the message points at the step log rather than asserting one cause.
- name: Fail closed — review did not run
if: always() && steps.claude-review.outputs.execution_file == ''
run: |
echo "::error title=Claude review did NOT run::No automated review was performed, so this check cannot pass. Most likely the anti-tamper gate - this PR's copy of .github/workflows/claude-code-review.yml differs from the default branch. Only THIS file trips it; PRs changing other workflows are reviewed normally. This step also fires on any failure before Claude starts (expired token, missing write permission, install failure), so read the 'Run Claude Code Review' step log to tell them apart. Either way this PR requires operator review before merge."
exit 1
- name: Verify formal review was submitted
if: always() && steps.claude-review.outputs.execution_file != ''
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: |
# Branch protection requires a formal review state. Plain PR comments
# don't count, and inline-only comments create empty-body COMMENTED
# reviews that don't count either.
formal_count=$(gh api "repos/$REPO/pulls/$PR_NUMBER/reviews" \
--jq '[.[] | select(.user.login == "claude[bot]") |
select(.state == "APPROVED" or
.state == "CHANGES_REQUESTED" or
((.body // "") | length > 0))] | length')
echo "Formal claude[bot] reviews on PR #$PR_NUMBER: $formal_count"
if [ "$formal_count" -eq 0 ]; then
echo "::error title=No formal review submitted::Claude reviewed the PR but did not call 'gh pr review'. Re-run the workflow or invoke '@claude re-review' on the PR."
exit 1
fi