diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1e7898bfb..e5a2a415c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,8 +3,9 @@ name: Tests on: push: branches: [main] + # Pull requests into any base branch: a stacked pull request targets + # another pull request's branch and needs the same jobs. pull_request: - branches: [main] # Cancel outdated PR runs; give each main push its own independent group. concurrency: diff --git a/changelog.d/1321-ci-pull-requests-into-any-base.changed.md b/changelog.d/1321-ci-pull-requests-into-any-base.changed.md new file mode 100644 index 000000000..40534bcbc --- /dev/null +++ b/changelog.d/1321-ci-pull-requests-into-any-base.changed.md @@ -0,0 +1 @@ +The Tests workflow (`.github/workflows/test.yml`) now runs for pull requests into any base branch, not only `main` (microcosm#1321). A stacked pull request, whose base is another pull request's branch, previously got no CI at all. Pushes still run it only for `main`, and the jobs, the country selection, the concurrency group and the secrets are unchanged. diff --git a/docs/agent-guide.md b/docs/agent-guide.md index b14084800..b6b043db8 100644 --- a/docs/agent-guide.md +++ b/docs/agent-guide.md @@ -41,7 +41,13 @@ or `uv sync --all-packages --all-extras`. To keep both countries set up, point PR CI (`.github/workflows/test.yml`) has `lint`, `engine-free`, `engine-us`, `engine-uk`, `integration-uk`, and `wheels` jobs, plus the -`select-countries` orchestration job. +`select-countries` orchestration job. It runs for pull requests into any base +branch, so a stacked pull request, whose base is another pull request's +branch, gets the same jobs; pushes run it only for `main`. That costs runner +time: every push to a pull request's branch, whatever its base, runs the full +workflow on the organization's shared runners, with the jobs and country +selection a pull request into `main` would get. Merging one change up a stack +of N pull requests therefore starts N full runs. `tools/ci_test_plan.py` is the only authority for test-directory ownership, CI job assignment, country ownership, US timing-report categories, and changed-path country selection. Its `TEST_GROUPS` registry defines every valid diff --git a/packages/microcosm-build/tests/engine_free/shared/test_ci_integration_job.py b/packages/microcosm-build/tests/engine_free/shared/test_ci_integration_job.py index bcaac635a..70caa2549 100644 --- a/packages/microcosm-build/tests/engine_free/shared/test_ci_integration_job.py +++ b/packages/microcosm-build/tests/engine_free/shared/test_ci_integration_job.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import Any + import yaml from test_support.paths import paths_for @@ -71,6 +73,30 @@ def test_integration_job_is_uk_selected_and_read_only() -> None: assert "run: bash tools/run_integration_tests.sh" in integration +def _workflow_triggers() -> dict[str, Any]: + workflow = yaml.safe_load(_TEST_WORKFLOW.read_text(encoding="utf-8")) + # PyYAML follows YAML 1.1, which reads the bare key ``on`` as boolean true. + return workflow[True] + + +def test_pull_requests_into_any_base_branch_run_the_tests_workflow() -> None: + """A stacked pull request targets another pull request's branch, not main, + and must get the same jobs. + + GitHub matches ``branches`` and ``branches-ignore`` entries as glob + patterns, so checking particular branch names against them proves nothing + about other bases. The trigger must have no base-branch filter at all. + """ + pull_request_trigger = _workflow_triggers()["pull_request"] or {} + + base_branch_filters = {"branches", "branches-ignore"} & pull_request_trigger.keys() + assert sorted(base_branch_filters) == [] + + +def test_only_pushes_to_main_run_the_tests_workflow() -> None: + assert _workflow_triggers()["push"] == {"branches": ["main"]} + + def test_every_workflow_job_caps_its_runtime() -> None: """A hung job must not hold an org-shared runner for GitHub's 6-hour default.""" jobs = yaml.safe_load(_TEST_WORKFLOW.read_text(encoding="utf-8"))["jobs"]