|
1 | 1 | name: Claude Code Review with Progress Tracking |
2 | 2 |
|
| 3 | +# Trigger Claude review on PR lifecycle events and explicit mentions |
| 4 | + |
3 | 5 | on: |
| 6 | + # Trigger when a new issue comment is created (for @claude mentions) |
4 | 7 | issue_comment: |
5 | 8 | types: [created] |
| 9 | + # Trigger when a PR review comment is created/edited/deleted (for @claude mentions) |
6 | 10 | pull_request_review_comment: |
7 | 11 | types: [created, edited, deleted] |
| 12 | + # Trigger on new or assigned issues (for future extension or automation) |
8 | 13 | issues: |
9 | 14 | types: [opened, assigned] |
| 15 | + # Trigger when a PR review is submitted (for @claude in the review body) |
10 | 16 | pull_request_review: |
11 | 17 | types: [submitted] |
| 18 | + # Main trigger for PR events, using pull_request_target for elevated permissions |
12 | 19 | pull_request_target: |
13 | 20 | types: [opened, synchronize, reopened] |
14 | 21 |
|
15 | 22 | permissions: |
| 23 | + # Read repository contents needed for code review |
16 | 24 | contents: read |
| 25 | + # Allow Claude to post review comments on pull requests |
17 | 26 | pull-requests: write |
| 27 | + # Allow Claude to interact with issues if needed |
18 | 28 | issues: write |
| 29 | + # Allow this workflow to manage its own actions if required |
19 | 30 | actions: write |
20 | 31 |
|
21 | 32 | jobs: |
22 | 33 | claude-review-with-tracking: |
23 | 34 | runs-on: ubuntu-latest |
24 | 35 |
|
| 36 | + # Only run for trusted authors or when explicitly mentioned by them |
25 | 37 | if: | |
26 | 38 | ( |
27 | 39 | github.event_name == 'pull_request_target' && |
@@ -51,43 +63,79 @@ jobs: |
51 | 63 | ) |
52 | 64 |
|
53 | 65 | steps: |
| 66 | + # Checkout the repository at the appropriate commit for review |
54 | 67 | - name: Checkout repository |
55 | 68 | uses: actions/checkout@v4 |
56 | 69 | with: |
| 70 | + # Use PR head SHA for pull_request_target, fallback to current SHA otherwise |
57 | 71 | fetch-depth: 0 |
58 | 72 | ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }} |
59 | 73 |
|
| 74 | + # Handle fork branches for pull_request_target events |
| 75 | + - name: Setup Fork Remote (for pull_request_target) |
| 76 | + if: ${{ github.event_name == 'pull_request_target' }} |
| 77 | + env: |
| 78 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 79 | + run: | |
| 80 | + PR_NUMBER=${{ github.event.pull_request.number }} |
| 81 | + HEAD_REF="${{ github.event.pull_request.head.ref }}" |
| 82 | + HEAD_OWNER="${{ github.event.pull_request.head.repo.owner.login }}" |
| 83 | + HEAD_REPO="${{ github.event.pull_request.head.repo.name }}" |
| 84 | + CURRENT_OWNER="${{ github.repository_owner }}" |
| 85 | +
|
| 86 | + # For forked PRs, temporarily change origin URL to fork repository |
| 87 | + # This allows claude-code-action to fetch the PR branch correctly |
| 88 | + if [ "$HEAD_OWNER" != "$CURRENT_OWNER" ]; then |
| 89 | + echo "PR is from fork: $HEAD_OWNER/$HEAD_REPO" |
| 90 | + FORK_URL="https://github.com/$HEAD_OWNER/$HEAD_REPO.git" |
| 91 | + echo "Temporarily changing origin URL to fork: $FORK_URL" |
| 92 | + git remote set-url origin "$FORK_URL" |
| 93 | + git fetch origin "$HEAD_REF" |
| 94 | + git branch "$HEAD_REF" "origin/$HEAD_REF" 2>/dev/null || git branch -f "$HEAD_REF" "origin/$HEAD_REF" |
| 95 | + fi |
| 96 | +
|
| 97 | + # For comment-driven triggers, ensure we have the correct PR branch checked out |
60 | 98 | - name: Checkout PR Branch (for comments) |
61 | 99 | if: ${{ github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' }} |
62 | 100 | env: |
63 | 101 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
64 | 102 | run: | |
65 | | - # Get PR info first |
66 | 103 | PR_NUMBER=${{ github.event.issue.number || github.event.pull_request.number }} |
67 | | - BASE_BRANCH=$(gh pr view $PR_NUMBER --json baseRefName -q '.baseRefName') |
68 | | - |
69 | | - # Fetch the base branch if it exists |
70 | | - if git ls-remote --exit-code origin "refs/heads/$BASE_BRANCH" > /dev/null 2>&1; then |
71 | | - if ! git fetch origin "$BASE_BRANCH"; then |
72 | | - echo "Warning: Failed to fetch base branch '$BASE_BRANCH'" |
73 | | - fi |
74 | | - else |
75 | | - echo "Warning: Base branch '$BASE_BRANCH' not found, PR may need to be retargeted" |
| 104 | +
|
| 105 | + # Fetch PR metadata: head branch name and source repository |
| 106 | + PR_DATA=$(gh pr view $PR_NUMBER --json headRefName,headRepositoryOwner,headRepository,baseRefName) |
| 107 | + HEAD_REF=$(echo "$PR_DATA" | jq -r '.headRefName') |
| 108 | + HEAD_OWNER=$(echo "$PR_DATA" | jq -r '.headRepositoryOwner.login') |
| 109 | + HEAD_REPO=$(echo "$PR_DATA" | jq -r '.headRepository.name') |
| 110 | + BASE_BRANCH=$(echo "$PR_DATA" | jq -r '.baseRefName') |
| 111 | + CURRENT_OWNER="${{ github.repository_owner }}" |
| 112 | +
|
| 113 | + # For forked PRs, temporarily change origin URL to fork repository |
| 114 | + # This allows claude-code-action to fetch the PR branch correctly |
| 115 | + if [ "$HEAD_OWNER" != "$CURRENT_OWNER" ]; then |
| 116 | + echo "PR is from fork: $HEAD_OWNER/$HEAD_REPO" |
| 117 | + FORK_URL="https://github.com/$HEAD_OWNER/$HEAD_REPO.git" |
| 118 | + echo "Temporarily changing origin URL to fork: $FORK_URL" |
| 119 | + git remote set-url origin "$FORK_URL" |
76 | 120 | fi |
77 | | - |
78 | | - gh pr checkout $PR_NUMBER |
79 | 121 |
|
| 122 | + # Fetch and checkout the PR branch |
| 123 | + git fetch origin "$HEAD_REF" |
| 124 | + git branch "$HEAD_REF" "origin/$HEAD_REF" 2>/dev/null || git branch -f "$HEAD_REF" "origin/$HEAD_REF" |
| 125 | + git checkout "$HEAD_REF" |
| 126 | +
|
| 127 | + # Invoke Claude to perform an automated PR review with progress tracking |
80 | 128 | - name: PR Review with Progress Tracking |
81 | 129 | uses: anthropics/claude-code-action@v1 |
82 | 130 | with: |
83 | 131 | anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} |
84 | 132 | github_token: ${{ secrets.GITHUB_TOKEN }} |
85 | 133 |
|
86 | | - # Enable progress tracking |
| 134 | + # Enable progress tracking and show full Claude output in logs |
87 | 135 | track_progress: true |
88 | 136 | show_full_output: true |
89 | 137 |
|
90 | | - # Your custom review instructions |
| 138 | + # Custom review instructions passed to Claude |
91 | 139 | prompt: | |
92 | 140 | REPO: ${{ github.repository }} |
93 | 141 |
|
@@ -121,6 +169,6 @@ jobs: |
121 | 169 | Provide detailed feedback using inline comments for specific issues. |
122 | 170 | Use top-level comments for general observations or praise. |
123 | 171 |
|
124 | | - # Tools for comprehensive PR review |
| 172 | + # Restrict tools that Claude can use during the review |
125 | 173 | claude_args: | |
126 | 174 | --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)" |
0 commit comments