Skip to content

Commit 8defd7e

Browse files
committed
Fix robustness issues in auto-fix-ci workflow [auto-fix]
- Add PR open check before attempting fixes - Check last 3 commits for [auto-fix] tag (not just last one) - Handle case where workflow fails but no jobs failed - Fix comment step to only run when failure_details succeeded - Remove unnecessary id-token permission - Add note about fork PR limitation
1 parent 34e1636 commit 8defd7e

File tree

1 file changed

+64
-15
lines changed

1 file changed

+64
-15
lines changed

.github/workflows/auto-fix-ci.yml

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
name: Auto Fix CI Failures
22

3+
# NOTE: This workflow only works for PRs from branches in the same repo.
4+
# Fork PRs cannot be auto-fixed because GITHUB_TOKEN lacks push access to forks.
5+
36
on:
47
workflow_run:
58
workflows: ["Validate"]
@@ -11,7 +14,6 @@ permissions:
1114
pull-requests: write
1215
actions: read
1316
issues: write
14-
id-token: write
1517

1618
jobs:
1719
auto-fix:
@@ -25,32 +27,51 @@ jobs:
2527
startsWith(github.event.workflow_run.head_branch, 'claude/')
2628
runs-on: ubuntu-latest
2729
steps:
30+
- name: Check if PR is still open
31+
id: pr_check
32+
uses: actions/github-script@v7
33+
with:
34+
script: |
35+
const pr = await github.rest.pulls.get({
36+
owner: context.repo.owner,
37+
repo: context.repo.repo,
38+
pull_number: ${{ github.event.workflow_run.pull_requests[0].number }}
39+
});
40+
return { isOpen: pr.data.state === 'open' };
41+
2842
- name: Checkout code
43+
if: fromJSON(steps.pr_check.outputs.result).isOpen
2944
uses: actions/checkout@v4
3045
with:
3146
ref: ${{ github.event.workflow_run.head_branch }}
3247
fetch-depth: 10
3348
token: ${{ secrets.GITHUB_TOKEN }}
3449

35-
- name: Check if last commit was auto-fix (prevent loops)
50+
- name: Check for recent auto-fix commits (prevent loops)
51+
if: fromJSON(steps.pr_check.outputs.result).isOpen
3652
id: check_loop
3753
run: |
38-
LAST_COMMIT_MSG=$(git log -1 --pretty=%s)
39-
if [[ "$LAST_COMMIT_MSG" == *"[auto-fix]"* ]]; then
54+
# Check last 3 commits for auto-fix tag to be more robust
55+
RECENT_COMMITS=$(git log -3 --pretty=%s)
56+
if echo "$RECENT_COMMITS" | grep -q "\[auto-fix\]"; then
4057
echo "skip=true" >> $GITHUB_OUTPUT
41-
echo "Last commit was an auto-fix, skipping to prevent loop"
58+
echo "Recent commit was an auto-fix, skipping to prevent loop"
4259
else
4360
echo "skip=false" >> $GITHUB_OUTPUT
4461
fi
4562
4663
- name: Setup git identity
47-
if: steps.check_loop.outputs.skip != 'true'
64+
if: |
65+
fromJSON(steps.pr_check.outputs.result).isOpen &&
66+
steps.check_loop.outputs.skip != 'true'
4867
run: |
4968
git config --global user.email "claude[bot]@users.noreply.github.com"
5069
git config --global user.name "claude[bot]"
5170
5271
- name: Get CI failure details
53-
if: steps.check_loop.outputs.skip != 'true'
72+
if: |
73+
fromJSON(steps.pr_check.outputs.result).isOpen &&
74+
steps.check_loop.outputs.skip != 'true'
5475
id: failure_details
5576
uses: actions/github-script@v7
5677
with:
@@ -69,6 +90,15 @@ jobs:
6990
7091
const failedJobs = jobs.data.jobs.filter(job => job.conclusion === 'failure');
7192
93+
if (failedJobs.length === 0) {
94+
return {
95+
runUrl: run.data.html_url,
96+
failedJobs: [],
97+
errorLogs: [],
98+
hasFailedJobs: false
99+
};
100+
}
101+
72102
let errorLogs = [];
73103
for (const job of failedJobs) {
74104
try {
@@ -79,7 +109,7 @@ jobs:
79109
});
80110
errorLogs.push({
81111
jobName: job.name,
82-
logs: logs.data.substring(0, 50000) // Limit log size
112+
logs: logs.data.substring(0, 50000)
83113
});
84114
} catch (e) {
85115
errorLogs.push({
@@ -92,11 +122,15 @@ jobs:
92122
return {
93123
runUrl: run.data.html_url,
94124
failedJobs: failedJobs.map(j => j.name),
95-
errorLogs: errorLogs
125+
errorLogs: errorLogs,
126+
hasFailedJobs: true
96127
};
97128
98129
- name: Fix CI failures with Claude
99-
if: steps.check_loop.outputs.skip != 'true'
130+
if: |
131+
fromJSON(steps.pr_check.outputs.result).isOpen &&
132+
steps.check_loop.outputs.skip != 'true' &&
133+
fromJSON(steps.failure_details.outputs.result).hasFailedJobs
100134
id: claude
101135
uses: anthropics/claude-code-action@v1
102136
with:
@@ -137,22 +171,37 @@ jobs:
137171
claude_args: "--allowedTools 'Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git:*),Bash(uv:*),Bash(python:*),Bash(pytest:*),Bash(ruff:*)'"
138172

139173
- name: Comment on PR with fix status
140-
if: always() && steps.check_loop.outputs.skip != 'true'
174+
if: |
175+
always() &&
176+
fromJSON(steps.pr_check.outputs.result).isOpen &&
177+
steps.check_loop.outputs.skip != 'true' &&
178+
steps.failure_details.outcome == 'success'
141179
uses: actions/github-script@v7
142180
with:
143181
script: |
144182
const prNumber = ${{ github.event.workflow_run.pull_requests[0].number }};
145-
const conclusion = '${{ steps.claude.outcome }}';
183+
const claudeOutcome = '${{ steps.claude.outcome }}';
184+
const hasFailedJobs = ${{ fromJSON(steps.failure_details.outputs.result).hasFailedJobs }};
146185
const runUrl = '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}';
186+
const failureUrl = '${{ fromJSON(steps.failure_details.outputs.result).runUrl }}';
147187
148188
let body;
149-
if (conclusion === 'success') {
189+
if (!hasFailedJobs) {
190+
body = `## CI Auto-Fix Skipped
191+
192+
The CI workflow failed but no individual jobs failed (possibly a setup/infrastructure issue).
193+
194+
- **Fix workflow run**: ${runUrl}
195+
- **Original failure**: ${failureUrl}
196+
197+
Manual investigation may be required.`;
198+
} else if (claudeOutcome === 'success') {
150199
body = `## CI Auto-Fix Attempted
151200
152201
Claude has analyzed the CI failure and attempted to fix the issues.
153202
154203
- **Fix workflow run**: ${runUrl}
155-
- **Original failure**: ${{ fromJSON(steps.failure_details.outputs.result).runUrl }}
204+
- **Original failure**: ${failureUrl}
156205
157206
Please review the changes pushed to this branch.`;
158207
} else {
@@ -161,7 +210,7 @@ jobs:
161210
Claude attempted to fix the CI failure but encountered issues.
162211
163212
- **Fix workflow run**: ${runUrl}
164-
- **Original failure**: ${{ fromJSON(steps.failure_details.outputs.result).runUrl }}
213+
- **Original failure**: ${failureUrl}
165214
166215
Manual intervention may be required.`;
167216
}

0 commit comments

Comments
 (0)