GitHub Actions
Three workflows, from a one-liner to a sharded, cached pipeline, plus a step that fails the build below a mutation score. Pick the one that matches how much you want to optimize.
1. Simplest: checkout and run
Install Gooze and run the whole suite. No registry, no caching — a good starting point.
name: Mutation testing
on: [push, pull_request]
jobs:
gooze:
runs-on: ubuntu-latest
container: golang:1.27 # official Go image: go is already installed
steps:
- uses: actions/checkout@v4
- run: go install gooze.dev/pkg/gooze@latest
- run: gooze run ./...3. Sharded + cached baseline
Add an OCI baseline so each run only re-tests changed files (incremental runs). Every shard pulls the :main baseline for the cache, then hands its reports to the merge job as an artifact — shards never push to the registry. The merge job combines them with gooze report merge and, only on main, publishes the single merged baseline back to :main.
permissions:
contents: read
packages: write # push the merged baseline to GHCR
env:
REPORTS_REF: ghcr.io/${{ github.repository }}/gooze-reports:main
GOOZE_REGISTRY_USERNAME: ${{ github.actor }}
GOOZE_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
jobs:
test:
runs-on: ubuntu-latest
container: golang:1.27
strategy:
matrix:
shard: [0, 1, 2]
steps:
- uses: actions/checkout@v4
- run: go install gooze.dev/pkg/gooze@latest
# Reuse the main baseline so unchanged files are skipped (the cache).
- name: Restore baseline from main
run: gooze report pull "$REPORTS_REF" || echo "no baseline yet"
- name: Run shard ${{ matrix.shard }}
run: gooze run -s ${{ matrix.shard }}/3 ./...
# Hand reports to the merge job via an artifact — no registry push here.
- name: Upload shard reports
uses: actions/upload-artifact@v4
with:
name: gooze-shard-${{ matrix.shard }}
path: .gooze-reports/
merge:
needs: test
runs-on: ubuntu-latest
container: golang:1.27
steps:
- run: go install gooze.dev/pkg/gooze@latest
- name: Collect shard reports
uses: actions/download-artifact@v4
with:
path: .gooze-reports
pattern: gooze-shard-*
merge-multiple: true
- name: Merge shards
run: gooze report merge
# Only main publishes the merged baseline back to the registry.
- name: Publish merged baseline (main only)
if: ${{ github.ref == 'refs/heads/main' }}
run: gooze report push "$REPORTS_REF"Fail the build below a score (quality gate)
Gooze has no threshold flag yet: survivors never change its exit code. Add this step %s. It reads the mutation score from the non-interactive output and fails when it is below MIN_SCORE.
# Fail the job when the mutation score is below MIN_SCORE (percent).
- name: Mutation score gate
env:
MIN_SCORE: "60"
run: |
score=$(gooze report view | sed -n 's/^Mutation score: \([0-9.]*\)%$/\1/p' | tail -1)
echo "Mutation score: ${score}% (minimum ${MIN_SCORE}%)"
awk -v s="$score" -v m="$MIN_SCORE" 'BEGIN { exit !(s != "" && s >= m) }'With sharding, gate only in the merge job: a single shard's score covers only its slice. A missing score (no reports) also fails the step.
Authentication
GOOZE_REGISTRY_USERNAME/GOOZE_REGISTRY_PASSWORD— the password may be a token/PAT (for GHCR useGITHUB_TOKEN).- If unset, Gooze falls back to the Docker credential store, so a prior
docker/login-actionstep also works. - For a non-TLS or self-signed registry add
--plain-httpor--insecureto push/pull.