From 19bbb7e58c614beb9ada53faee8215384cf0a999 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 00:56:06 +0000 Subject: [PATCH 1/9] Initial plan From f2ead62e6f45a31b7bf70bb3a5fd5db897b27b89 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 00:59:41 +0000 Subject: [PATCH 2/9] Address review comments on auto-fix-ci workflow Co-authored-by: nhorton <204146+nhorton@users.noreply.github.com> --- .github/workflows/auto-fix-ci.yml | 91 ++++++++++++++++++------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/.github/workflows/auto-fix-ci.yml b/.github/workflows/auto-fix-ci.yml index 2c770d2..f29e13f 100644 --- a/.github/workflows/auto-fix-ci.yml +++ b/.github/workflows/auto-fix-ci.yml @@ -51,7 +51,9 @@ jobs: if: fromJSON(steps.pr_check.outputs.result).isOpen id: check_loop run: | - # Check last 3 commits for auto-fix tag to be more robust + # Check last 3 commits for auto-fix tag to prevent infinite loops. + # We look back 3 commits as a lightweight safeguard: this is enough to catch + # any recent auto-fix pushes triggered by this workflow without scanning the full history. RECENT_COMMITS=$(git log -3 --pretty=%s) if echo "$RECENT_COMMITS" | grep -q "\[auto-fix\]"; then echo "skip=true" >> $GITHUB_OUTPUT @@ -60,14 +62,6 @@ jobs: echo "skip=false" >> $GITHUB_OUTPUT fi - - name: Setup git identity - if: | - fromJSON(steps.pr_check.outputs.result).isOpen && - steps.check_loop.outputs.skip != 'true' - run: | - git config --global user.email "claude[bot]@users.noreply.github.com" - git config --global user.name "claude[bot]" - - name: Get CI failure details if: | fromJSON(steps.pr_check.outputs.result).isOpen && @@ -107,6 +101,8 @@ jobs: repo: context.repo.repo, job_id: job.id }); + // Truncate logs to 50000 characters to stay within Claude's context window + // and GitHub API response size limits errorLogs.push({ jobName: job.name, logs: logs.data.substring(0, 50000) @@ -168,7 +164,7 @@ jobs: ${{ toJSON(fromJSON(steps.failure_details.outputs.result).errorLogs) }} ``` anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - claude_args: "--allowedTools 'Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git:*),Bash(uv:*),Bash(python:*),Bash(pytest:*),Bash(ruff:*)'" + claude_args: --allowedTools Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git commit:*),Bash(git push:*),Bash(git status:*),Bash(git diff:*),Bash(uv:*),Bash(python:*),Bash(pytest:*),Bash(ruff:*) - name: Comment on PR with fix status if: | @@ -179,40 +175,61 @@ jobs: uses: actions/github-script@v7 with: script: | - const prNumber = ${{ github.event.workflow_run.pull_requests[0].number }}; + // Safely access pull request number with null check + const pullRequests = context.payload.workflow_run?.pull_requests; + if (!pullRequests || pullRequests.length === 0) { + console.log('No pull request found, skipping comment'); + return; + } + const prNumber = pullRequests[0].number; + + // Safely access failure details with null check + const failureDetails = '${{ steps.failure_details.outputs.result }}'; + if (!failureDetails) { + console.log('No failure details available, skipping comment'); + return; + } + const failureData = JSON.parse(failureDetails); + const claudeOutcome = '${{ steps.claude.outcome }}'; - const hasFailedJobs = ${{ fromJSON(steps.failure_details.outputs.result).hasFailedJobs }}; + const hasFailedJobs = failureData.hasFailedJobs; const runUrl = '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'; - const failureUrl = '${{ fromJSON(steps.failure_details.outputs.result).runUrl }}'; + const failureUrl = failureData.runUrl; let body; if (!hasFailedJobs) { - body = `## CI Auto-Fix Skipped - - The CI workflow failed but no individual jobs failed (possibly a setup/infrastructure issue). - - - **Fix workflow run**: ${runUrl} - - **Original failure**: ${failureUrl} - - Manual investigation may be required.`; + body = [ + '## CI Auto-Fix Skipped', + '', + 'The CI workflow failed but no individual jobs failed (possibly a setup/infrastructure issue).', + '', + `- **Fix workflow run**: ${runUrl}`, + `- **Original failure**: ${failureUrl}`, + '', + 'Manual investigation may be required.' + ].join('\n'); } else if (claudeOutcome === 'success') { - body = `## CI Auto-Fix Attempted - - Claude has analyzed the CI failure and attempted to fix the issues. - - - **Fix workflow run**: ${runUrl} - - **Original failure**: ${failureUrl} - - Please review the changes pushed to this branch.`; + body = [ + '## CI Auto-Fix Attempted', + '', + 'Claude has analyzed the CI failure and attempted to fix the issues.', + '', + `- **Fix workflow run**: ${runUrl}`, + `- **Original failure**: ${failureUrl}`, + '', + 'Please review the changes pushed to this branch.' + ].join('\n'); } else { - body = `## CI Auto-Fix Failed - - Claude attempted to fix the CI failure but encountered issues. - - - **Fix workflow run**: ${runUrl} - - **Original failure**: ${failureUrl} - - Manual intervention may be required.`; + body = [ + '## CI Auto-Fix Failed', + '', + 'Claude attempted to fix the CI failure but encountered issues.', + '', + `- **Fix workflow run**: ${runUrl}`, + `- **Original failure**: ${failureUrl}`, + '', + 'Manual intervention may be required.' + ].join('\n'); } await github.rest.issues.createComment({ From 0b359dc0f0283b10918f6d498e971836db76e870 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 01:00:34 +0000 Subject: [PATCH 3/9] Fix trailing spaces in workflow file Co-authored-by: nhorton <204146+nhorton@users.noreply.github.com> --- .github/workflows/auto-fix-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/auto-fix-ci.yml b/.github/workflows/auto-fix-ci.yml index f29e13f..00fd980 100644 --- a/.github/workflows/auto-fix-ci.yml +++ b/.github/workflows/auto-fix-ci.yml @@ -182,7 +182,7 @@ jobs: return; } const prNumber = pullRequests[0].number; - + // Safely access failure details with null check const failureDetails = '${{ steps.failure_details.outputs.result }}'; if (!failureDetails) { @@ -190,7 +190,7 @@ jobs: return; } const failureData = JSON.parse(failureDetails); - + const claudeOutcome = '${{ steps.claude.outcome }}'; const hasFailedJobs = failureData.hasFailedJobs; const runUrl = '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'; From b4f858ee4d28f34d048a0d8644d249412072f31e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 01:01:23 +0000 Subject: [PATCH 4/9] Fix claude_args quoting and improve null check Co-authored-by: nhorton <204146+nhorton@users.noreply.github.com> --- .github/workflows/auto-fix-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/auto-fix-ci.yml b/.github/workflows/auto-fix-ci.yml index 00fd980..2970b60 100644 --- a/.github/workflows/auto-fix-ci.yml +++ b/.github/workflows/auto-fix-ci.yml @@ -164,7 +164,7 @@ jobs: ${{ toJSON(fromJSON(steps.failure_details.outputs.result).errorLogs) }} ``` anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - claude_args: --allowedTools Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git commit:*),Bash(git push:*),Bash(git status:*),Bash(git diff:*),Bash(uv:*),Bash(python:*),Bash(pytest:*),Bash(ruff:*) + claude_args: "--allowedTools Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git commit:*),Bash(git push:*),Bash(git status:*),Bash(git diff:*),Bash(uv:*),Bash(python:*),Bash(pytest:*),Bash(ruff:*)" - name: Comment on PR with fix status if: | @@ -185,7 +185,7 @@ jobs: // Safely access failure details with null check const failureDetails = '${{ steps.failure_details.outputs.result }}'; - if (!failureDetails) { + if (!failureDetails || failureDetails.trim() === '') { console.log('No failure details available, skipping comment'); return; } From 5e7a7e6606b8f16c9a2d9b39da1379547ec8ee6e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 01:02:11 +0000 Subject: [PATCH 5/9] Use YAML folded scalar for claude_args to avoid quoting issues Co-authored-by: nhorton <204146+nhorton@users.noreply.github.com> --- .github/workflows/auto-fix-ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/auto-fix-ci.yml b/.github/workflows/auto-fix-ci.yml index 2970b60..e71e54d 100644 --- a/.github/workflows/auto-fix-ci.yml +++ b/.github/workflows/auto-fix-ci.yml @@ -164,7 +164,9 @@ jobs: ${{ toJSON(fromJSON(steps.failure_details.outputs.result).errorLogs) }} ``` anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - claude_args: "--allowedTools Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git commit:*),Bash(git push:*),Bash(git status:*),Bash(git diff:*),Bash(uv:*),Bash(python:*),Bash(pytest:*),Bash(ruff:*)" + claude_args: >- + --allowedTools + Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git commit:*),Bash(git push:*),Bash(git status:*),Bash(git diff:*),Bash(uv:*),Bash(python:*),Bash(pytest:*),Bash(ruff:*) - name: Comment on PR with fix status if: | From 83f33b2fcafc8d93b92946f9132b5319ff7d2981 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 01:03:10 +0000 Subject: [PATCH 6/9] Fix context object consistency and claude_args formatting Co-authored-by: nhorton <204146+nhorton@users.noreply.github.com> --- .github/workflows/auto-fix-ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/auto-fix-ci.yml b/.github/workflows/auto-fix-ci.yml index e71e54d..1027f85 100644 --- a/.github/workflows/auto-fix-ci.yml +++ b/.github/workflows/auto-fix-ci.yml @@ -164,9 +164,7 @@ jobs: ${{ toJSON(fromJSON(steps.failure_details.outputs.result).errorLogs) }} ``` anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - claude_args: >- - --allowedTools - Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git commit:*),Bash(git push:*),Bash(git status:*),Bash(git diff:*),Bash(uv:*),Bash(python:*),Bash(pytest:*),Bash(ruff:*) + claude_args: --allowedTools Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git commit:*),Bash(git push:*),Bash(git status:*),Bash(git diff:*),Bash(uv:*),Bash(python:*),Bash(pytest:*),Bash(ruff:*) - name: Comment on PR with fix status if: | @@ -178,7 +176,7 @@ jobs: with: script: | // Safely access pull request number with null check - const pullRequests = context.payload.workflow_run?.pull_requests; + const pullRequests = ${{ toJSON(github.event.workflow_run.pull_requests) }}; if (!pullRequests || pullRequests.length === 0) { console.log('No pull request found, skipping comment'); return; From bb9c183626aa4e1d70b2b8f997f60d9db8f4a2e0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 01:04:06 +0000 Subject: [PATCH 7/9] Add null safety check to PR validation step Co-authored-by: nhorton <204146+nhorton@users.noreply.github.com> --- .github/workflows/auto-fix-ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/auto-fix-ci.yml b/.github/workflows/auto-fix-ci.yml index 1027f85..555532b 100644 --- a/.github/workflows/auto-fix-ci.yml +++ b/.github/workflows/auto-fix-ci.yml @@ -32,10 +32,15 @@ jobs: uses: actions/github-script@v7 with: script: | + const pullRequests = ${{ toJSON(github.event.workflow_run.pull_requests) }}; + if (!pullRequests || pullRequests.length === 0) { + console.log('No pull requests found'); + return { isOpen: false }; + } const pr = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, - pull_number: ${{ github.event.workflow_run.pull_requests[0].number }} + pull_number: pullRequests[0].number }); return { isOpen: pr.data.state === 'open' }; From 77d746f7ca20501995c843b1bfbfc454fbfffe44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 01:04:47 +0000 Subject: [PATCH 8/9] Add JSON parsing safety and quote claude_args properly Co-authored-by: nhorton <204146+nhorton@users.noreply.github.com> --- .github/workflows/auto-fix-ci.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/auto-fix-ci.yml b/.github/workflows/auto-fix-ci.yml index 555532b..a242951 100644 --- a/.github/workflows/auto-fix-ci.yml +++ b/.github/workflows/auto-fix-ci.yml @@ -169,7 +169,7 @@ jobs: ${{ toJSON(fromJSON(steps.failure_details.outputs.result).errorLogs) }} ``` anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - claude_args: --allowedTools Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git commit:*),Bash(git push:*),Bash(git status:*),Bash(git diff:*),Bash(uv:*),Bash(python:*),Bash(pytest:*),Bash(ruff:*) + claude_args: "--allowedTools Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git commit:*),Bash(git push:*),Bash(git status:*),Bash(git diff:*),Bash(uv:*),Bash(python:*),Bash(pytest:*),Bash(ruff:*)" - name: Comment on PR with fix status if: | @@ -188,13 +188,19 @@ jobs: } const prNumber = pullRequests[0].number; - // Safely access failure details with null check + // Safely access failure details with null check and JSON validation const failureDetails = '${{ steps.failure_details.outputs.result }}'; - if (!failureDetails || failureDetails.trim() === '') { + if (!failureDetails || failureDetails.trim() === '' || failureDetails === 'undefined' || failureDetails === 'null') { console.log('No failure details available, skipping comment'); return; } - const failureData = JSON.parse(failureDetails); + let failureData; + try { + failureData = JSON.parse(failureDetails); + } catch (e) { + console.log('Failed to parse failure details:', e); + return; + } const claudeOutcome = '${{ steps.claude.outcome }}'; const hasFailedJobs = failureData.hasFailedJobs; From a6865335b7ebd44755b7b290a6db1cff04397010 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 01:05:51 +0000 Subject: [PATCH 9/9] Use validated PR number from pr_check step throughout workflow Co-authored-by: nhorton <204146+nhorton@users.noreply.github.com> --- .github/workflows/auto-fix-ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/auto-fix-ci.yml b/.github/workflows/auto-fix-ci.yml index a242951..cd547eb 100644 --- a/.github/workflows/auto-fix-ci.yml +++ b/.github/workflows/auto-fix-ci.yml @@ -35,14 +35,15 @@ jobs: const pullRequests = ${{ toJSON(github.event.workflow_run.pull_requests) }}; if (!pullRequests || pullRequests.length === 0) { console.log('No pull requests found'); - return { isOpen: false }; + return { isOpen: false, prNumber: null }; } + const prNumber = pullRequests[0].number; const pr = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, - pull_number: pullRequests[0].number + pull_number: prNumber }); - return { isOpen: pr.data.state === 'open' }; + return { isOpen: pr.data.state === 'open', prNumber: prNumber }; - name: Checkout code if: fromJSON(steps.pr_check.outputs.result).isOpen @@ -142,7 +143,7 @@ jobs: ## Failure Information - Failed CI Run: ${{ fromJSON(steps.failure_details.outputs.result).runUrl }} - Failed Jobs: ${{ join(fromJSON(steps.failure_details.outputs.result).failedJobs, ', ') }} - - PR Number: ${{ github.event.workflow_run.pull_requests[0].number }} + - PR Number: ${{ fromJSON(steps.pr_check.outputs.result).prNumber }} - Branch: ${{ github.event.workflow_run.head_branch }} - Repository: ${{ github.repository }}