mirror of
https://github.com/block/goose.git
synced 2026-07-17 12:56:20 +02:00
Add /goose issue solver github workflow (#6068)
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
name: goose Issue Solver
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
issue_number:
|
||||
description: 'Issue number to solve'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
env:
|
||||
GOOSE_RECIPE: |
|
||||
version: "1.0.0"
|
||||
title: "Solve GitHub Issue"
|
||||
description: "Solve GitHub issue #${ISSUE_NUMBER}"
|
||||
|
||||
extensions:
|
||||
- type: builtin
|
||||
name: developer
|
||||
- type: platform
|
||||
name: todo
|
||||
|
||||
instructions: |
|
||||
Principles:
|
||||
- Extract all requirements before coding. Missing one means failure.
|
||||
- Understand before changing. Research the code first.
|
||||
- Follow existing patterns and AGENTS.md if it exists.
|
||||
- Stop when requirements are met. Nothing more.
|
||||
- Verify through deterministic means.
|
||||
- Your context degrades. The TODO is your memory. Update it after each step.
|
||||
|
||||
prompt: |
|
||||
Solve GitHub issue #${ISSUE_NUMBER}: ${ISSUE_TITLE}
|
||||
|
||||
The issue is saved at /tmp/issue.json
|
||||
|
||||
Trigger comment:
|
||||
${TRIGGER_COMMENT}
|
||||
|
||||
Write this to your TODO immediately and update as you progress:
|
||||
|
||||
## Phase 1: Understand
|
||||
- [ ] Read /tmp/issue.json
|
||||
- [ ] Write all requirements (explicit + implicit) to /tmp/requirements.md
|
||||
- [ ] Read AGENTS.md if it exists
|
||||
|
||||
## Phase 2: Research
|
||||
- [ ] Explore codebase with analyze and rg
|
||||
- [ ] Identify files that need to change
|
||||
- [ ] Update TODO with findings
|
||||
|
||||
## Phase 3: Plan
|
||||
- [ ] Decide on implementation approach
|
||||
- [ ] For nontrivial issues, use subagents to evaluate architecture or implementation choices
|
||||
- [ ] Update TODO with specific changes to make
|
||||
|
||||
## Phase 4: Implement
|
||||
- [ ] Implement minimal fix per /tmp/requirements.md
|
||||
- [ ] Before adding anything, check: is it in the requirements? If not, don't.
|
||||
- [ ] No .github/, no lock files, no secrets
|
||||
|
||||
## Phase 5: Verify
|
||||
- [ ] source bin/activate-hermit
|
||||
- [ ] cargo check
|
||||
- [ ] cargo test (affected crates)
|
||||
- [ ] cargo fmt
|
||||
- [ ] ./scripts/clippy-lint.sh
|
||||
- [ ] Fix failures, retry up to 3 times
|
||||
|
||||
## Phase 6: Confirm (MANDATORY)
|
||||
- [ ] Reread /tmp/issue.json
|
||||
- [ ] Reread /tmp/requirements.md
|
||||
- [ ] Confirm all requirements met, nothing extra added
|
||||
- [ ] Write a summary of changes to /tmp/issue_summary.txt
|
||||
|
||||
The Phase 6 "Reread" steps MUST appear in your updated TODO. Skipping them is failure.
|
||||
|
||||
Only write /tmp/issue_summary.txt if the fix is complete and verified.
|
||||
Run `git add` for any new files required for the fix.
|
||||
Do NOT commit. Leave changes in the working directory for the workflow to handle.
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: read
|
||||
|
||||
concurrency:
|
||||
group: goose-issue-${{ github.event.issue.number || github.event.inputs.issue_number }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
solve-issue:
|
||||
if: |
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(!github.event.issue.pull_request &&
|
||||
startsWith(github.event.comment.body, '/goose') &&
|
||||
contains(fromJSON('["OWNER", "MEMBER"]'), github.event.comment.author_association))
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
|
||||
container:
|
||||
image: ghcr.io/block/goose:latest
|
||||
options: --user root
|
||||
env:
|
||||
GOOSE_PROVIDER: ${{ vars.GOOSE_PROVIDER || 'openai' }}
|
||||
GOOSE_MODEL: ${{ vars.GOOSE_MODEL || 'gpt-5.1' }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
HOME: /tmp/goose-home
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y jq gettext curl build-essential pkg-config libssl-dev
|
||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null
|
||||
apt-get update
|
||||
apt-get install -y gh
|
||||
|
||||
- name: Get issue details (issue_comment)
|
||||
if: github.event_name == 'issue_comment'
|
||||
env:
|
||||
ISSUE_JSON: ${{ toJSON(github.event.issue) }}
|
||||
run: printenv ISSUE_JSON > /tmp/issue.json
|
||||
|
||||
- name: Get issue details (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: gh api /repos/${{ github.repository }}/issues/${{ github.event.inputs.issue_number }} > /tmp/issue.json
|
||||
|
||||
- name: Set issue outputs
|
||||
id: issue
|
||||
run: |
|
||||
echo "number=$(jq -r '.number' /tmp/issue.json)" >> $GITHUB_OUTPUT
|
||||
|
||||
echo "title<<TITLE_EOF" >> $GITHUB_OUTPUT
|
||||
jq -r '.title' /tmp/issue.json >> $GITHUB_OUTPUT
|
||||
echo "TITLE_EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run goose
|
||||
id: goose
|
||||
env:
|
||||
ISSUE_NUMBER: ${{ steps.issue.outputs.number }}
|
||||
ISSUE_TITLE: ${{ steps.issue.outputs.title }}
|
||||
TRIGGER_COMMENT: ${{ github.event.comment.body || 'Triggered via workflow_dispatch' }}
|
||||
run: |
|
||||
mkdir -p $HOME/.local/share/goose/sessions
|
||||
mkdir -p $HOME/.config/goose
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
echo "$GOOSE_RECIPE" | envsubst '$ISSUE_NUMBER $ISSUE_TITLE $TRIGGER_COMMENT' > /tmp/recipe.yaml
|
||||
|
||||
goose run --recipe /tmp/recipe.yaml
|
||||
|
||||
if [ -n "$(git status --porcelain)" ] && [ -f /tmp/issue_summary.txt ]; then
|
||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
||||
echo "summary<<SUMMARY_EOF" >> $GITHUB_OUTPUT
|
||||
cat /tmp/issue_summary.txt >> $GITHUB_OUTPUT
|
||||
echo "SUMMARY_EOF" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Verify no workflow changes
|
||||
if: steps.goose.outputs.has_changes == 'true'
|
||||
run: |
|
||||
if git diff --name-only | grep -q "^\.github/"; then
|
||||
echo "::error::Changes to .github/ are not allowed"
|
||||
git checkout -- .github/
|
||||
fi
|
||||
|
||||
- name: Create Pull Request
|
||||
if: steps.goose.outputs.has_changes == 'true'
|
||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # pin@v7.0.8
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: "fix: ${{ steps.issue.outputs.title }}"
|
||||
title: "fix: ${{ steps.issue.outputs.title }}"
|
||||
branch: goose/issue-${{ steps.issue.outputs.number }}
|
||||
delete-branch: true
|
||||
draft: true
|
||||
labels: goose-generated
|
||||
body: |
|
||||
Closes #${{ steps.issue.outputs.number }}
|
||||
|
||||
## Summary
|
||||
${{ steps.goose.outputs.summary || 'See commits for details.' }}
|
||||
|
||||
---
|
||||
*Generated by goose Issue Solver*
|
||||
Reference in New Issue
Block a user