Add Docker support for Goose in CI/CD pipelines (#4434)
Adds a production-ready Docker image for Goose that enables using Goose itself in CI pipelines to improve the codebase.
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
name: Daily Test Coverage Finder
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run daily at 2 AM UTC
|
||||
- cron: '0 2 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: 'Dry run (no PR creation)'
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
find-untested-code:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/block/goose:latest
|
||||
options: --user root
|
||||
env:
|
||||
GOOSE_PROVIDER: ${{ vars.GOOSE_PROVIDER || 'openai' }}
|
||||
GOOSE_MODEL: ${{ vars.GOOSE_MODEL || 'gpt-4o' }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install analysis tools
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y jq ripgrep
|
||||
|
||||
- name: Find untested code and create working test
|
||||
id: find_untested
|
||||
run: |
|
||||
# Create analysis and test creation script
|
||||
cat << 'EOF' > /tmp/create_working_test.txt
|
||||
Your task is to find ONE untested function in the Rust codebase and create a working test for it.
|
||||
|
||||
Requirements:
|
||||
1. The function MUST be in the crates/ directory
|
||||
2. It MUST have actual logic (not just a simple getter/setter)
|
||||
3. It MUST not already have a test
|
||||
4. Prefer functions with complexity but that are still testable in isolation
|
||||
5. Focus on the goose crate first, then goose-cli, then others
|
||||
|
||||
Process:
|
||||
1. Find a suitable untested function
|
||||
2. Write a comprehensive unit test for it
|
||||
3. Apply your changes to the codebase
|
||||
4. Run the test with: cargo test --test <test_name>
|
||||
5. If the test fails:
|
||||
- Read and understand the error message
|
||||
- Fix the test code
|
||||
- Apply the fix and run the test again
|
||||
- Repeat up to 3 times until the test passes
|
||||
6. Once the test passes (or after 3 attempts), save the final changes as a git diff to /tmp/test_addition.patch
|
||||
7. Report the outcome:
|
||||
- If successful: write "SUCCESS" to /tmp/test_result.txt
|
||||
- If no suitable function found: write "NO_FUNCTION_FOUND" to /tmp/test_result.txt
|
||||
- If test couldn't be fixed: write "TEST_FAILED" to /tmp/test_result.txt
|
||||
|
||||
Important:
|
||||
- Only add ONE test for ONE function
|
||||
- The test MUST compile and pass before creating the patch
|
||||
- Keep changes minimal and focused
|
||||
- Include a descriptive test name that explains what is being tested
|
||||
EOF
|
||||
|
||||
goose run -i /tmp/create_working_test.txt
|
||||
|
||||
# Check the result
|
||||
if [ -f /tmp/test_result.txt ]; then
|
||||
RESULT=$(cat /tmp/test_result.txt)
|
||||
echo "Test creation result: $RESULT"
|
||||
|
||||
if [ "$RESULT" = "SUCCESS" ] && [ -f /tmp/test_addition.patch ]; then
|
||||
echo "patch_created=true" >> $GITHUB_OUTPUT
|
||||
# Extract function name from patch for PR title
|
||||
FUNC_NAME=$(grep -E "fn test_|#\[test\]" /tmp/test_addition.patch | head -1 | sed 's/.*test_//' | sed 's/(.*//' || echo "function")
|
||||
echo "function_name=${FUNC_NAME}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "patch_created=false" >> $GITHUB_OUTPUT
|
||||
echo "Reason: $RESULT"
|
||||
fi
|
||||
else
|
||||
echo "patch_created=false" >> $GITHUB_OUTPUT
|
||||
echo "No result file created"
|
||||
fi
|
||||
|
||||
- name: Create Pull Request
|
||||
if: steps.find_untested.outputs.patch_created == 'true' && github.event.inputs.dry_run != 'true'
|
||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # pin@v7.0.8
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: "test: add test for ${{ steps.find_untested.outputs.function_name }}"
|
||||
title: "test: add test coverage for ${{ steps.find_untested.outputs.function_name }}"
|
||||
body: |
|
||||
## 🤖 Automated Test Addition
|
||||
|
||||
This PR was automatically generated by Goose to improve test coverage.
|
||||
|
||||
### What changed?
|
||||
Added a unit test for a previously untested function.
|
||||
|
||||
### Why?
|
||||
Part of our daily automated test coverage improvement initiative. Goose analyzes the codebase to find untested but important functions and creates focused unit tests for them.
|
||||
|
||||
### Review checklist
|
||||
- [ ] Test is meaningful and actually tests the function
|
||||
- [ ] Test name is descriptive
|
||||
- [ ] Test passes locally
|
||||
- [ ] No unnecessary changes included
|
||||
|
||||
---
|
||||
*Generated by the Daily Test Coverage Finder workflow*
|
||||
branch: goose/test-coverage-${{ github.run_number }}
|
||||
delete-branch: true
|
||||
labels: |
|
||||
goose-generated
|
||||
test
|
||||
automated
|
||||
|
||||
- name: Summary
|
||||
if: always()
|
||||
env:
|
||||
PATCH_CREATED: ${{ steps.find_untested.outputs.patch_created }}
|
||||
FUNCTION_NAME: ${{ steps.find_untested.outputs.function_name }}
|
||||
run: |
|
||||
if [ "$PATCH_CREATED" == "true" ]; then
|
||||
echo "✅ Successfully found untested code and created a test"
|
||||
echo "📝 Function tested: $FUNCTION_NAME"
|
||||
else
|
||||
echo "ℹ️ No suitable untested code found today"
|
||||
fi
|
||||
Reference in New Issue
Block a user