diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6bf787c4..597153d4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -102,7 +102,13 @@ jobs: # and returns every version's verdict on the first run. fail-fast: false matrix: - python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] + # A pull request runs the 3.10 floor the locks resolve for, the 3.12 + # coverage leg and the newest interpreter; the push to main runs every + # version, so main still carries the full verdict. Measured over + # 2026-10-11..25, 11 runs averaged 13 billed minutes, 4 of them on 3.11 + # and 3.13, and none of the 10 failed Tests runs since 2026-06 failed on + # 3.11 or 3.13 without the outer legs failing too. + python-version: ${{ github.event_name == 'pull_request' && fromJSON('["3.10", "3.12", "3.14"]') || fromJSON('["3.10", "3.11", "3.12", "3.13", "3.14"]') }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/tests/test_ci_artifact_contract.py b/tests/test_ci_artifact_contract.py index 9178bf64..4dde808f 100644 --- a/tests/test_ci_artifact_contract.py +++ b/tests/test_ci_artifact_contract.py @@ -11,6 +11,7 @@ from __future__ import annotations +import json import re from pathlib import Path from typing import Any @@ -123,10 +124,24 @@ class TestCompatibilityMatrix: """Independent legs run at once, and exactly one of them owns coverage.""" def test_matrix_runs_every_supported_version_concurrently(self) -> None: - """Serialized legs cost the sum of their wall time and hide later failures.""" - strategy = _load_workflow(_TESTS_WORKFLOW)["jobs"]["test"]["strategy"] + """Serialized legs cost the sum of their wall time and hide later failures. - assert strategy["matrix"]["python-version"] == _SUPPORTED_PYTHON_VERSIONS + The push to main runs every supported version. A pull request runs a + subset, which must still hold the floor, the coverage leg and the + newest interpreter, so a dropped leg is one main still tests. + """ + strategy = _load_workflow(_TESTS_WORKFLOW)["jobs"]["test"]["strategy"] + selector = re.fullmatch( + r"\$\{\{ github\.event_name == 'pull_request' && fromJSON\('(\[[^']*\])'\)" + r" \|\| fromJSON\('(\[[^']*\])'\) \}\}", + strategy["matrix"]["python-version"], + ) + + assert selector is not None + pull_request, push = (json.loads(group) for group in selector.groups()) + assert push == _SUPPORTED_PYTHON_VERSIONS + assert {_SUPPORTED_PYTHON_VERSIONS[0], _COVERAGE_VERSION, _SUPPORTED_PYTHON_VERSIONS[-1]} <= set(pull_request) + assert set(pull_request) <= set(push) assert strategy["fail-fast"] is False assert "max-parallel" not in strategy