Skip to content

ci(mutation): run mutation tests only when src/ or test/ changed - #30

Merged
math3usmartins merged 1 commit into
0.3.xfrom
ci/mutation-only-on-code-changes
Jul 27, 2026
Merged

ci(mutation): run mutation tests only when src/ or test/ changed#30
math3usmartins merged 1 commit into
0.3.xfrom
ci/mutation-only-on-code-changes

Conversation

@math3usmartins

Copy link
Copy Markdown
Member

Infection is the slowest CI job (full coverage run + thousands of mutants), and it can only change outcome when the mutated code (src/) or the tests that kill mutants (test/) change. Gate it: a changes job (dorny/paths-filter) detects whether src/ or test/ was touched, and the infection job runs only when it was — so a docs- or config-only PR skips mutation entirely. The needs: phpunit ordering is preserved (mutation still waits for unit tests).

Infection is the slowest CI job (full coverage run + thousands of mutants),
and it can only change outcome when the mutated code (src/) or the tests
that kill mutants (test/) change. Gate it: a `changes` job (dorny/paths-filter)
detects whether src/ or test/ was touched, and the `infection` job runs only
when it was — so a docs- or config-only PR skips mutation entirely. The
`needs: phpunit` ordering is preserved (mutation still waits for unit tests).
@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown

Greptile Summary

This PR gates the expensive infection (mutation testing) job behind a dorny/paths-filter path check, so it only runs when src/ or test/ files are touched. The changes job is added as a new dependency alongside phpunit, and infection uses needs.changes.outputs.code == 'true' to conditionally skip on docs- or config-only commits.

  • New changes job: runs dorny/paths-filter@v3 with contents: read + pull-requests: read permissions, emitting a single code boolean output; for pull_request events this correctly uses the GitHub API (no git history needed).
  • Updated infection job: needs now includes [phpunit, changes] with an if guard; the phpunit ordering and artifact upload are preserved unchanged.

Confidence Score: 4/5

The change is safe to merge — it only modifies CI gating logic, leaves all existing jobs intact, and correctly skips mutation testing for docs/config-only commits on PRs.

The core optimization works correctly for the primary use case (pull_request events). Two minor concerns remain: the new action is pinned to a mutable tag rather than a commit SHA, and the shallow checkout on push-to-main forces dorny/paths-filter to perform extra network fetches to locate the before-commit — neither causes incorrect behavior, just hardening and efficiency gaps.

Files Needing Attention: .github/workflows/ci-core.yml — the changes job's checkout and action-pin configuration.

Security Review

dorny/paths-filter@v3 is referenced by a mutable tag rather than a pinned commit SHA. A compromised or tag-reassigned upstream release would execute attacker-controlled code in the CI runner with repository contents: read and pull-requests: read access. Pinning to a full commit SHA closes this supply-chain window.

Important Files Changed

Filename Overview
.github/workflows/ci-core.yml Adds a changes job using dorny/paths-filter@v3 to gate the expensive infection job on src/ or test/ modifications; works correctly for pull_request events but shallow-clone behavior on push-to-main is worth verifying.

Reviews (1): Last reviewed commit: "ci(mutation): run mutation tests only wh..." | Re-trigger Greptile

Comment thread .github/workflows/ci-core.yml
Comment on lines +29 to +36
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
code:
- 'src/**'
- 'test/**'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Shallow clone may force extra fetches on push-to-main

For pull_request events, dorny/paths-filter uses the GitHub API (no git history needed), so the current setup is perfectly correct there. For push events to main, the action needs to compare against github.event.before, which isn't present in the default fetch-depth: 1 shallow clone. The action recovers by calling git fetch --deepen in a loop until the merge-base is found, but this adds unnecessary network round-trips on every push to main. Adding fetch-depth: 0 to the checkout step (or setting the base input) avoids the extra fetching and makes the behavior explicit.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declining. Accurate that on push to main, dorny deepens the shallow clone to reach github.event.before.

But the suggested fix trades the wrong way:

  • On pull_request: the event that actually gates mutation on feature branches — dorny uses the GitHub API and touches no git history, so the shallow checkout is already optimal (fetch-depth is irrelevant there).
  • On push to main, before is the previous tip, so it's typically 1–2 incremental fetches. That's trivial.
  • fetch-depth: 0 clones the entire history on every run (all PRs and pushes), including the PR runs where dorny doesn't use git at all.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. The trade-off math is clearly against fetch-depth: 0 — paying a full history clone on every PR (where dorny never touches git) just to save 1–2 incremental fetches on push-to-main is the wrong direction. The current shallow checkout is the better default. Thanks for the clear breakdown.

@math3usmartins
math3usmartins merged commit 3988a8a into 0.3.x Jul 27, 2026
8 checks passed
@math3usmartins
math3usmartins deleted the ci/mutation-only-on-code-changes branch July 27, 2026 22:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant