landingi/crap-metric-analyzer
A PHP package for analyzing CRAP metrics, combining cyclomatic complexity and test coverage to identify high-risk, hard-to-maintain code. Helps teams prioritize refactoring and improve coverage where it matters most.
Evidence basis: The only signal available for this assessment is the v1.0.4 release note. The package scope is inferred as a Laravel/PHP tooling package that ingests PHPUnit clover XML coverage reports (parser, coverage-gate, or reporting integration). Architecture and interface specifics below are stated as assumptions to be validated; the risk analysis of the release-note policy itself is not an assumption and holds regardless of package internals.
Architecture fit. The package sits at the tooling boundary, not in the application request path: it consumes a static artifact (--coverage-clover output) produced by PHPUnit and therefore has no runtime coupling to the Laravel app container beyond service-provider registration and config publishing. That is a favourable architectural position — blast radius is CI, not production traffic. Fit is good for teams that already produce clover output as part of their pipeline; poor for teams using only text/HTML coverage or third-party coverage SaaS.
Integration feasibility. Mechanically trivial (Composer install, publish config, invoke in a CI step). The feasibility constraint is not mechanical, it is version-pairing: the package's input format is dictated by the PHPUnit version that generates the report. The maintainer's explicit policy — "we will support always only the newest structure" — makes package version and PHPUnit version a coupled pair. Integration is easy if you are on the newest PHPUnit major; it is blocked or undefined if you are not.
Technical risk.
| Risk | Severity | Notes |
|---|---|---|
| Compatibility cliff (policy, not bug) | High | Dropping older clover schemas is a deliberate, permanent decision. No deprecation window is offered. Teams on older PHPUnit must pin or upgrade. |
| Silent failure on unsupported schema | High | If an older-format report parses to zero coverage rather than raising, CI coverage gates go falsely green or falsely red. This is the single most damaging failure mode and must be verified empirically, not assumed. |
| Semver hygiene | Medium | A patch release (1.0.4) that changes the accepted input format is semantically a breaking change for affected consumers. Treat patch bumps as potentially breaking until proven otherwise. |
| Version lockstep burden | Medium | Every PHPUnit major bump becomes a forced package upgrade, whether or not the app changed. |
| Parser fixture coverage | Medium | Unknown whether the repo carries clover fixtures per supported schema; without them, regressions surface in users' CI rather than upstream. |
Key questions (blocking further assessment).
Stack fit. Conventional Laravel toolchain: Composer dependency, a service provider, a publishable config file, and typically an Artisan command invoked as a CI step. It should be introduced as a test/CI dependency (require-dev semantics) and kept out of the runtime image if the package's only role is report parsing. Confirm it does not need to be in require for the production deploy — if it does, that is a design smell worth raising.
Migration path. Pin producer and consumer together as a pair. Do not upgrade the package independently of PHPUnit:
| PHPUnit (producer) | Clover schema | Package version | Action |
|---|---|---|---|
| Newest supported major | Newest structure | ≥ 1.0.4 | Supported path |
| Older major | Older structure | ≤ 1.0.3 (pin) | Stay pinned, or upgrade PHPUnit first |
| Older major | Older structure | 1.0.4 | Unverified — do not adopt blind |
Compatibility verification (do this before any merge). Run the new version against a real clover artifact from your current pipeline in a throwaway branch, and assert the parsed coverage figure is non-zero and matches the prior version's output within tolerance. A non-zero assertion is the cheapest possible defence against the silent-zero failure mode.
Sequencing.
Rollback. Because the package reads a file and emits a result, rollback is a Composer pin change plus a rerun — low cost, provided step 3's guard exists to make a bad state visible.
Maintenance. In-repo code maintenance is low. The real maintenance load is externalized version tracking: the "newest structure only" policy is a standing commitment to be reactive to PHPUnit format changes, and it converts an upstream test-framework release into a potential forced upgrade for every consumer. That is predictable — which is better than chaotic — but it is recurring, and it lands on whoever owns CI tooling, not on the application team.
Support. Expect inbound issues of the form "coverage shows 0% after upgrading" where the root cause is a producer/consumer version mismatch. The maintainer's cost here is entirely a function of error-message quality: a hard, explicit "unsupported clover schema version, supported: X, found: Y" message is worth more than any documentation. For your team, this means the first-line support burden sits with whoever owns the pipeline, and the diagnostic burden is on you to capture the clover schema version in CI logs.
Scaling. Effectively free. Parsing is linear in report size and runs once per CI job. The only scaling concern is large monorepo clover files — reports for a 10k-test suite can reach hundreds of MB, so watch memory limits and step runtime; if the package loads the whole document, that is a ceiling to note. Multi-repo fleets multiply the version-pairing obligation by the number of repos, which is where the operational cost actually compounds.
Failure modes.
| Failure | Symptom | Detectability | Mitigation |
|---|---|---|---|
| Unsupported clover schema | Zero/absent coverage data | Low unless guarded | Non-zero assertion in CI; capture schema version in logs |
| No report produced (missing driver) | File not found or empty | Medium | Fail on missing/empty artifact |
| Truncated or malformed XML (crashed run) | Parse error | High | Fail the job; do not treat as zero |
| Path mapping drift across PHPUnit versions | Coverage attributed to wrong files | Low | Diff parsed output against prior version during canary |
| Patch-level format change adopted blindly | Surprise breakage | Medium | Treat patch bumps as potentially breaking; read release notes every time |
Ramp-up. Low for developers — one config file and one CI step. The ramp is concentrated in the CI/DevOps owner, who must internalise the one rule that matters: this package's version is bound to your PHPUnit version. Encode that rule in a README line and in the pin itself, and onboarding is complete in an afternoon. Skip the guard in step 3 and the ramp-up cost reappears later as a debugging session about why coverage silently dropped.
Recommendation. Adopt 1.0.4 only after the canary in "Compatibility verification" confirms correct non-zero parsing against a real artifact from your current PHPUnit version, and only with the non-zero/missing-artifact guard in place. If you are not on the newest PHPUnit major, pin to the last version that supported your schema and schedule the PHPUnit upgrade explicitly rather than accepting an implicit one. The policy itself is defensible — narrow support surface, lower maintainer cost — but it transfers upgrade timing risk to consumers, so it must be managed, not merely noted.
How can I help you explore Laravel packages today?