Skip to content

Add PR-affected-lines coverage gate via shipmonk/coverage-guard#5892

Draft
janedbal wants to merge 1 commit into
phpstan:2.2.xfrom
janedbal:patch-coverage-gate
Draft

Add PR-affected-lines coverage gate via shipmonk/coverage-guard#5892
janedbal wants to merge 1 commit into
phpstan:2.2.xfrom
janedbal:patch-coverage-gate

Conversation

@janedbal

Copy link
Copy Markdown
Contributor

Draft, following up on the suggestion in #5891 (comment) — add a CI gate using shipmonk/coverage-guard that enforces coverage only on the lines a PR changes.

What it does

A new pull_request-only job (.github/workflows/patch-coverage.yml):

  1. Checks out the PR head (pull_request.head.sha), fetch-depth: 0.
  2. Runs the suite with pcov, mirroring the existing paratest coverage step (make infection / the mutation-testing job), but emits clover. paratest merges per-worker coverage, so no separate merge step is needed.
  3. Computes the diff as git diff base.sha...head.sha (three-dot) and runs coverage-guard check coverage/clover.xml --patch changes.patch.

Diff generation (the important bit)

This mirrors GitLab's "merged results" approach used in our private CI, but adapted to GitHub. Rather than relying on GitHub's refs/pull/N/merge merge commit (which only exists when the PR is mergeable and whose line numbers can drift from head), it uses the three-dot base...head diff — exactly what GitHub's "Files changed" tab shows:

  • No merge is performed, so it's independent of whether the PR conflicts with base.
  • The + line numbers are in head's coordinate system, matching the coverage collected on the head checkout — so patch lines and clover lines align.

Preconditions worth noting

  • The default suite runs the analyser in-process (RuleTestCase / TypeInferenceTestCase), so src/ coverage is captured. The only subprocess-spawning tests (exec group) and levels are already excluded in phpunit.xml.
  • beStrictAboutCoverageMetadata=true + failOnRisky=true would break a naive phpunit --coverage-* run (few tests carry #[CoversClass]). The paratest coverage path is already green today (mutation-testing job), which is why this reuses it rather than a plain phpunit run.

Open decisions

  • coverage-guard is installed ad-hoc in the job; if we keep this, move it to require-dev.
  • Thresholds in coverage-guard.php (EnforceCoverageForMethodsRule, 50% / 50% / 5 lines) are placeholders — needs tuning, or a custom rule.
  • Currently blocking. May want continue-on-error for an observation period first.

Co-Authored-By: Claude Code

Draft. Adds a pull_request-only job that runs the test suite with pcov
coverage (mirroring the existing paratest coverage step), computes the
GitHub three-dot diff (base...head) for the PR, and runs
`coverage-guard check --patch` so only lines the PR changed are gated.

Co-Authored-By: Claude Code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
ref: ${{ github.event.pull_request.head.sha }}

- name: "Install PHP"
uses: "shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc" # v2.37.1
ini-file: development
ini-values: memory_limit=-1

- uses: "ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda" # v4.0.0

- uses: "ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda" # v4.0.0

- uses: "ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda" # v4.0.0
Comment on lines +40 to +44
- name: "Checkout"
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: "Compute PR diff"
run: |
git diff \
"${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" \
- name: "Compute PR diff"
run: |
git diff \
"${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" \
"${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" \
> changes.patch
echo "----- changed files -----"
git diff --name-only "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}"
"${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" \
> changes.patch
echo "----- changed files -----"
git diff --name-only "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}"
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.

2 participants