66
77jobs :
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