Skip to content

chore(quality): point PHPMD at the central ruleset - #108

Merged
rubenvdlinde merged 1 commit into
developmentfrom
chore/central-phpmd-ruleset
Aug 12, 2026
Merged

chore(quality): point PHPMD at the central ruleset#108
rubenvdlinde merged 1 commit into
developmentfrom
chore/central-phpmd-ruleset

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

What

Step 2a of the Nextcloud CI/CD alignment, following the merged reference
larpingapp#314.

file before after
phpmd.xml local ruleset, 43 rules copied by hand stub → vendor/conduction/hydra-gates/quality-config/phpmd.xml + this app's one live deviation
phpmd-unusedparams.xml local copy deleted; the second leg points at the central copy

What is preserved, and what is deliberately dropped

Preserved — ExcessiveClassLength at 1050. A real, reasoned relaxation, so
it is re-declared verbatim with its comment via <exclude> + re-declaration.

Dropped — DevelopmentCodeFragment with ignore-namespaces=false. That rule
was dead, and this PR brings it to life.
PDepend resolves an unqualified call
inside a namespaced file to the current-namespace-qualified image, so
var_dump($x) in namespace OCA\Launchpad\Service; reaches the rule as
OCA\Launchpad\Service\var_dump and never matches unwanted-functions. All of
this app's production PHP is namespaced, so with the default false the rule
matched nothing anywhere — see ConductionNL/openregister#2286. The central
ruleset sets ignore-namespaces=true, which is the working configuration, so
the local declaration is simply not carried over.

Measured consequence: none today. With the rule now genuinely active,
composer phpmd output is byte-identical — there is no var_dump / print_r /
debug_zval_dump / debug_print_backtrace in lib/ for it to find. The change
is that from now on there cannot be one. (Hydra gate 2, forbidden-patterns, is
the broader independent guard and stays as it is.)

A second, quieter difference: the unused-params exclude-pattern

The local ruleset excluded */Migration/*; the central one excludes
*/lib/Migration/*. PDepend compiles these into unanchored regexes, so the
broad form also swallows any lib/*/Migration/ directory — lib/Service/Migration/,
lib/Command/Migration/ — where signatures are not interface-mandated.

Checked rather than assumed: find lib -path '*/Migration/*' -name '*.php'
resolves to lib/Migration and nothing else in this app, so the two patterns
select the same files here. Both forms produce 0 findings. The narrower central
pattern is strictly safer going forward.

--baseline-file becomes explicit on the second leg

PHPMD only honours a baseline you name. Otherwise
Baseline\BaselineFileFinder::find() looks for phpmd.baseline.xml in the
directory of the first ruleset argument
:

$baselinePath = dirname(realpath($ruleSets[0])) . '/phpmd.baseline.xml';

While phpmd-unusedparams.xml sat at the app root, the second leg was
auto-discovering ./phpmd.baseline.xml (106 violations, 1 of them
UnusedFormalParameter) without ever naming it. Pointed into vendor/, it
would find no baseline at all. The flag is now passed explicitly.

The first leg still relies on auto-discovery, and that is fine: phpmd.xml
stays at the app root, so the finder still lands on ./phpmd.baseline.xml. It
is left as-is to keep this diff to the lines the migration actually requires.

Verification

1. The effective rule set, before and after

Dumped rule by rule through PHPMD's own RuleSetFactory (class, rule name,
priority, since, and every resolved property):

before   43 rules   ignore-patterns: ['*/Migration/*']
after    43 rules   ignore-patterns: ['*/lib/Migration/*']

Exactly two rules differ, and both are the intended changes above:

DevelopmentCodeFragment   ignore-namespaces: false  ->  true
ExcessiveClassLength      minimum: 1050             ->  1050   (unchanged, re-declared)

The count staying at 43 is the check on the <exclude> + re-declare pattern: if
the exclude had been ignored, ExcessiveClassLength would appear twice at 1050
and 1000, and the stricter one would win.

composer phpmd output is byte-identical before and after (0 findings, exit 0).

2. Positive control — the second leg is alive

A scratch copy of lib/ was given three probe classes and the post-change
script re-run:

probe expectation result
lib/ProbeControl/ProbeMainLeg.php — an else branch leg 1 must report it reported
lib/ProbeControl/ProbeUnusedParam.php — an unused parameter leg 2 must report it reported
lib/Migration/ProbeMigrationUnusedParam.php — same violation leg 2 must not report it not reported

Exit code 2, i.e. the run can still fail with the baseline in place. The probes
exist only in the scratch copy; nothing in this diff.

Deliberately not in this PR

  • The ExcessiveClassLength debt — preserved at 1050, comment intact.
  • The 106 baselined violations — untouched.
  • PHPStan and stylelint — separate steps (2b, 2d) of the same plan.
  • Existing gate findings. Gates now scan the whole tree (ADR-020 superseded,
    .github@main 4c37371d), so development already carries this app's whole
    backlog. This PR adds nothing to it; phpmd itself stays green.
  • Quality Report is an aggregator and never an independent defect.

phpmd.xml becomes a stub referencing
vendor/conduction/hydra-gates/quality-config/phpmd.xml, and the local
phpmd-unusedparams.xml is deleted in favour of the central copy.

ExcessiveClassLength 1050 is preserved via <exclude> plus a re-declaration.
DevelopmentCodeFragment with ignore-namespaces=false is NOT carried over: with
that setting PDepend namespace-qualifies every unqualified call, so the rule
matched nothing in this fully namespaced codebase. The central true takes over
and the rule becomes live at no cost - phpmd output is byte-identical.

The second leg also gains an explicit --baseline-file, because PHPMD
auto-discovers phpmd.baseline.xml next to the FIRST ruleset argument and the
ruleset has moved into vendor/.
@rubenvdlinde
rubenvdlinde merged commit 5b62c9f into development Aug 12, 2026
32 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/launchpad @ 56c53d8

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
composer ✅ 104/104
npm ✅ 548/548
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-12 22:22 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde deleted the chore/central-phpmd-ruleset branch August 12, 2026 23:36
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.

1 participant