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
50 changes: 44 additions & 6 deletions .github/workflows/claude-pr-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,60 @@ jobs:
github.event.pull_request != null ||
github.event.issue.pull_request != null
) &&
contains(github.event.comment.body, '@claude')
contains(github.event.comment.body, '@claude') &&
(
github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR'
)

runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
id-token: write

id-token: write # Required by claude-code-action for GitHub App token exchange.
steps:
# issue_comment payloads identify PR comments, but do not include the PR
# head repo. Query the PR before allowing Claude to run on fork PRs.
- name: Check PR origin
id: pr-origin
env:
GH_TOKEN: ${{ github.token }}
EVENT_NAME: ${{ github.event_name }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_PULL_REQUEST_URL: ${{ github.event.issue.pull_request.url }}
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail
if [ "$EVENT_NAME" = "issue_comment" ] && [ -z "$ISSUE_PULL_REQUEST_URL" ]; then
echo "is_internal=true" >> "$GITHUB_OUTPUT"
exit 0
fi

pr_number="${PULL_REQUEST_NUMBER:-$ISSUE_NUMBER}"
if ! head_repo="$(gh api "repos/${REPOSITORY}/pulls/${pr_number}" --jq '.head.repo.full_name')"; then
echo "Unable to determine PR head repository for #${pr_number}; skipping Claude."
echo "is_internal=false" >> "$GITHUB_OUTPUT"
exit 0
fi

if [ "$head_repo" = "$REPOSITORY" ]; then
echo "is_internal=true" >> "$GITHUB_OUTPUT"
else
echo "is_internal=false" >> "$GITHUB_OUTPUT"
echo "Skipping Claude for external PR from ${head_repo:-unknown}."
fi

- name: Checkout repository
uses: actions/checkout@v7
if: steps.pr-origin.outputs.is_internal == 'true'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 1
persist-credentials: false

- name: Comprehensive PR Review
if: steps.pr-origin.outputs.is_internal == 'true'
uses: anthropics/claude-code-action@769e3bdff9bb7ecfb51bad4c9cba23d6f5fc5ea5 # v1.0.163
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
Expand Down Expand Up @@ -131,8 +170,7 @@ jobs:

Only provide noteworthy feedback. Keep feedback concise.
Provide feedback using inline comments for specific issues.
Use top-level comments for general observations.
Do not add positive reinforcement comments.

claude_args: |
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)"
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr diff:*),Bash(gh pr view:*)"
39 changes: 36 additions & 3 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ permissions:
contents: write
pull-requests: write
issues: write
id-token: write

id-token: write # Required by claude-code-action for GitHub App token exchange.
jobs:
claude:
runs-on: ubuntu-latest
Expand All @@ -20,12 +19,46 @@ jobs:
contains(github.event.comment.body, '@claude') &&
github.event.comment.user.login == 'matticbot'
steps:
# issue_comment payloads identify PR comments, but do not include the PR
# head repo. Query the PR before allowing Claude to run on fork PRs.
- name: Check PR origin
id: pr-origin
env:
GH_TOKEN: ${{ github.token }}
EVENT_NAME: ${{ github.event_name }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_PULL_REQUEST_URL: ${{ github.event.issue.pull_request.url }}
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail
if [ "$EVENT_NAME" = "issue_comment" ] && [ -z "$ISSUE_PULL_REQUEST_URL" ]; then
echo "is_internal=true" >> "$GITHUB_OUTPUT"
exit 0
fi

pr_number="${PULL_REQUEST_NUMBER:-$ISSUE_NUMBER}"
if ! head_repo="$(gh api "repos/${REPOSITORY}/pulls/${pr_number}" --jq '.head.repo.full_name')"; then
echo "Unable to determine PR head repository for #${pr_number}; skipping Claude."
echo "is_internal=false" >> "$GITHUB_OUTPUT"
exit 0
fi

if [ "$head_repo" = "$REPOSITORY" ]; then
echo "is_internal=true" >> "$GITHUB_OUTPUT"
else
echo "is_internal=false" >> "$GITHUB_OUTPUT"
echo "Skipping Claude for external PR from ${head_repo:-unknown}."
fi

- name: Checkout repository
uses: actions/checkout@v7
if: steps.pr-origin.outputs.is_internal == 'true'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0

- name: Run Claude
if: steps.pr-origin.outputs.is_internal == 'true'
uses: anthropics/claude-code-action@769e3bdff9bb7ecfb51bad4c9cba23d6f5fc5ea5 # v1.0.163
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
Loading