d0x2f/clover-merge
d0x2f/clover-merge merges multiple Clover XML coverage reports into one consolidated file. Designed for Laravel/PHP projects, it helps aggregate coverage from parallel test runs and CI jobs so results can be passed cleanly to dashboards and reporting tools.
--enforce/-e <pct> flag nominally lets the merger be the gate, but the enforcement logic is roughly three lines of arithmetic over the merged totals — do not make an unmaintained binary the system of record for pass/fail. Use -e as a local convenience, and keep the authoritative gate in your own CI script or in the coverage consumer you already pay for.phpcov merge inside phpunit/php-code-coverage, and as a native feature of most coverage vendors. It should never appear as a line item in a SaaS negotiation. The new threshold flag does not change this — a merge plus a covered/total comparison is not a product.Consider it when all of the following hold:
phpunit/php-code-coverage toolchain just for phpcov merge.--enforce, you have validated its semantics against your own numbers: which metric the threshold applies to (line vs. method vs. per-file), how rounding works, and what the exit code does under partial/empty input. A gate that silently no-ops or misfires is worse than no gate.Look elsewhere — or write the 40 lines yourself — when:
sonar.php.coverage.reportPaths takes a comma-separated list) or merges server-side (Codecov, Coveralls). Prefer configuring the tool you already pay for.path roots across CI runners, method-level counters). An unmaintained merger with no test suite you trust is a silent-data-corruption risk in exactly the metric people argue about — and now that it can fail a build, a bug in it is a blocked PR, not just a wrong number.if statement.Default recommendation: treat it as a reference implementation. Vendor or fork it, pin it, and add a fixture-based test that asserts merged totals equal the sum of inputs — and, if you use -e, that the threshold outcome matches the expected exit code at boundary values. That converts a stale 9-star dependency into an owned 100-line utility with no supply-chain surface. Pin to an exact version and do not float across major/minor updates automatically: this is now code that can turn your pipeline red.
For executives (one paragraph): We can cut CI time roughly in proportion to how much we parallelize the PHP test suite, but today that either slows the pipeline or blinds us to total coverage. A small MIT-licensed utility — about a hundred lines, no runtime dependencies, no licence cost — recombines the per-job coverage reports into the single number we already report upward, so parallelizing tests doesn't quietly weaken our quality gate. Its newest version can also fail the build when merged coverage drops below a threshold, which is convenient but not a reason to depend on it: it is a single-maintainer project that went roughly seven years without a release before this one. Zero budget impact, low technical risk, and it removes the main objection to the CI-speed work.
For engineering (short version): Use it as a one-step CLI in the coverage stage (clover-merge a.xml b.xml -o coverage.xml) when you have sharded jobs or split suites. v1.0.5 adds --enforce/-e <pct>, which exits non-zero below the threshold — useful locally, but keep the authoritative gate in our own script so a bug in a pinned third-party binary can't block PRs on its own terms. Do not take a runtime dependency on the upstream repo: one release after a long dormancy, zero dependents, and we still can't verify PHP 8 behaviour or XXE hardening in its XML parsing. Fork it into tools/ under our own CI, pin the version, add tests asserting merged totals equal the sum of inputs plus threshold boundary cases, and disable external entity loading in the parser. If phpcov merge from phpunit/php-code-coverage is already in our lockfile, prefer that and skip this entirely. Either way, first check whether Sonar/Codecov can take the multiple paths directly — if they can, this whole card closes as "no action."
How can I help you explore Laravel packages today?