diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 2b926a2..335fae8 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -3,6 +3,12 @@ name: Mutation Testing on: push: branches: [master] + paths: + - "**/*.go" + - "**/testdata/**" + - go.mod + - go.sum + - .github/workflows/mutation.yml pull_request: branches: [master] @@ -15,6 +21,9 @@ jobs: timeout-minutes: 60 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + # --git-diff-lines needs the base branch and merge-base history. + fetch-depth: 0 - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: go.mod @@ -28,13 +37,27 @@ jobs: # cmd/ - integration tests re-invoke the binary (would recurse) # internal/importing - resolution behaviour depends on GOPATH layout; excluded from mutation targets # internal/parser - excluded from mutation targets (type-checker setup is test-infrastructure, not user logic) + # Pull requests mutate only lines in the PR. Pushes to master retain the full-tree + # gate so a faulty diff filter cannot hide a regression permanently. # --coverage generates a profile before mutation to compute covered-code MSI # and marks mutants in untested code as "not covered" rather than running them. # --min-msi and --min-covered-msi enforce quality gates. + env: + EVENT_NAME: ${{ github.event_name }} run: | + scope_args=() + if [[ "$EVENT_NAME" == "pull_request" ]]; then + scope_args=( + --git-diff-lines + --git-diff-base origin/master + --ignore-msi-with-no-mutations + ) + fi + go-mutesting \ --exec-timeout 30 \ --coverage \ + "${scope_args[@]}" \ --min-msi 75 \ --min-covered-msi 80 \ github.com/jonbaldie/go-mutesting/v2/mutator/arithmetic \ diff --git a/CHANGELOG.md b/CHANGELOG.md index 58ab46c..11e875b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). This project uses [Semantic Versioning](https://semver.org/). +## [Unreleased] + +### Changed +- Mutation CI now tests only lines changed by a pull request, while retaining the full-tree gate for code-related pushes to `master`. Pull requests with no mutable changes pass without running mutants. + +--- + ## [v2.7.8] — 2026-07-13 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index a7c9034..ff3f13b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -71,9 +71,10 @@ git config core.hooksPath githooks `pre-commit` runs the fast, whole-tree, deterministic checks (gofmt, go vet, gocyclo, ineffassign, messgo, build, unit tests) and hard-fails on any finding or missing tool. -`pre-push` runs mutation testing scoped to the diff against `origin/master` via -`--git-diff-lines`. Vulnerability scanning (`security.yml`) depends on external advisory -feeds and stays CI-only; it is not mirrored locally. +`pre-push` mirrors the pull-request mutation gate, scoped to the diff against +`origin/master` via `--git-diff-lines`. CI retains a full-tree mutation gate for +code-related pushes to `master`. Vulnerability scanning (`security.yml`) depends on external +advisory feeds and stays CI-only; it is not mirrored locally. ## Shipping workflow diff --git a/docs/ci.md b/docs/ci.md index c5af65c..be80cc1 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -61,6 +61,11 @@ Once you've written tests to kill the known survivors, remove them from the base Limit mutation to lines changed in the PR to keep feedback fast and relevant: ```yaml +- uses: actions/checkout@v6 + with: + # Required so go-mutesting can resolve the base branch and merge-base. + fetch-depth: 0 + - run: | /tmp/go-mutesting \ --git-diff-lines \ diff --git a/githooks/pre-push b/githooks/pre-push index 315fd80..1d8548b 100755 --- a/githooks/pre-push +++ b/githooks/pre-push @@ -1,8 +1,8 @@ #!/bin/sh -# Local mirror of .github/workflows/mutation.yml, scoped to the diff against -# origin/master instead of the whole tree (mutation testing is slow; running it -# whole-tree on every push is not viable locally). Hard-fails on escaped -# mutants, on a gate miss, and on any missing tool - no silent skips. +# Local mirror of .github/workflows/mutation.yml's pull-request mode, scoped to +# the diff against origin/master. CI retains a full-tree gate for code pushes to +# master. Hard-fails on escaped mutants, on a gate miss, and on any missing tool - +# no silent skips. # # Not opt-out by default. To enable this hook, run once: # git config core.hooksPath githooks @@ -72,8 +72,8 @@ if ! go build -o "$GO_MUTESTING_BIN" ./cmd/go-mutesting; then fi echo "pre-push: running mutation testing scoped to the diff against origin/master..." -# Same package list, timeout, and quality gates as .github/workflows/mutation.yml -# and CLAUDE.md, restricted to changed lines via --git-diff-lines/--git-diff-base. +# Same package list, timeout, quality gates, and changed-line scope as the +# pull-request mode in .github/workflows/mutation.yml and CLAUDE.md. # --ignore-msi-with-no-mutations avoids failing pushes that don't touch these # packages at all. STATUS=0