From af6936055bc8438304e9298e596eac5eeafd2dad Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 6 Nov 2026 14:51:00 +0100 Subject: [PATCH] docs: quote the pip lines CI pins for PR checks --- .github/workflows/deploy-site.yml | 2 ++ CONTRIBUTING.md | 8 +++++- scripts/generate_readme.py | 23 +++++++++++++++- tests/test_contributing_text.py | 45 ++++++++++++++++++++++++++++++- wiki/testing-guide.md | 4 ++- 5 files changed, 78 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/deploy-site.yml index 67130fe8f..4ea290a9b 100644 --- a/.github/workflows/deploy-site.yml +++ b/.github/workflows/deploy-site.yml @@ -89,6 +89,8 @@ on: # generated folders are gitignored and never trigger anything. - "website/**" - ".github/workflows/deploy-site.yml" + # The contributing guide quotes the pip lines of its test job. + - ".github/workflows/validate.yml" workflow_dispatch: permissions: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3073b4eb2..f7b2d05f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -72,7 +72,7 @@ validation above is its check. For code, profiles or platform files, these are the checks CI runs on a pull request (Python 3.12 or newer): ```bash -pip install pyyaml "jsonschema[format-nongpl]" markdown pyte hypothesis vermin setuptools +pip install pyyaml "jsonschema[format-nongpl]==4.26.0" "markdown==3.10.2" "pyte==0.8.2" "hypothesis==6.170.8" "vermin==1.9.2" "setuptools==80.9.0" python scripts/validate_pr.py --changed # the BIOS files the branch adds python scripts/validate_schemas.py --source-only # profiles and platform files python scripts/profile_sync.py --added --strict # each profile the branch adds @@ -83,8 +83,14 @@ npm ci --prefix website && npm run build --prefix website # the built site, Nod python -m unittest discover -s tests -t . python scripts/validate_site.py --site-dir website/dist # links and page budgets vermin --no-tips -t=3.8- --violations install.py # install.py stays on Python 3.8 +python3.8 -m unittest tests.test_install_tui # the full screen on the installer's floor ``` +The versions are the ones CI pins. Three tools come from the system, not from +that line, and the tests that need them skip without them: `shellcheck` for the +handheld launchers, `bwrap` (bubblewrap) for the probe sandbox, and a Python 3.8 +with pyte (`python3.8 -m pip install "pyte==0.8.2"`) for the full screen. CI has all three. + `profile_sync.py` compares the branch with this repository's `main`, and fetches it in a fork's clone. A profile you only edit is not held to `--strict`: its older refs are reviewed by hand. diff --git a/scripts/generate_readme.py b/scripts/generate_readme.py index 462b3d093..51588abb4 100644 --- a/scripts/generate_readme.py +++ b/scripts/generate_readme.py @@ -13,6 +13,7 @@ from __future__ import annotations import argparse import json import os +import re import sys from collections.abc import Callable from datetime import datetime, timezone @@ -915,6 +916,19 @@ def generate_readme(db: dict, platforms_dir: str, db_path: str = "database.json" return "\n".join(lines) + "\n" +def ci_install_lines() -> tuple[str, str]: + """The pip lines the test job of validate.yml runs, verbatim. + + The guide listed the packages without their versions, so a local run + could pass on releases CI never installs. Read from the workflow, the + two cannot disagree. The second line is the Python 3.8 one. + """ + text = (_REPO / ".github" / "workflows" / "validate.yml").read_text(encoding="utf-8") + main = re.search(r'^\s*run: (pip install pyyaml "jsonschema.*markdown.*)$', text, re.M) + floor = re.search(r"^\s*run: (python3\.8 -m pip install .*)$", text, re.M) + return main.group(1), floor.group(1) + + def contributing_text( link: Callable[[str], str], title: str, site_words: str ) -> str: @@ -924,6 +938,7 @@ def contributing_text( site. *link* renders a site page (absolute URL for the README, relative .md for the site); *site_words* names the site from where the text is read. """ + pip_line, floor_line = ci_install_lines() return f"""{title} ## Add a BIOS file @@ -998,7 +1013,7 @@ validation above is its check. For code, profiles or platform files, these are the checks CI runs on a pull request (Python 3.12 or newer): ```bash -pip install pyyaml "jsonschema[format-nongpl]" markdown pyte hypothesis vermin setuptools +{pip_line} python scripts/validate_pr.py --changed # the BIOS files the branch adds python scripts/validate_schemas.py --source-only # profiles and platform files python scripts/profile_sync.py --added --strict # each profile the branch adds @@ -1009,8 +1024,14 @@ npm ci --prefix website && npm run build --prefix website # the built site, Nod python -m unittest discover -s tests -t . python scripts/validate_site.py --site-dir website/dist # links and page budgets vermin --no-tips -t=3.8- --violations install.py # install.py stays on Python 3.8 +python3.8 -m unittest tests.test_install_tui # the full screen on the installer's floor ``` +The versions are the ones CI pins. Three tools come from the system, not from +that line, and the tests that need them skip without them: `shellcheck` for the +handheld launchers, `bwrap` (bubblewrap) for the probe sandbox, and a Python 3.8 +with pyte (`{floor_line}`) for the full screen. CI has all three. + `profile_sync.py` compares the branch with this repository's `main`, and fetches it in a fork's clone. A profile you only edit is not held to `--strict`: its older refs are reviewed by hand. diff --git a/tests/test_contributing_text.py b/tests/test_contributing_text.py index 593ad04fa..579f8a617 100644 --- a/tests/test_contributing_text.py +++ b/tests/test_contributing_text.py @@ -114,11 +114,41 @@ class BeforeOpeningAPullRequest(unittest.TestCase): line naming the old theme installed packages nothing reads.""" text = generate_readme.generate_contributing() section = text.split("## Before opening a PR", 1)[1].split("\n## ", 1)[0] - self.assertIn('pip install pyyaml "jsonschema[format-nongpl]" markdown', section) + self.assertIn('pip install pyyaml "jsonschema[format-nongpl]==', section) self.assertNotIn("mkdocs", section) self.assertTrue((REPO_ROOT / "website" / "package-lock.json").is_file()) +class TheChecklistInstallsWhatCiInstalls(unittest.TestCase): + """The pip line named the packages without versions, and nothing said + that shellcheck, bubblewrap and a Python 3.8 with pyte come from the + system: their tests skipped locally and failed first in CI.""" + + def test_the_pip_lines_are_the_workflow_lines(self): + workflow = (REPO_ROOT / ".github" / "workflows" / "validate.yml").read_text(encoding="utf-8") + text = generate_readme.generate_contributing() + section = text.split("## Before opening a PR", 1)[1].split("\n## ", 1)[0] + pinned = [line.split("run: ", 1)[1] for line in workflow.splitlines() + if re.match(r"\s*run: (python3\.8 -m )?pip install .*==", line) + and "pyte" in line] + self.assertEqual(len(pinned), 2) + for line in pinned: + with self.subTest(line=line): + self.assertIn(line, section) + + def test_it_names_the_system_tools_ci_installs(self): + workflow = (REPO_ROOT / ".github" / "workflows" / "validate.yml").read_text(encoding="utf-8") + text = generate_readme.generate_contributing() + section = text.split("## Before opening a PR", 1)[1].split("\n## ", 1)[0] + for tool, step in (("shellcheck", "shellcheck --version"), + ("bwrap", "bwrap --ro-bind"), + ("python3.8 -m unittest tests.test_install_tui", + "python3.8 -m unittest tests.test_install_tui")): + with self.subTest(tool=tool): + self.assertIn(step, workflow) + self.assertIn(tool, section) + + class OneFileThroughTheBrowser(unittest.TestCase): """Adding one BIOS asked for a fork, a 5.5 GB clone, five pip packages, the data directories and the whole suite, and promised a PR comment that @@ -174,3 +204,16 @@ class OneFileThroughTheBrowser(unittest.TestCase): if __name__ == "__main__": unittest.main() + + +class TheGuideRebuildsWhenItsPinsMove(unittest.TestCase): + """The checklist quotes validate.yml, so a pin bump there must redeploy + the guide and meet the README/CONTRIBUTING freshness check.""" + + def test_deploy_site_watches_the_validation_workflow(self): + import yaml + + deploy = yaml.safe_load( + (REPO_ROOT / ".github" / "workflows" / "deploy-site.yml").read_text(encoding="utf-8")) + paths = deploy[True]["push"]["paths"] + self.assertIn(".github/workflows/validate.yml", paths) diff --git a/wiki/testing-guide.md b/wiki/testing-guide.md index 351ab614d..a9f94702d 100644 --- a/wiki/testing-guide.md +++ b/wiki/testing-guide.md @@ -42,7 +42,9 @@ tests are reported as skipped, so install them before a pull request full-screen tests drive `install.py --tui` on a pseudo-terminal and read the screen back with `pyte`, and fuzz the key decoder with `hypothesis`: both skip without them (`pip install pyte hypothesis`). `pip install -e ".[dev]"` from the -checkout installs all of these at once, from the `dev` extra of `pyproject.toml`. +checkout installs all of these at once, from the `dev` extra of `pyproject.toml`, +which sets lower bounds only. The contributing guide's checklist reads the exact +versions CI pins from `validate.yml`. No test framework beyond the standard library `unittest` module. ## Modules at a glance