Skip to content

Commit 0576603

Browse files
GiggleLiuclaude
andcommitted
Update PR automation workflow
- Add commit status reporting - Support both runner env and repository secret for API key - Self-hosted runner uses runner's .env, GitHub-hosted uses secrets Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 318a542 commit 0576603

1 file changed

Lines changed: 46 additions & 110 deletions

File tree

.github/workflows/pr-automation.yml

Lines changed: 46 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,19 @@ on:
66

77
jobs:
88
execute:
9-
# Only run on PR comments (not issue comments) from repo owner/collaborators
9+
# Only run on PR comments with recognized commands
1010
if: |
1111
github.event.issue.pull_request &&
12-
startsWith(github.event.comment.body, '[action]') ||
13-
startsWith(github.event.comment.body, '[fix]') ||
14-
startsWith(github.event.comment.body, '[debug]')
12+
(startsWith(github.event.comment.body, '[action]') ||
13+
startsWith(github.event.comment.body, '[fix]') ||
14+
startsWith(github.event.comment.body, '[debug]'))
1515
16-
# Use self-hosted runner to run Claude on your local machine
17-
# Change to 'ubuntu-latest' to run on GitHub-hosted runners instead
18-
runs-on: ubuntu-latest
16+
runs-on: self-hosted
1917

2018
permissions:
2119
contents: write
2220
pull-requests: write
23-
issues: write
21+
statuses: write
2422

2523
steps:
2624
- name: Get PR details
@@ -36,23 +34,25 @@ jobs:
3634
core.setOutput('branch', pr.data.head.ref);
3735
core.setOutput('sha', pr.data.head.sha);
3836
39-
// Determine command
4037
const body = context.payload.comment.body;
4138
let command = 'unknown';
4239
if (body.startsWith('[action]')) command = 'action';
4340
else if (body.startsWith('[fix]')) command = 'fix';
4441
else if (body.startsWith('[debug]')) command = 'debug';
4542
core.setOutput('command', command);
4643
47-
- name: Post queued comment
44+
- name: Set pending status
4845
uses: actions/github-script@v7
4946
with:
5047
script: |
51-
await github.rest.issues.createComment({
48+
await github.rest.repos.createCommitStatus({
5249
owner: context.repo.owner,
5350
repo: context.repo.repo,
54-
issue_number: context.issue.number,
55-
body: '[queued] Job started in GitHub Actions...'
51+
sha: '${{ steps.pr.outputs.sha }}',
52+
state: 'pending',
53+
context: 'PR Automation / ${{ steps.pr.outputs.command }}',
54+
description: 'Running...',
55+
target_url: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
5656
});
5757
5858
- name: Checkout PR branch
@@ -76,75 +76,41 @@ jobs:
7676
if: steps.pr.outputs.command == 'action'
7777
run: |
7878
for f in PLAN.md plan.md .claude/plan.md docs/plan.md; do
79-
if [ -f "$f" ]; then
80-
echo "file=$f" >> $GITHUB_OUTPUT
81-
exit 0
82-
fi
79+
[ -f "$f" ] && echo "file=$f" >> $GITHUB_OUTPUT && exit 0
8380
done
84-
# Check docs/plans/*.md
8581
latest=$(ls -t docs/plans/*.md 2>/dev/null | head -1)
86-
if [ -n "$latest" ]; then
87-
echo "file=$latest" >> $GITHUB_OUTPUT
88-
exit 0
89-
fi
90-
echo "file=" >> $GITHUB_OUTPUT
82+
[ -n "$latest" ] && echo "file=$latest" >> $GITHUB_OUTPUT && exit 0
83+
echo "No plan file found" && exit 1
9184
9285
- name: Execute plan
93-
if: steps.pr.outputs.command == 'action' && steps.plan.outputs.file != ''
94-
id: execute
86+
if: steps.pr.outputs.command == 'action'
9587
env:
96-
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
88+
ANTHROPIC_API_KEY_SECRET: ${{ secrets.ANTHROPIC_API_KEY }}
9789
run: |
98-
set +e
99-
OUTPUT=$(claude --dangerously-skip-permissions --max-turns 100 -p "
90+
# Use secret if set, otherwise use runner's env
91+
[ -n "$ANTHROPIC_API_KEY_SECRET" ] && export ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY_SECRET"
92+
claude --dangerously-skip-permissions --max-turns 100 -p "
10093
Execute the plan in '${{ steps.plan.outputs.file }}'.
10194
10295
Instructions:
10396
1. Read the plan file carefully
10497
2. Implement each step in order
10598
3. Commit changes with descriptive messages
10699
4. Push changes: git push origin ${{ steps.pr.outputs.branch }}
107-
108-
Do NOT post comments to the PR.
109-
" 2>&1)
110-
EXIT_CODE=$?
111-
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
112-
113-
# Save output to file (for artifact)
114-
echo "$OUTPUT" > claude-output.txt
115-
116-
# Save truncated output for comment
117-
echo "output<<EOF" >> $GITHUB_OUTPUT
118-
echo "$OUTPUT" | tail -100 >> $GITHUB_OUTPUT
119-
echo "EOF" >> $GITHUB_OUTPUT
120-
121-
- name: Handle missing plan
122-
if: steps.pr.outputs.command == 'action' && steps.plan.outputs.file == ''
123-
uses: actions/github-script@v7
124-
with:
125-
script: |
126-
await github.rest.issues.createComment({
127-
owner: context.repo.owner,
128-
repo: context.repo.repo,
129-
issue_number: context.issue.number,
130-
body: '[waiting] No plan file found. Please create one of: PLAN.md, plan.md, .claude/plan.md, docs/plan.md, or docs/plans/*.md'
131-
});
132-
core.setFailed('No plan file found');
100+
" 2>&1 | tee claude-output.txt
133101
134102
- name: Fix review comments
135103
if: steps.pr.outputs.command == 'fix'
136-
id: fix
137104
env:
138-
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
105+
ANTHROPIC_API_KEY_SECRET: ${{ secrets.ANTHROPIC_API_KEY }}
139106
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
140107
run: |
141-
set +e
142-
143-
# Fetch review comments
108+
# Use secret if set, otherwise use runner's env
109+
[ -n "$ANTHROPIC_API_KEY_SECRET" ] && export ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY_SECRET"
144110
INLINE=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.issue.number }}/comments --jq '.[].body' 2>/dev/null || echo "")
145111
REVIEWS=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.issue.number }}/reviews --jq '.[] | select(.body != "") | .body' 2>/dev/null || echo "")
146112
147-
OUTPUT=$(claude --dangerously-skip-permissions --max-turns 100 -p "
113+
claude --dangerously-skip-permissions --max-turns 100 -p "
148114
Address the PR review comments.
149115
150116
=== Inline Review Comments ===
@@ -158,77 +124,47 @@ jobs:
158124
2. Make the requested changes to the code
159125
3. Commit: git commit -am 'Address PR review feedback'
160126
4. Push: git push origin ${{ steps.pr.outputs.branch }}
161-
162-
Do NOT post comments to the PR.
163-
" 2>&1)
164-
EXIT_CODE=$?
165-
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
166-
echo "$OUTPUT" > claude-output.txt
167-
echo "output<<EOF" >> $GITHUB_OUTPUT
168-
echo "$OUTPUT" | tail -100 >> $GITHUB_OUTPUT
169-
echo "EOF" >> $GITHUB_OUTPUT
127+
" 2>&1 | tee claude-output.txt
170128
171129
- name: Debug test
172130
if: steps.pr.outputs.command == 'debug'
173-
id: debug
174-
env:
175-
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
176-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
177131
run: |
178-
set +e
179-
OUTPUT=$(claude --dangerously-skip-permissions --max-turns 5 -p "
180-
This is a debug test. Post a comment to PR #${{ github.event.issue.number }} on repository ${{ github.repository }} with:
181-
gh pr comment ${{ github.event.issue.number }} --repo ${{ github.repository }} --body '[pass] GitHub Actions pipeline test successful'
182-
" 2>&1)
183-
EXIT_CODE=$?
184-
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
185-
echo "$OUTPUT" > claude-output.txt
186-
187-
- name: Upload Claude output
132+
echo "Debug test passed - workflow is working" | tee claude-output.txt
133+
134+
- name: Upload logs
188135
if: always()
189136
uses: actions/upload-artifact@v4
190137
with:
191138
name: claude-output
192139
path: claude-output.txt
193140
retention-days: 7
194141

195-
- name: Post success comment
196-
if: success() && (steps.execute.outputs.exit_code == '0' || steps.fix.outputs.exit_code == '0')
142+
- name: Set success status
143+
if: success()
197144
uses: actions/github-script@v7
198145
with:
199146
script: |
200-
const command = '${{ steps.pr.outputs.command }}';
201-
const msg = command === 'action' ? '[done] Plan execution completed.' : '[fixed] Review comments addressed.';
202-
const output = `${{ steps.execute.outputs.output || steps.fix.outputs.output }}`;
203-
204-
let body = msg;
205-
if (output) {
206-
body += `\n\n<details><summary>Claude output (last 100 lines)</summary>\n\n\`\`\`\n${output}\n\`\`\`\n</details>`;
207-
}
208-
body += `\n\n[View full logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
209-
210-
await github.rest.issues.createComment({
147+
await github.rest.repos.createCommitStatus({
211148
owner: context.repo.owner,
212149
repo: context.repo.repo,
213-
issue_number: context.issue.number,
214-
body: body
150+
sha: '${{ steps.pr.outputs.sha }}',
151+
state: 'success',
152+
context: 'PR Automation / ${{ steps.pr.outputs.command }}',
153+
description: 'Completed successfully',
154+
target_url: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
215155
});
216156
217-
- name: Post failure comment
218-
if: failure() || steps.execute.outputs.exit_code != '0' && steps.execute.outputs.exit_code != '' || steps.fix.outputs.exit_code != '0' && steps.fix.outputs.exit_code != ''
157+
- name: Set failure status
158+
if: failure()
219159
uses: actions/github-script@v7
220160
with:
221161
script: |
222-
const output = `${{ steps.execute.outputs.output || steps.fix.outputs.output }}`;
223-
let body = '[failed] Job failed.';
224-
if (output) {
225-
body += `\n\n<details><summary>Claude output (last 100 lines)</summary>\n\n\`\`\`\n${output}\n\`\`\`\n</details>`;
226-
}
227-
body += `\n\n[View full logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
228-
229-
await github.rest.issues.createComment({
162+
await github.rest.repos.createCommitStatus({
230163
owner: context.repo.owner,
231164
repo: context.repo.repo,
232-
issue_number: context.issue.number,
233-
body: body
165+
sha: '${{ steps.pr.outputs.sha }}',
166+
state: 'failure',
167+
context: 'PR Automation / ${{ steps.pr.outputs.command }}',
168+
description: 'Failed - check logs',
169+
target_url: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
234170
});

0 commit comments

Comments
 (0)