Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,23 @@ jobs:
outputs:
run_review: ${{ steps.check.outputs.run_review }}
steps:
- name: Check for exact @claude review command
- name: Check for @claude review on its own line
id: check
env:
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
body="$(python - <<'PY'
has_review_command="$(python - <<'PY'
import os

body = os.environ.get("COMMENT_BODY", "")
print(" ".join(body.split()))
print(
"true"
if any(line.strip() == "@claude review" for line in body.splitlines())
else "false"
)
PY
)"
if [ "$body" = "@claude review" ]; then
if [ "$has_review_command" = "true" ]; then
echo "run_review=true" >> "$GITHUB_OUTPUT"
else
echo "run_review=false" >> "$GITHUB_OUTPUT"
Expand All @@ -44,7 +49,15 @@ jobs:
if: |
always() &&
(
(github.event_name == 'pull_request' && github.event.pull_request.user.type != 'Bot') ||
(
github.event_name == 'pull_request' &&
github.event.pull_request.user.type != 'Bot' &&
github.event.pull_request.draft == false &&
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association) &&
!contains(github.event.pull_request.labels.*.name, 'skip-ai-review') &&
!contains(github.event.pull_request.labels.*.name, 'dependencies') &&
!contains(github.event.pull_request.labels.*.name, 'chore')
) ||
needs.detect-claude-command.outputs.run_review == 'true'
)
runs-on:
Expand All @@ -53,9 +66,10 @@ jobs:
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
permissions:
contents: read
pull-requests: read
pull-requests: write
issues: read
id-token: write
actions: read

steps:
- name: Checkout repository
Expand All @@ -65,13 +79,24 @@ jobs:

- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@v1
uses: anthropics/claude-code-action@88c168b39e7e64da0286d812b6e9fbebb6708185
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
track_progress: >-
${{
(
github.event_name == 'pull_request' &&
contains(fromJson('["opened","synchronize","ready_for_review","reopened"]'), github.event.action)
) ||
(
github.event_name == 'issues' &&
contains(fromJson('["opened","edited","labeled","assigned"]'), github.event.action)
)
}}
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
plugins: 'code-review@claude-code-plugins'
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ env.PR_NUMBER }}'

# Tools based on CLAUDE.md development commands
# Includes: uv (pytest, alembic, python), pnpm (check, lint, test), and gh CLI
claude_args: '--allowed-tools "Bash(uv run pytest:*),Bash(uv run alembic:*),Bash(uv run python:*),Bash(uv sync:*),Bash(pnpm install:*),Bash(pnpm check:*),Bash(pnpm lint:*),Bash(pnpm format:*),Bash(pnpm test:*),Bash(pnpm build:*),Bash(gh issue:*),Bash(gh pr:*),Bash(gh search:*)"'
claude_args: '--allowed-tools "mcp__github_inline_comment__create_inline_comment,Bash(uv run pytest:*),Bash(uv run alembic:*),Bash(uv run python:*),Bash(uv sync:*),Bash(pnpm install:*),Bash(pnpm check:*),Bash(pnpm lint:*),Bash(pnpm format:*),Bash(pnpm test:*),Bash(pnpm build:*),Bash(gh issue:*),Bash(gh pr:*),Bash(gh search:*)" --model claude-opus-4-6'
21 changes: 13 additions & 8 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ on:
jobs:
detect-non-claude-review:
name: Skip Exact @claude Review Command
runs-on: ubuntu-latest
permissions: {}
runs-on: ubuntu-latest
outputs:
run_claude: ${{ steps.check.outputs.run_claude }}
steps:
- name: Skip exact @claude review command
- name: Skip comments with @claude review on its own line
id: check
env:
EVENT_NAME: ${{ github.event_name }}
Expand All @@ -28,13 +28,18 @@ jobs:
echo "run_claude=true" >> "$GITHUB_OUTPUT"
exit 0
fi
body="$(python - <<'PY'
has_review_command="$(python - <<'PY'
import os

body = os.environ.get("COMMENT_BODY", "")
print(" ".join(body.split()))
print(
"true"
if any(line.strip() == "@claude review" for line in body.splitlines())
else "false"
)
PY
)"
if [ "$body" = "@claude review" ]; then
if [ "$has_review_command" = "true" ]; then
echo "run_claude=false" >> "$GITHUB_OUTPUT"
else
echo "run_claude=true" >> "$GITHUB_OUTPUT"
Expand Down Expand Up @@ -75,8 +80,8 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
pull-requests: write
issues: write
id-token: write
actions: read # Required for Claude to read CI results on PRs
steps:
Expand All @@ -87,7 +92,7 @@ jobs:

- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1
uses: anthropics/claude-code-action@88c168b39e7e64da0286d812b6e9fbebb6708185
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

Expand Down
Loading