ci: Make claude action review PRs only and fix the instructions

Turns out the claude code action has issues reviewing PRs from forks
(https://github.com/anthropics/claude-code-action/issues/939). Let's
reuse the approach from https://github.com/pzmarzly/demo--claude-bot-reviews
instead (which I've explicitly asked permission for to reuse).

Unlike the linked demo, we still insist on a comment by a maintainer
before claude reviews the PR.
This commit is contained in:
Daan De Meyer
2026-03-06 15:11:54 +01:00
parent 83e872b4c2
commit 5d223ff468
2 changed files with 151 additions and 62 deletions
+151
View File
@@ -0,0 +1,151 @@
# Integrates Claude Code as an AI assistant for reviewing pull requests.
# Mention @claude in any PR review to request a review. Claude authenticates
# via AWS Bedrock using OIDC — no long-lived API keys required.
name: Claude Review
on:
pull_request_review_comment:
types: [created]
pull_request_review:
types: [submitted]
concurrency:
group: claude-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
claude-review:
runs-on: ubuntu-latest
if: |
github.repository_owner == 'systemd' &&
(github.event_name == 'pull_request_review_comment' &&
contains(github.event.comment.body, '@claude') &&
contains(fromJSON('["MEMBER","OWNER","COLLABORATOR"]'), github.event.comment.author_association)) ||
(github.event_name == 'pull_request_review' &&
contains(github.event.review.body, '@claude') &&
contains(fromJSON('["MEMBER","OWNER","COLLABORATOR"]'), github.event.review.author_association))
permissions:
contents: read # Read repository contents
pull-requests: write # Post comments and reviews on PRs
id-token: write # Authenticate with AWS via OIDC
actions: read # Access workflow run metadata
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }}
role-session-name: GitHubActions-Claude-${{ github.run_id }}
aws-region: us-east-1
- name: Run Claude Code
uses: anthropics/claude-code-action@1fc90f3ed982521116d8ff6d85b948c9b12cae3e
with:
use_bedrock: "true"
github_token: ${{ secrets.GITHUB_TOKEN }}
claude_args: |
--model us.anthropic.claude-opus-4-6-v1
--max-turns 100
--allowedTools "
Read,Write,Edit,MultiEdit,LS,Grep,Glob,Task,
Bash(cat:*),Bash(test:*),Bash(printf:*),Bash(jq:*),Bash(head:*),Bash(git:*),Bash(gh:*),
mcp__github_inline_comment__create_inline_comment,
"
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
HEAD SHA: ${{ github.event.pull_request.head.sha }}
Review this pull request.
You are in the upstream repo without the patch applied. Do not apply it.
## Phase 1: Gather context
Fetch the patch, PR title/body, and list of existing comments (top-level, inline, and reviews):
- `gh pr diff ${{ github.event.pull_request.number }} --patch`
- `gh pr view ${{ github.event.pull_request.number }} --json title,body`
- `gh api --paginate repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments`
- `gh api --paginate repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/comments`
- `gh api --paginate repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/reviews`
## Phase 2: Parallel review subagents
Review:
- Code quality, style, and best practices
- Potential bugs, issues, incorrect logic
- Security implications
- CLAUDE.md - compliance
For every category, launch subagents to review them in parallel. Group related sections
as needed — use 2-4 subagents based on PR size and scope.
Give each subagent the PR title, description, full patch, and the list of changed files.
Each subagent must return a JSON array of issues:
`[{"file": "path", "line": <number or null>, "severity": "must-fix|suggestion|nit", "title": "...", "body": "..."}]`
Subagents must ONLY return the JSON array — they must NOT post comments,
call `gh`, or use `mcp__github_inline_comment__create_inline_comment`.
All posting happens in Phase 3.
Each subagent MUST verify its findings before returning them:
- For style/convention claims, check at least 3 existing examples in the codebase to confirm
the pattern actually exists before flagging a violation.
- For "use X instead of Y" suggestions, confirm X actually exists and works for this case.
- If unsure, don't include the issue.
## Phase 3: Collect and post
After ALL subagents complete:
1. Collect all issues. Merge duplicates (same file, lines within 3 of each other, same problem).
2. Drop low-confidence findings.
3. For CLAUDE.md violations that appear in 3+ existing places in the codebase, do NOT post inline comments.
Instead, add them to the 'CLAUDE.md improvements' section of the tracking comment
4. Check existing inline review comments (fetched in Phase 1). Do NOT post an inline comment if
one already exists on the same file+line about the same problem.
5. Check for author replies that dismiss or reject a previous comment. Do NOT re-raise an issue
the PR author has already responded to disagreeing with.
6. Post new inline comments with `mcp__github_inline_comment__create_inline_comment`.
Prefix ALL comments with "Claude: ".
Link format: https://github.com/${{ github.repository }}/blob/${{ github.event.pull_request.head.sha }}/README.md#L10-L15
Then maintain a single top-level "tracking comment" listing ALL issues as checkboxes.
Use a hidden HTML marker to find it: `<!-- claude-pr-review -->`.
Look through the top-level comments fetched in Phase 1 for one containing that marker.
**If no tracking comment exists (first run):**
Create one with `gh pr comment ${{ github.event.pull_request.number }} --body "..."` using this format:
```
Claude: review of <REPO> #<PR NUMBER> (<HEAD SHA>)
<!-- claude-pr-review -->
### Must fix
- [ ] **title** — `file:line` — short explanation
### Suggestions
- [ ] **title** — `file:line` — short explanation
### Nits
- [ ] **title** — `file:line` — short explanation
### CLAUDE.md improvements
- improvement suggestion
```
Omit empty sections.
**If a tracking comment already exists (subsequent run):**
1. Parse the existing checkboxes. For each old issue, check if the current patch still has
that problem (re-check the relevant lines in the new diff). If fixed, mark it `- [x]`.
If the author dismissed it, mark it `- [x] ~~title~~ (dismissed)`.
2. Append any NEW issues found in this run that aren't already listed.
3. Update the HEAD SHA in the header line.
4. Edit the comment in-place.
```
printf '%s' "$BODY" > pr-review-body.txt
gh api --method PATCH repos/${{ github.repository }}/issues/comments/<comment-id> -F body=@pr-review-body.txt
```
-62
View File
@@ -1,62 +0,0 @@
# Integrates Claude Code as an AI assistant for issues and pull requests.
# Mention @claude in any issue comment, PR review comment, or PR review to
# interact with it, or assign the "claude" user to an issue. Claude
# authenticates via AWS Bedrock using OIDC — no long-lived API keys required.
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
claude:
runs-on: ubuntu-latest
if: |
github.repository_owner == 'systemd' &&
((github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@claude') &&
contains(fromJSON('["MEMBER","OWNER","COLLABORATOR"]'), github.event.comment.author_association)) ||
(github.event_name == 'pull_request_review_comment' &&
contains(github.event.comment.body, '@claude') &&
contains(fromJSON('["MEMBER","OWNER","COLLABORATOR"]'), github.event.comment.author_association)) ||
(github.event_name == 'pull_request_review' &&
contains(github.event.review.body, '@claude') &&
contains(fromJSON('["MEMBER","OWNER","COLLABORATOR"]'), github.event.review.author_association)) ||
(github.event_name == 'issues' &&
github.event.action == 'assigned' &&
github.event.assignee.login == 'claude'))
permissions:
contents: read # Read repository contents
issues: write # Post comments on issues
pull-requests: write # Post comments and reviews on PRs
id-token: write # Authenticate with AWS via OIDC
actions: read # Access workflow run metadata
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
fetch-depth: 1
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_NAME }}
role-session-name: GitHubActions-Claude-${{ github.run_id }}
aws-region: us-east-1
- name: Run Claude Code
uses: anthropics/claude-code-action@1fc90f3ed982521116d8ff6d85b948c9b12cae3e
with:
use_bedrock: "true"
github_token: ${{ secrets.GITHUB_TOKEN }}
claude_args: |
--model us.anthropic.claude-opus-4-6-v1