Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions .github/workflows/patch-coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# https://help.github.com/en/categories/automating-your-workflow-with-github-actions
#
# DRAFT — patch (PR-affected lines only) coverage gate via shipmonk/coverage-guard.
# See https://github.com/shipmonk-rnd/coverage-guard
#
# Only runs on pull_request: it gates the lines the PR changed, so it has no
# meaning on push to a maintained branch.

name: "Patch coverage"

on:
pull_request:
paths-ignore:
- 'compiler/**'
- 'apigen/**'
- 'changelog-generator/**'
- 'issue-bot/**'

concurrency:
group: patch-coverage-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
patch-coverage:
name: "Patch coverage"
runs-on: ubuntu-latest
timeout-minutes: 60

steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit

# fetch-depth: 0 so the merge-base of base..head is present locally.
# ref: head.sha checks out the *real* PR head (NOT the refs/pull/N/merge
# commit) so the line numbers in the coverage report and in the diff
# below refer to the same tree. See the PR description for why this
# sidesteps GitHub's merge-commit/conflict handling entirely.
- name: "Checkout"
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}

Check failure

Code scanning / octoscan

Use of 'actions/checkout' with a custom ref. Error

Use of 'actions/checkout' with a custom ref.

Check warning

Code scanning / zizmor

credential persistence through GitHub Actions artifacts Warning

credential persistence through GitHub Actions artifacts
Comment on lines +40 to +44

- name: "Install PHP"
uses: "shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc" # v2.37.1

Check notice

Code scanning / poutine

Github Action from Unverified Creator used Note

Usage of the following GitHub Actions repositories was detected in workflows
or composite actions, but their owner is not a verified creator.
with:
coverage: "pcov"
php-version: "8.3"
tools: pecl
extensions: ds,mbstring
ini-file: development
ini-values: memory_limit=-1

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

Check notice

Code scanning / poutine

Github Action from Unverified Creator used Note

Usage of the following GitHub Actions repositories was detected in workflows
or composite actions, but their owner is not a verified creator.

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

Check notice

Code scanning / poutine

Github Action from Unverified Creator used Note

Usage of the following GitHub Actions repositories was detected in workflows
or composite actions, but their owner is not a verified creator.
with:
working-directory: "tests/"

# coverage-guard is not yet a dependency; install it ad-hoc for the gate.
# If we decide to keep this, move it into require-dev instead.
- name: "Install coverage-guard"
run: composer require --dev shipmonk/coverage-guard --ignore-platform-reqs

# Mirror the proven-green coverage step from `make infection` /
# the mutation-testing job (paratest + pcov over the whole suite), but
# emit clover so coverage-guard can read it. paratest merges the
# per-worker coverage for us, so no `coverage-guard merge` step is needed.
- name: "Tests with coverage"
run: |
php -d pcov.enabled=1 tests/vendor/bin/paratest \
--runner WrapperRunner \
--passthru-php="'-d' 'pcov.enabled=1'" \
--coverage-clover=coverage/clover.xml

# GitHub's own "Files changed" diff is the three-dot diff between the
# base branch tip and the PR head (git diff base...head == diff from
# merge-base(base, head) to head). It performs NO merge, so it is
# independent of whether the PR conflicts with base. The "+" line
# numbers are in head's coordinate system, matching the coverage report
# collected on the head checkout above.
- name: "Compute PR diff"
run: |
git diff \
"${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" \

Check warning

Code scanning / zizmor

code injection via template expansion Warning

code injection via template expansion

Check warning

Code scanning / zizmor

code injection via template expansion Warning

code injection via template expansion
> changes.patch
echo "----- changed files -----"
git diff --name-only "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}"

Check warning

Code scanning / zizmor

code injection via template expansion Warning

code injection via template expansion

Check warning

Code scanning / zizmor

code injection via template expansion Warning

code injection via template expansion

- name: "Check patch coverage"
run: vendor/bin/coverage-guard check coverage/clover.xml --patch changes.patch

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: patch-coverage
path: |
coverage/clover.xml
changes.patch
26 changes: 26 additions & 0 deletions coverage-guard.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types = 1);

// DRAFT config for shipmonk/coverage-guard — https://github.com/shipmonk-rnd/coverage-guard
//
// Used by .github/workflows/patch-coverage.yml to gate coverage on the lines a
// PR changes. Thresholds below are a starting point, tune to taste.

use ShipMonk\CoverageGuard\Config;
use ShipMonk\CoverageGuard\Rule\EnforceCoverageForMethodsRule;

$config = new Config();

// The coverage report is produced by PHPUnit/paratest on the same runner that
// runs the gate, so the absolute file paths inside clover.xml already live
// under this directory — git root is enough, no path mapping needed.
// (The monorepo needs addCoveragePathMapping() only because PHPUnit there runs
// inside a container at a different WORKDIR than the checkout.)
$config->setGitRoot(__DIR__);

$config->addRule(new EnforceCoverageForMethodsRule(
requiredCoveragePercentage: 50,
minMethodChangePercentage: 50,
minExecutableLines: 5,
));

return $config;
Loading