Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -900,8 +900,12 @@ jobs:
python: '3.x'
- os: windows-latest
python: '3.x'
# The oldest Python the package supports (`requires-python`).
- os: ubuntu-latest
# The oldest Python the package supports (`requires-python`), on
# ubuntu-24.04 and not ubuntu-latest (#1094): the Ubuntu 26.04 that
# `ubuntu-latest` now gives out has no 3.9 build for setup-python,
# which lists 3.10 to 3.15 there and 3.8 to 3.15 for 24.04. The
# rows above ask for `3.x`, which 26.04 has, and stay on the latest.
- os: ubuntu-24.04
python: '3.9'
env:
WHEEL: ${{ needs.build.outputs.wheel }}
Expand Down
21 changes: 19 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,16 @@ concurrency:
cancel-in-progress: true

jobs:
# ubuntu-24.04, NOT ubuntu-latest (#1096). The Ubuntu 26.04 that
# `ubuntu-latest` now gives out runs this suite out of disk: #1092's run of
# this job (job 119050702775, image `ubuntu-26.04` version 20261012.163.1)
# ended `2436 failed, 11382 passed, 380 skipped, 5579 errors in 3048.23s`,
# with 28325 lines of `[Errno 122] Disk quota exceeded`, and later `No space
# left on device`, all under pytest's basetemp in /tmp,
# `/tmp/pytest-of-runner/pytest-0`. The same job passed on 24.04. It stays
# on 24.04 until the suite runs on 26.04, which #1096 tracks.
tests:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
# PINNED BY COMMIT, not by tag — the rule this repository spends a
# whole README section on. A tag can be moved and a commit cannot.
Expand Down Expand Up @@ -268,8 +276,17 @@ jobs:
# Python, one file for every system; the release workflow (#563's next
# pull request) installs it on Linux, macOS and Windows before it uploads
# anything.
#
# ubuntu-24.04, NOT ubuntu-latest (#1094). 3.9 is `requires-python`'s
# floor, and the Ubuntu 26.04 that `ubuntu-latest` now gives out has no 3.9
# build for setup-python: its manifest lists 3.10 to 3.15 there, and 3.8 to
# 3.15 for 24.04. A run that landed on a 26.04 runner failed in setup-python
# with `The version '3.9' with architecture 'x64' was not found for Ubuntu
# 26.04.` The `tests` job above is on ubuntu-24.04 too, for a reason of its
# own (#1096), and `tests-git-bash` runs on windows-latest. In release.yml,
# `build` asks for `3.12` on ubuntu-latest, which 26.04 has.
package:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
# The same two commits the other jobs pin.
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
Expand Down
2 changes: 1 addition & 1 deletion tests/test_doctor_legs_members_next.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
ask `quote_arg` for it (`platform="nt"`, from any host) and compare the
string; no test here pastes a line into `powershell`. A Windows-only test
would not change that, because no job runs this file on Windows: `tests.yml`
runs the suite on ubuntu-latest alone (the macOS and Windows jobs were
runs the suite on ubuntu-24.04 alone (the macOS and Windows jobs were
dropped, #597), and its one Windows job, `tests-git-bash`, runs three files
of the launcher's and the installer's suites and no other. A
`skipif(os.name != "nt")` test added here would be skipped by every runner
Expand Down
88 changes: 85 additions & 3 deletions tests/test_release_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,9 +559,14 @@ def test_the_install_check_runs_on_three_systems_and_python_3_9(workflow):
host by the recorded digest."""
install = workflow["jobs"]["install"]
legs = install["strategy"]["matrix"]["include"]
assert {leg["os"] for leg in legs} == {"ubuntu-latest", "macos-latest",
"windows-latest"}
assert {"os": "ubuntu-latest", "python": "3.9"} in legs
assert {leg["os"] for leg in legs} == {"ubuntu-latest", "ubuntu-24.04",
"macos-latest", "windows-latest"}
assert {"os": "ubuntu-24.04", "python": "3.9"} in legs
# #1094: `ubuntu-latest` now gives out Ubuntu 26.04, which has no 3.9
# build for setup-python, so the 3.9 row stays on 24.04 and every row on
# the latest image asks for a Python 26.04 has.
assert [leg["python"] for leg in legs if leg["os"] == "ubuntu-latest"] \
== ["3.x"]
assert install["strategy"]["fail-fast"] is False
assert install["env"]["PIP_INDEX_URL"] == "https://pypi.org/simple/"
for step in install["steps"]:
Expand All @@ -576,6 +581,83 @@ def test_the_install_check_runs_on_three_systems_and_python_3_9(workflow):
"from PyPI")


def test_the_package_job_runs_its_python_3_9_on_ubuntu_24_04():
"""#1094: `tests.yml`'s `package` job builds and installs on 3.9, the
floor of `requires-python`, and the Ubuntu 26.04 that `ubuntu-latest` now
gives out has no 3.9 build for setup-python, so a run that landed there
failed in setup-python. The job names 24.04 and asks for 3.9 once; the
next test holds every job of both workflows on `ubuntu-latest` to what
26.04 has."""
jobs = load_yaml(WORKFLOWS / "tests.yml")["jobs"]
package = jobs["package"]
assert package["runs-on"] == "ubuntu-24.04"
pythons = [step["with"]["python-version"] for step in package["steps"]
if step.get("uses", "").startswith("actions/setup-python@")]
assert pythons == ["3.9"]


def test_the_tests_job_runs_the_suite_on_ubuntu_24_04():
"""#1096: `tests.yml`'s `tests` job runs the whole suite, and on the
Ubuntu 26.04 that `ubuntu-latest` now gives out it ended `2436 failed,
11382 passed, 380 skipped, 5579 errors`, with `[Errno 122] Disk quota
exceeded` under pytest's basetemp in `/tmp` and `No space left on
device` after it. The job is pinned to 24.04, where it passed, until
the suite runs on 26.04; the change that moves it back takes this test
with it."""
jobs = load_yaml(WORKFLOWS / "tests.yml")["jobs"]
assert jobs["tests"]["runs-on"] == "ubuntu-24.04"


def setup_python_pairs():
"""Every (file, job, runner, Python) a setup-python step of `tests.yml`
or `release.yml` asks for, as text. A job with an `include` matrix
gives one pair for each row, with each `${{ matrix.<key> }}` the row
has filled from it; a job with no matrix gives one. A matrix with any
other key, the standard `os: [...]` form, is not expanded here, so it
fails closed. `str()` makes an unquoted `python-version: 3.9`, which
`load_yaml` reads as the float 3.9, the text Actions hands
setup-python."""
for path in (WORKFLOWS / "tests.yml", WORKFLOWS / "release.yml"):
for name, job in load_yaml(path)["jobs"].items():
matrix = job.get("strategy", {}).get("matrix", {})
assert set(matrix) <= {"include"}, (
path.name, name, sorted(matrix))
rows = matrix.get("include")
steps = [step for step in job.get("steps", [])
if step.get("uses", "").startswith(
"actions/setup-python@")]
for step in steps:
for row in rows or [{}]:
runner = str(job["runs-on"])
python = str(step["with"]["python-version"])
for key, value in row.items():
ref = "${{ matrix.%s }}" % key
runner = runner.replace(ref, str(value))
python = python.replace(ref, str(value))
yield path.name, name, runner, python


def test_no_setup_python_on_ubuntu_latest_asks_for_a_python_26_04_lacks():
"""#1094: the Ubuntu 26.04 that `ubuntu-latest` gives out has setup-python
builds for 3.10 to 3.15 alone, so every job of both workflows that is on
`ubuntu-latest` asks for `3.x` or `3.12`, and a 3.9 job is on 24.04. An
allow list over the expanded matrix rows, so it holds for an unquoted
3.9, for `release.yml`'s `build` job, and for a Python or a runner that
an `include` row gives. A matrix of the standard form, with a key of its
own, fails the helper's assertion instead of passing unchecked."""
pairs = list(setup_python_pairs())
for file, job, runner, python in pairs:
where = (file, job, runner, python)
assert "${{" not in runner + python, where
if runner == "ubuntu-latest":
assert python in {"3.x", "3.12"}, where
if python.split(".")[:2] == ["3", "9"]:
assert runner == "ubuntu-24.04", where
# The two 3.9 jobs are among the pairs, so the loop is not vacuous.
assert ("tests.yml", "package", "ubuntu-24.04", "3.9") in pairs
assert ("release.yml", "install", "ubuntu-24.04", "3.9") in pairs


def test_the_header_says_how_to_release(workflow):
"""The release notes (`docs/release-notes/v1.1.0.md` and `v1.1.1.md`)
point at this header for the steps, so it carries them: Brett Heap's
Expand Down
Loading