-
Notifications
You must be signed in to change notification settings - Fork 10
151 lines (129 loc) · 7.46 KB
/
claude-code-review.yml
File metadata and controls
151 lines (129 loc) · 7.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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:
# Opt-out: PR authors can apply the `skip-claude-review` label to suppress
# the bot on subsequent commits. Removing the label re-enables review on
# the next push.
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-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@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 1
- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@26ddc358fe3befff50c5ec2f80304c90c763f6f8 # 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: |
You are reviewing PR #${{ github.event.pull_request.number }} in ${{ github.repository }}.
STEP 1 — Fetch existing review threads and issue comments BEFORE reviewing.
Run this GraphQL query and read the results carefully:
gh api graphql -f query='
query($owner:String!,$repo:String!,$num:Int!){
repository(owner:$owner,name:$repo){
pullRequest(number:$num){
reviewThreads(first:100){
nodes{
id
isResolved
path
line
comments(first:20){ nodes{ author{login} body }}
}
}
comments(first:100){
nodes{ author{login} body }
}
}
}
}' \
-f owner=${{ github.repository_owner }} \
-f repo=${{ github.event.repository.name }} \
-F num=${{ github.event.pull_request.number }}
STEP 2 — Build a set of issues already covered by prior bot comments
(threads whose first comment is authored by a bot or this workflow's
identity). Treat each prior comment as "(path, line, topic)".
STEP 3 — Dedupe policy. For each issue you are about to raise, look for a
prior thread covering the same (path, line, topic):
• If an UNRESOLVED thread exists for this (path, line, topic) → SKIP.
Don't duplicate an open thread; the user will get to it.
• If a RESOLVED thread exists for this (path, line, topic), classify the
ORIGINAL comment:
(a) Actionable ask (it requested the author to change something —
e.g. "rename X", "use Y instead", "extract this", "add null check"):
→ Read the CURRENT code at that location.
- If the requested change WAS made → SKIP (user fixed it).
- If the requested change was NOT made → UNRESOLVE the
original thread (do NOT post a new comment). Use:
gh api graphql -f query='
mutation($id:ID!){
unresolveReviewThread(input:{threadId:$id}){
thread{ id isResolved }
}
}' -f id=<THREAD_ID>
where <THREAD_ID> is the thread.id from STEP 1.
→ If thread replies show the author/maintainer explicitly
disagreed or declined ("won't fix", "intentional", "ship it
anyway") → SKIP regardless of code state. The decision was made.
(b) Informational / nit / praise / question (not an ask for a change):
→ SKIP. Resolution means acknowledged; don't re-post and don't
unresolve.
• If a prior comment raised a DIFFERENT topic on the same line → OK to post.
• New issues the prior review missed entirely → post normally.
STEP 4 — Read CLAUDE.md at the repo root first — it references Agents.md
and agent_docs/ which contain all project conventions, architecture, and
rules. Follow every convention defined there during your review.
STEP 5 — Run the review. The /code-review plugin below will analyze the PR
and propose inline comments. You MUST apply STEP 3 as a POSTING GATE on
every single comment the plugin wants to create — this includes comments
the plugin would post via mcp__github_inline_comment__create_inline_comment
or via `gh pr comment`. Concretely:
BEFORE every call to mcp__github_inline_comment__create_inline_comment:
1. Compute (path, line, topic) of the comment you are about to post.
2. Look it up in the dedupe set from STEP 1.
3. Apply STEP 3. If STEP 3 says SKIP → do NOT call the tool at all.
If STEP 3 says UNRESOLVE → call the unresolveReviewThread mutation
INSTEAD of posting a new comment.
4. Only post if STEP 3 says OK to post.
Top-level summary comment — POST ONLY IF the run produced an action.
An action means: (a) you posted at least one new inline comment, OR
(b) you unresolved at least one previously-resolved thread. If neither
happened, post NO summary comment at all — stay completely silent.
Do NOT post filler summaries like "No new issues" or "Nothing to report".
When you DO post a summary, list only: (a) the new findings you posted
this run, and (b) any threads you unresolved this run. Do not list
issues you skipped via the dedupe gate.
STEP 6 — Post approval message or stay silent.
After the review completes:
• If you posted NO new inline comments and unresolved NO threads
(i.e., the PR is clean) → post an approval comment using:
gh pr comment ${{ github.event.pull_request.number }} --body "✅ No issues found. Checked for bugs and CLAUDE.md compliance."
• If you DID post inline comments or unresolve threads → do NOT post an approval comment.
Now run the plugin:
/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }} --comment
use_sticky_comment: true
claude_args: |
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*),Bash(gh api graphql:*),Bash(gh api:*)"