Skip to content

Analyse plugins against their minimum Matomo too, PG-5221 - #49

Closed
snake14 wants to merge 6 commits into
mainfrom
PG-5221-phpstan-min-matomo
Closed

Analyse plugins against their minimum Matomo too, PG-5221#49
snake14 wants to merge 6 commits into
mainfrom
PG-5221-phpstan-min-matomo

Conversation

@snake14

@snake14 snake14 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Description

Stacked on #44 — review that one first; this PR targets its branch, so the diff here is only the addition.

#44 analyses a plugin against maximum_supported_matomo. That never sees a plugin calling a core API which does not exist yet in the oldest Matomo its plugin.json claims to support: the call analyses cleanly against current core, and then fatals for everyone on an older install. This adds the leg that catches it.

  • matomo-targets input, a JSON array of {target, php} objects defaulting to [{"target": "minimum_required_matomo"}, {"target": "maximum_supported_matomo"}]. The job becomes a matrix over it, so a caller can drop back to one target by passing a single-element array. php is optional and falls back to the php-version input; set it per target once a plugin's targets span Matomo majors, because bootstrap-phpstan.php executes core rather than only parsing it and a Matomo 6 checkout cannot be bootstrapped by the PHP 7.2 Matomo 5 still allows. The workflow compares the resolved PHP against the checked-out piwik_minimumPHPVersion and fails with that instruction rather than dying on 8.1 syntax partway through analysis.
  • artifacts/bootstrap-phpstan.php, copied into the Matomo root when the checkout has none.
  • The result cache key now includes the target, since the legs analyse different Matomo trees and both save within one run.

Why the bootstrap copy is needed. Matomo only ships bootstrap-phpstan.php from 5.4.0 (added 2025-03-01, first released in that tag), and plugin phpstan.neon files reference it as bootstrapFiles: ../../bootstrap-phpstan.php. Against an older target PHPStan exits before analysing anything, so without this the minimum leg would fail to start for every plugin whose declared floor predates 5.4.0 — which is most of them; CustomReports declares >=5.0.0-rc5. The file has to be copied into the Matomo root rather than referenced from the action checkout, because it derives PIWIK_DOCUMENT_ROOT from its own location. Its three dependencies (core/bootstrap.php, core/Application/Environment.php, core/Exception/NotYetInstalledException.php) are all present in the 5.0.0-rc5 tag, so the copy works against the oldest target in use.

Expect this to surface real findings. The point is to fail where a plugin has been relying on newer core, so some plugins will go red on the minimum leg when they adopt this. The two valid resolutions are the same as everywhere else: stop using the newer API, or raise require.matomo in plugin.json and note it in the changelog. matomo-targets: '[{"target": "maximum_supported_matomo"}]' unblocks a plugin while that is sorted out.

This is the PHP half of the same problem as #48, which catches the Less and Twig half at test time. Neither covers the other: a PHP call fails only when the code path is reached, so tests can miss it, while plugin .less and .twig compile at runtime and take down every page.

Related: PG-5221, PG-4897.

Checklist

  • [✔] I have understood, reviewed, and tested all AI outputs before use
  • [✔] All AI instructions respect security, IP, and privacy rules

Review

A plugin can call a core API that only exists in a newer Matomo than its
plugin.json declares. Analysing against current core alone never sees it.

Matomo only ships bootstrap-phpstan.php from 5.4.0, so older targets need the
copy in artifacts/ for PHPStan to start at all.
Matomo gained phpstan/phpstan, the composer script and bootstrap-phpstan.php
in one commit released in 5.4.0, so the minimum leg had no analyser to run.
An ignore for a class_exists-guarded call matches on the minimum target but
not the maximum one, where reportUnmatchedIgnoredErrors would then fail the
run. An optional phpstan-min-matomo.neon keeps those ignores off that leg.
The reusable PHPStan workflow passed php-version straight to setup-php, so a
caller could not use the aliases the tests action accepts and had to repeat a
literal version that silently goes stale when a floor moves. Extracting the
table keeps one definition; a copy in each would drift exactly when it matters.
Both matrix legs took the single php-version input, so a plugin whose targets
span Matomo majors would try to bootstrap a Matomo 6 checkout under the PHP 7.2
Matomo 5 allows. bootstrap-phpstan.php executes core, so that dies on 8.1 syntax
partway through analysis; the workflow now checks the resolved PHP against the
checked-out piwik_minimumPHPVersion and says what to change.
@snake14
snake14 requested a review from a team August 13, 2026 02:28
@snake14 snake14 added the Needs Review For pull requests that need a code review. label Aug 13, 2026
@snake14
snake14 requested a review from AltamashShaikh August 13, 2026 23:02
Base automatically changed from PG-4897-shared-phpstan to main August 18, 2026 04:12
@snake14 snake14 removed the Needs Review For pull requests that need a code review. label Aug 20, 2026
@snake14
snake14 removed request for a team and AltamashShaikh August 20, 2026 21:43
@snake14

snake14 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favour of #51

@snake14 snake14 closed this Aug 20, 2026
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