Skip to content

TWO-24998: make Magento version-combination CI coverage honest (classifier + skip surfacing)#237

Open
dgjlindsay wants to merge 3 commits into
stagingfrom
doug/two-24998-honest-version-coverage
Open

TWO-24998: make Magento version-combination CI coverage honest (classifier + skip surfacing)#237
dgjlindsay wants to merge 3 commits into
stagingfrom
doug/two-24998-honest-version-coverage

Conversation

@dgjlindsay

@dgjlindsay dgjlindsay commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Child of TWO-24739. Reference implementation (magento-plugin); magento-abn-plugin adopts the reconciled script in a follow-up PR.

What changed

dev/magento-support-matrix.sh classifies every in-window Magento×PHP combo as run or skip, and the split happens at matrix-assembly time (the discover-magento-matrix job) — not inside a green job.

  • --emit-matrix returns runnable combos only. phpstan/di-compile legs are therefore all real tests: a green leg unambiguously means "tested." A skipped combo is never a test leg, so it can never masquerade as a pass.
  • --emit-skips returns untestable combos with reasons. The discover job renders them to $GITHUB_STEP_SUMMARY as a coverage table and emits one ::warning:: annotation per skipped combo — a not-run combination shows up yellow on the run summary, clearly distinct from a green pass, at a glance.
  • Support window is honest. Current + previous 2 over all published minors — image availability no longer slides the window down. An in-policy minor with no CI image is a surfaced skip, not silently backfilled by an older out-of-policy minor.
  • Missing CI image auto-detected via docker manifest inspect (retry + fail-toward-run so a Docker Hub blip can't zero the matrix). Retired the hand-maintained image-exclusion list — which the probe immediately showed was stale: 2.4.9 images exist for php84/php85, only php83 is missing.
  • Network hardening: retry + JSON-shape validation on the php.net and per-minor composer.json fetches (were single un-retried SPOFs). GitHub token no longer sent to php.net.

Coverage (this run)

Runnable (real green legs): 2.4.9×{8.4,8.5}, 2.4.8×{8.3,8.4}, 2.4.7×{8.2,8.3}. NOT run (warning + table): 2.4.9×8.3 and 2.4.8×8.2 (no CI image), 2.4.7×8.1 (past upstream PHP support). Window moved {2.4.8,2.4.7,2.4.6} → the true current+prev2 {2.4.9,2.4.8,2.4.7}; SUPPORT_WINDOW is the lever for a wider net.

Raised by Claude (pairing with Doug).

…n/skip

magento-support-matrix.sh becomes a CLASSIFIER, not a filter. Every combo in
the support window is emitted tagged status=run|skip (+skip_reason); nothing
testable is silently green, nothing untestable silently vanishes.

- Support window now = current+prev2 over ALL minors. Image availability no
  longer slides the window: an in-policy minor with no CI image surfaces as a
  skip instead of being backfilled by an older out-of-policy minor
  (fixes the "window silently trails a minor behind" defect).
- Missing CI image auto-detected via `docker manifest inspect` (retry +
  fail-toward-run on a registry blip). Retires the hand-maintained
  image-exclusion list — the probe found the list was already stale
  (2.4.9 images DO exist for php84/php85; only php83 is missing).
- Intentional exclusions become reason-only, surfaced as visible skips.
- Retry + shape-validation added to the php.net and composer.json fetches
  (previously single un-retried calls); GH token no longer leaked to php.net.
- phpstan / di-compile gain a Classify first-step; skip legs record the reason
  to $GITHUB_STEP_SUMMARY + a ::warning:: and gate the remaining steps off.
- New coverage-report job renders a durable Magento×PHP status/reason table
  to the run summary (serves the merchant-troubleshooting flow).

Reference implementation; abn adopts the reconciled script in a follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the dev/magento-support-matrix.sh script to transition from a filtering approach to a classification-based model. It introduces a fetch_json helper for robust API interaction and a probe_image function to dynamically verify Docker image availability, effectively removing the need for manual exclusion lists. The output format has been updated to explicitly report the status of each Magento × PHP combination, including skip reasons. The review feedback identifies a potential script termination issue caused by grep in a set -e environment and suggests using native Bash parameter expansion for string manipulation to improve efficiency.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +236 to +238
composer_json=$(fetch_json "magento/magento2@$minor composer.json" \
"https://raw.githubusercontent.com/magento/magento2/$minor/composer.json" \
1 'type == "object"') || exit 2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In the subsequent pipeline (lines 244-247), grep -oE is used to parse the PHP constraints:

    php_minors_for_magento=$(echo "$php_constraint" \
        | grep -oE '~[0-9]+\.[0-9]+\.0' \
        | sed -E 's/~([0-9]+\.[0-9]+)\.0/\1/' \
        | sort -V)

Because set -o pipefail and set -e are active, if grep finds no matches (e.g., if the constraint format changes or is invalid), it will exit with status 1. This will cause the entire pipeline to fail and terminate the script immediately, bypassing the defensive check on line 248.

To prevent this silent termination and allow the diagnostic error message on line 249 to be printed, append || true to the assignment:

    php_minors_for_magento=$(echo "$php_constraint" \
        | grep -oE '~[0-9]+\.[0-9]+\.0' \
        | sed -E 's/~([0-9]+\.[0-9]+)\.0/\1/' \
        | sort -V) || true

Comment thread dev/magento-support-matrix.sh Outdated
# drop any combo flagged on `excluded_combo_map`.
matched=()
for php in $accepted; do
php_image="php$(echo "$php" | tr -d '.')-fpm"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

We can optimize this by using native Bash parameter expansion instead of spawning a subshell with echo and tr. This is cleaner and more efficient.

Suggested change
php_image="php$(echo "$php" | tr -d '.')-fpm"
php_image="php${php//./}-fpm"

dgjlindsay and others added 2 commits July 4, 2026 09:52
…skips

Reworks the earlier approach per review: a skipped combo must never appear as a
green test leg. The run/skip decision now happens entirely in the discover job:

- `--emit-matrix` returns RUNNABLE combos only; phpstan/di-compile legs are all
  real tests, so a green leg unambiguously means "tested". Dropped the per-job
  Classify step + proceed-gates (no longer needed).
- New `--emit-skips` returns the untestable combos with reasons. The discover
  job renders them to $GITHUB_STEP_SUMMARY as a coverage table AND emits one
  ::warning:: annotation per skipped combo — a not-run combination is visible at
  a glance (yellow, on the run summary) and cannot be mistaken for a pass.

GHA still cannot paint a per-matrix-leg job grey, but this sidesteps that
entirely: untestable combos are simply not test legs. Nothing silently green,
nothing silently vanished.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… param expansion

- Append `|| true` to the require.php constraint pipeline: under set -o pipefail
  a no-match grep would terminate the script and bypass the empty-check
  diagnostic below it.
- Replace `$(echo "$php" | tr -d '.')` with bash parameter expansion
  `${php//./}` — no subshell.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dgjlindsay

Copy link
Copy Markdown
Contributor Author

Addressed the Gemini review in 633b844:

  • grep -oE constraint pipeline now ends with || true so a no-match under set -o pipefail can't terminate the script before the empty-check diagnostic.
  • php_image uses ${php//./} parameter expansion (no subshell).

by Claude

@brtkwr brtkwr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed adversarially against the honest-CI direction (no fake-green skips). Aligned and happy with it: untestable combos surface as ::warning:: + a step-summary coverage table rather than passing green, the stale intentionally_excluded / hand-maintained exclusion machinery is fully removed with no dangling references, the upstream fetches have retry + JSON-shape validation, and the token is scoped to github.com hosts only. Approving as the source-of-truth classifier.

A few non-blocking notes for your consideration:

  1. The discover step invokes the script three times (--emit-matrix, --emit-skips, --emit-php-lint-matrix), and each invocation re-runs the full classification (re-fetching the upstream JSON and re-probing every docker manifest). So the run-list and the skip-list come from two independent runs rather than one classification, which means under a transient docker manifest inspect error a combo could land in one output without being the exact mirror of the other, and it triples the anonymous Docker Hub rate-limit exposure. Consider classifying once into a single JSON and slicing run/skip/lint from that.

  2. probe_image fails toward run, so in degraded / rate-limited conditions a genuinely-missing image becomes a real (red) matrix leg rather than the intended yellow skip. Not fake-green, but worth a header note that degraded probes shift skips into red legs by design.

  3. Worth confirming the empty-matrix case (run_count == 0 -> include: [] -> zero jobs) doesn't wedge any required branch-protection checks that expect those job names to report.

None of these block; comfortable with it going in first as the parity source of truth.

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.

2 participants