fix(phpmd): scope the lib/Migration UnusedFormalParameter exclusion to its own ruleset - #279
Merged
Merged
Conversation
…o its own ruleset The nested <exclude-pattern> inside the UnusedFormalParameter <rule> was inert: PHPMD 2.15 honours exclude-patterns only as direct children of <ruleset>, so lib/Migration was scanned by the very rule the pattern was written to spare. Hoisting the pattern to the top level of phpmd.xml would have worked but is applied at file-collection time, dropping lib/Migration from EVERY rule and silently swallowing real complexity, StaticAccess and method-length findings. UnusedFormalParameter now lives alone in phpmd-unusedparams.xml with a top-level */Migration/* exclude, and the phpmd composer script runs both legs keeping the worst exit code.
Contributor
Quality Report — ConductionNL/scholiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 750/750 | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-05 15:22 UTC
Download the full PDF report from the workflow artifacts.
Contributor
Quality Report — ConductionNL/scholiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 750/750 | |||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-05 20:06 UTC
Download the full PDF report from the workflow artifacts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of the fleet PHPMD ruleset fix (ConductionNL/.github#155). Propagates the shape
already merged in
nextcloud-app-template#125,doriath#157,larpingapp#263 andplanix#315.The defect
phpmd.xmldeclared:A nested
<exclude-pattern>is inert. PHPMD 2.15 reads exclude-patterns inRuleSetFactory::getIgnorePattern(), which walks$xml->children()— only elementsdirectly under
<ruleset>. A nested one parses without error and is discarded, solib/Migrationwas scanned by the very rule the pattern was written to spare.Reproduced directly on this repo's ruleset: a probe class in
lib/Migrationwith threeunused formal parameters was reported, exit 2, with the nested pattern in place.
Why not simply hoist the pattern
A top-level
<exclude-pattern>is applied by PDepend'sExcludePathFilteratfile-collection time, so it drops the file from every rule in the ruleset — real
complexity,
StaticAccessand method-length findings in migrations would silently vanish.The shape shipped here
phpmd.xmlno longer declaresUnusedFormalParameter; a comment records why.phpmd-unusedparams.xmlholds that rule alone, with a top-level*/Migration/*exclude — so the exclusion is scoped to that one rule and nothing else.phpmdcomposer script runs both legs, keeping the worst exit code so neitherleg can short-circuit the other.
Why
lib/Migrationis exempt from this one rule:OCP\Migration\IMigrationStepmandateschangeSchema(IOutput $output, Closure $schemaClosure, array $options)andpreSchemaChange/postSchemaChangewith the same three parameters. A step that needs noneof them still cannot drop them — the signature is not ours to change.
Measurement
PHPMD 2.15.0 (the version this repo's lockfile pins) on PHP 8.4.22, run in a
nextcloud:latestcontainer: host PHP 8.2 makesvendor/bin/phpmddie inplatform_check.phpwith exit 255, which reads exactly like a clean run. Exit codesare read directly, never through a pipe. Findings are compared as normalised
path:line:ruletriples — PHPMD right-pads thefile:linecolumn in text output, so rawline diffs are meaningless.
@SuppressWarningsstripped on a throwaway copy), beforeThe true count strips every
@SuppressWarningsinlib/on a throwaway copy that isnever committed, so the comparison isolates the ruleset change from the suppressions.
Retired: 0
Newly appearing (true): 0 — must be 0, and is.
Newly appearing (reported): 0. Retired (reported): 0.
Zero newly-hidden findings: every triple present before is present after, except the
retired
UnusedFormalParameterhits insidelib/Migrationlisted above.lib/Migrationin this repo: 0 PHP file(s).Dead-gate proof
A new leg that exits 0 on the shipped tree is indistinguishable from a leg that does not
run. Proven otherwise on a throwaway copy (probes removed before committing) — three
probes, run through the shipped two-leg invocation:
lib/Migration/ZzProbeMigration.phpUnusedFormalParameterlib/Migration/ZzProbeMigration.phpElseExpressionlib/ZzProbe/ZzProbe.phpUnusedFormalParameterLeg 2 goes from exit 0 to exit 2 under the probe, so it is live. The Migration
ElseExpressionprobe is still reported, so isolating the rule did not blind theother rules to
lib/Migration— which is exactly what a hoisted top-level pattern wouldhave done.
The rig itself was positive-controlled before the first measurement: the same probes under
the unfixed ruleset were reported with exit 2, including the three
UnusedFormalParameterhits in
lib/Migrationthat the nested pattern was supposed to suppress.Baseline
phpmd.baseline.xmlpresent: no. None was added, deleted or shrunk.PHPMD auto-discovers
phpmd.baseline.xmlfrom the working directory, so removing the--baseline-fileflag would be a no-op — the baseline stays active either way. Verifiedempirically on this fleet: identical command, baseline file present → 0 findings / exit 0;
same command with the file absent → 93 findings / exit 2.
Suppressions
0 deleted. This repo has no
lib/Migrationdirectory at all, so it carried no@SuppressWarnings(PHPMD.UnusedFormalParameter)tags for this fix to make redundant.This fix therefore retires nothing in this repo. Its value is the corrected shape — the old nested pattern was inert either way, and the new leg is proven live below, so the coverage is real the day a migration is added.
This repo still carries 2
UnusedFormalParameterand 3 other suppressions elsewhere inlib/; those are outside this PR's scope and untouched.No
@SuppressWarningswas added. No threshold was changed, no rule weakened, no baselineentry added, nothing skipped.
Tests
phpunit -c phpunit-unit.xml:(The default
phpunit.xmlsuite needs a live Nextcloud runtime and errors out in a barecheckout — a pre-existing condition this change does not touch.)
What this PR does NOT do
@SuppressWarnings, a threshold change or a waiverUnusedFormalParameter