Skip to content

Commit c05cda2

Browse files
ajstormclaude
andcommitted
dev-inf: add GitHub Actions workflows for issue auto-solving
Add two new GitHub Actions workflows to enable automated issue resolution using Claude Code: 1. issue-autosolve.yml - Triggered when an issue is labeled c-autosolve: - Assesses issue feasibility using Claude Opus - Implements fix with tests if suitable - Creates a cross-repo draft PR with o-autosolver label - Comments on the issue with results 2. pr-autosolve-comments.yml - Triggered when comments are left on PRs with the o-autosolver label: - Fetches all review comments - Uses Claude to address feedback - Amends commit and force-pushes - Posts summary with loop-prevention marker Both workflows use Vertex AI authentication and the Claude Opus model. Release note: None Epic: None Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b479177 commit c05cda2

File tree

2 files changed

+428
-0
lines changed

2 files changed

+428
-0
lines changed
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
name: Issue Auto-Solver
2+
3+
on:
4+
issues:
5+
types: [labeled]
6+
7+
concurrency:
8+
group: autosolve-issue-${{ github.event.issue.number }}
9+
cancel-in-progress: true
10+
11+
jobs:
12+
auto-solve-issue:
13+
runs-on: ubuntu-latest
14+
timeout-minutes: 60
15+
if: github.event.label.name == 'c-autosolve'
16+
permissions:
17+
contents: write
18+
pull-requests: write
19+
issues: write
20+
id-token: write
21+
22+
steps:
23+
- name: Validate required secrets
24+
run: |
25+
if [ -z "${{ secrets.AUTOSOLVER_PAT }}" ]; then
26+
echo "::error::AUTOSOLVER_PAT secret is not configured"
27+
exit 1
28+
fi
29+
30+
- name: Checkout repository
31+
uses: actions/checkout@v5
32+
with:
33+
fetch-depth: 0
34+
35+
- name: Authenticate to Google Cloud
36+
uses: 'google-github-actions/auth@v3'
37+
with:
38+
project_id: 'vertex-model-runners'
39+
service_account: 'ai-review@dev-inf-prod.iam.gserviceaccount.com'
40+
workload_identity_provider: 'projects/72497726731/locations/global/workloadIdentityPools/ai-review/providers/ai-review'
41+
42+
- name: Stage 1 - Assess Issue Feasibility
43+
id: assess
44+
uses: cockroachdb/claude-code-action@v1
45+
env:
46+
ANTHROPIC_VERTEX_PROJECT_ID: vertex-model-runners
47+
CLOUD_ML_REGION: us-east5
48+
with:
49+
github_token: ${{ secrets.GITHUB_TOKEN }}
50+
use_vertex: "true"
51+
claude_args: |
52+
--model claude-opus-4-5@20251101
53+
--allowedTools "Read,Grep,Glob,Bash(gh issue view:*)"
54+
prompt: |
55+
Assess GitHub issue #${{ github.event.issue.number }}
56+
Title: ${{ github.event.issue.title }}
57+
Body: ${{ github.event.issue.body }}
58+
59+
Determine if this issue is suitable for automated one-shot resolution.
60+
61+
Criteria for PROCEED:
62+
- Clear bug description (reproduction steps or description of how to reproduce)
63+
- Single component affected
64+
- No architectural changes required
65+
66+
Criteria for SKIP:
67+
- Requires design decisions or RFC
68+
- Affects multiple major components
69+
- Requires human judgment on product direction
70+
71+
**OUTPUT REQUIREMENT**: End your response with a single line containing only:
72+
- `ASSESSMENT_RESULT - PROCEED` or
73+
- `ASSESSMENT_RESULT - SKIP`
74+
75+
- name: Extract Assessment Result
76+
id: assess_result
77+
if: steps.assess.conclusion == 'success'
78+
run: |
79+
RESULT=$(jq -r '.[] | select(.type == "result") | .result' "${{ steps.assess.outputs.execution_file }}")
80+
{
81+
echo 'result<<EOF'
82+
echo "$RESULT"
83+
echo 'EOF'
84+
} >> "$GITHUB_OUTPUT"
85+
echo "Assessment result extracted (${#RESULT} characters)"
86+
87+
- name: Stage 2 - Implement Fix
88+
id: implement
89+
if: contains(steps.assess_result.outputs.result, 'ASSESSMENT_RESULT - PROCEED')
90+
uses: cockroachdb/claude-code-action@v1
91+
env:
92+
ANTHROPIC_VERTEX_PROJECT_ID: vertex-model-runners
93+
CLOUD_ML_REGION: us-east5
94+
with:
95+
github_token: ${{ secrets.GITHUB_TOKEN }}
96+
use_vertex: "true"
97+
claude_args: |
98+
--model claude-opus-4-5@20251101
99+
--allowedTools "Read,Write,Edit,Grep,Glob,Bash(./dev test:*),Bash(./dev testlogic:*),Bash(./dev build:*),Bash(./dev generate:*),Bash(git:*)"
100+
prompt: |
101+
Fix GitHub issue #${{ github.event.issue.number }}
102+
Title: ${{ github.event.issue.title }}
103+
Body: ${{ github.event.issue.body }}
104+
105+
Instructions:
106+
1. Read CLAUDE.md for project conventions and commit message format
107+
2. Read and understand the issue
108+
3. Implement the minimal fix required
109+
4. Add or update tests to verify the fix
110+
5. Run tests with ./dev test or ./dev testlogic
111+
6. Stage all changes with git add
112+
113+
When formatting commits and PRs, follow the guidelines in CLAUDE.md.
114+
115+
**OUTPUT REQUIREMENT**: End your response with a single line containing only:
116+
- `IMPLEMENTATION_RESULT - SUCCESS` or
117+
- `IMPLEMENTATION_RESULT - FAILED`
118+
119+
- name: Extract Implementation Result
120+
id: implement_result
121+
if: steps.implement.conclusion == 'success'
122+
run: |
123+
RESULT=$(jq -r '.[] | select(.type == "result") | .result' "${{ steps.implement.outputs.execution_file }}")
124+
{
125+
echo 'result<<EOF'
126+
echo "$RESULT"
127+
echo 'EOF'
128+
} >> "$GITHUB_OUTPUT"
129+
echo "Implementation result extracted (${#RESULT} characters)"
130+
131+
- name: Create branch and push to fork
132+
id: push
133+
if: contains(steps.implement_result.outputs.result, 'IMPLEMENTATION_RESULT - SUCCESS')
134+
env:
135+
AUTOSOLVER_PAT: ${{ secrets.AUTOSOLVER_PAT }}
136+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
137+
run: |
138+
git config user.name "crdb-autosolver"
139+
git config user.email "crdb-autosolver@users.noreply.github.com"
140+
141+
# Configure git credential helper to use PAT for the fork (avoids exposing token in URLs)
142+
git config --global credential.helper store
143+
echo "https://crdb-autosolver:${AUTOSOLVER_PAT}@github.com" > ~/.git-credentials
144+
chmod 600 ~/.git-credentials
145+
146+
# Add the fork as a remote (handle case where it already exists)
147+
git remote add fork https://github.com/crdb-autosolver/cockroach.git 2>/dev/null || \
148+
git remote set-url fork https://github.com/crdb-autosolver/cockroach.git
149+
150+
# Create branch first, then add files
151+
BRANCH_NAME="fix/issue-${{ github.event.issue.number }}"
152+
git checkout -b "$BRANCH_NAME"
153+
git add -A
154+
155+
# Get issue title for commit message (escape for safe use in heredoc)
156+
ISSUE_TITLE=$(gh issue view ${{ github.event.issue.number }} --json title -q '.title' 2>/dev/null || echo "fix issue #${{ github.event.issue.number }}")
157+
158+
# Get the first package modified for commit prefix (use --cached since files are now staged)
159+
PREFIX=$(git diff --name-only --cached 2>/dev/null | grep '\.go$' | head -1 | sed 's|pkg/||' | cut -d'/' -f1)
160+
if [ -z "$PREFIX" ]; then
161+
PREFIX="*"
162+
fi
163+
164+
# Create commit with proper formatting per CLAUDE.md using heredoc for safety
165+
# Note: heredoc content must start at column 0 to avoid whitespace in commit message
166+
git commit -F - <<EOF
167+
${PREFIX}: ${ISSUE_TITLE}
168+
169+
Fixes #${{ github.event.issue.number }}
170+
171+
Release note: None
172+
173+
Epic: None
174+
175+
Generated by Claude Code Auto-Solver
176+
Co-Authored-By: Claude <noreply@anthropic.com>
177+
EOF
178+
179+
# Push to the fork
180+
git push -u fork "$BRANCH_NAME" --force
181+
182+
echo "branch_name=$BRANCH_NAME" >> "$GITHUB_OUTPUT"
183+
184+
- name: Create PR
185+
id: create_pr
186+
if: steps.push.conclusion == 'success'
187+
env:
188+
GH_TOKEN: ${{ secrets.AUTOSOLVER_PAT }}
189+
run: |
190+
# Get issue title
191+
ISSUE_TITLE=$(gh issue view ${{ github.event.issue.number }} --repo ${{ github.repository }} --json title -q '.title' 2>/dev/null || echo "Issue #${{ github.event.issue.number }}")
192+
193+
# Get commit stats
194+
STATS=$(git diff --stat HEAD~1..HEAD 2>/dev/null || echo "")
195+
196+
# Create the PR from fork to upstream
197+
PR_URL=$(gh pr create \
198+
--repo ${{ github.repository }} \
199+
--head crdb-autosolver:${{ steps.push.outputs.branch_name }} \
200+
--base master \
201+
--draft \
202+
--title "$(git log -1 --pretty=%s)" \
203+
--body "Fixes #${{ github.event.issue.number }}
204+
205+
## Summary
206+
207+
This PR fixes **${ISSUE_TITLE}**.
208+
209+
### Changes Made
210+
211+
\`\`\`
212+
${STATS}
213+
\`\`\`
214+
215+
## Test Plan
216+
217+
- [x] Tests pass locally
218+
219+
---
220+
221+
*This PR was auto-generated by [crdb-issue-autosolver](https://github.com/ajstorm/crdb-issue-autosolver) using Claude Code.*
222+
*Please review carefully before approving.*" \
223+
--label "o-autosolver")
224+
225+
echo "pr_url=$PR_URL" >> "$GITHUB_OUTPUT"
226+
echo "Created PR: $PR_URL"
227+
228+
- name: Comment on issue - Success
229+
if: steps.create_pr.conclusion == 'success'
230+
env:
231+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
232+
run: |
233+
gh issue comment ${{ github.event.issue.number }} --body \
234+
"Auto-solver has created a draft PR to address this issue: ${{ steps.create_pr.outputs.pr_url }}
235+
236+
Please review the changes carefully before approving."
237+
238+
- name: Comment on issue - Skipped
239+
if: contains(steps.assess_result.outputs.result, 'ASSESSMENT_RESULT - SKIP')
240+
env:
241+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
242+
run: |
243+
gh issue comment ${{ github.event.issue.number }} --body \
244+
"Auto-solver assessed this issue but determined it is not suitable for automated resolution.
245+
246+
**Assessment:**
247+
${{ steps.assess_result.outputs.result }}
248+
249+
This issue may require human intervention due to complexity, architectural considerations, or ambiguity."
250+
251+
- name: Comment on issue - Failed
252+
if: |
253+
(steps.implement.conclusion == 'failure' ||
254+
contains(steps.implement_result.outputs.result, 'IMPLEMENTATION_RESULT - FAILED')) &&
255+
!contains(steps.assess_result.outputs.result, 'ASSESSMENT_RESULT - SKIP')
256+
env:
257+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
258+
run: |
259+
gh issue comment ${{ github.event.issue.number }} --body \
260+
"Auto-solver attempted to fix this issue but was unable to complete the implementation.
261+
262+
This issue may require human intervention."
263+
264+
- name: Remove c-autosolve label
265+
if: always()
266+
env:
267+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
268+
run: |
269+
gh issue edit ${{ github.event.issue.number }} --remove-label "c-autosolve" || true

0 commit comments

Comments
 (0)