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
25 changes: 23 additions & 2 deletions .github/scripts/ci_changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@

CPP_SUFFIXES = (".c", ".cc", ".cpp", ".h", ".hpp")

# Keep broad pull-request checks for routing edits, then avoid repeating
# their builds after a CI-only merge into an already released main branch.
CI_ROUTING_PATHS = frozenset(
(
".github/scripts/ci_changes.py",
".github/scripts/test_ci_changes.py",
".github/workflows/changes.yml",
".github/workflows/test.yaml",
)
)


def classify(paths):
selected = set()
Expand Down Expand Up @@ -108,15 +119,25 @@ def detect(event_name, event, ref_name):
base = event["before"]
if not base or set(base) == {"0"}:
return set(GROUPS)
paths = git("diff", "--name-only", "--no-renames", "-z", base, "HEAD").split("\0")
selected = classify(path for path in paths if path)
paths = [
path
for path in git(
"diff", "--name-only", "--no-renames", "-z", base, "HEAD"
).split("\0")
if path
]
selected = classify(paths)
if event_name == "push" and ref_name == "main":
version = tomllib.loads(Path("pyproject.toml").read_text())["project"][
"version"
]
if not git("tag", "--list", f"v{version}"):
# A docs-only fix after failed release CI must not bypass that CI.
return set(GROUPS)
if any(path in CI_ROUTING_PATHS for path in paths) and all(
path in CI_ROUTING_PATHS or path.endswith(".md") for path in paths
):
return {"python_quality"}
return selected


Expand Down
38 changes: 38 additions & 0 deletions .github/scripts/test_ci_changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,44 @@ def test_unreleased_version_forces_full_ci_even_for_docs(self):
):
self.assertEqual(detect("push", {"before": "base"}, "main"), expected)

def test_ci_routing_changes_run_full_pr_ci_but_not_repeat_on_tagged_main(self):
paths = [
".github/scripts/ci_changes.py",
".github/scripts/test_ci_changes.py",
".github/workflows/changes.yml",
".github/workflows/test.yaml",
"MAINTAINING.md",
]
changed = "\0".join(paths) + "\0"
with patch("ci_changes.git", side_effect=["merge-base", changed]):
self.assertEqual(
detect(
"pull_request",
{"pull_request": {"base": {"sha": "base"}}},
"42/merge",
),
set(GROUPS),
)
for changed_paths, tags, expected in (
(paths, "v0.3.3", {"python_quality"}),
(paths, "", set(GROUPS)),
(paths + ["src/simd/dispatch.cpp"], "v0.3.3", set(GROUPS)),
):
with self.subTest(changed_paths=changed_paths, tags=tags):
with (
patch(
"ci_changes.git",
side_effect=["\0".join(changed_paths) + "\0", tags],
),
patch(
"ci_changes.Path.read_text",
return_value='[project]\nversion = "0.3.3"',
),
):
self.assertEqual(
detect("push", {"before": "base"}, "main"), expected
)

def test_release_events_and_new_branches_run_everything(self):
for event, payload, ref in (
("workflow_dispatch", {}, "main"),
Expand Down
9 changes: 6 additions & 3 deletions MAINTAINING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ checks. Pushes compare the complete pushed range; pull requests compare against
their base. Renames and deletions are included. Relevant jobs also run if
change detection fails, so a detection error cannot silently waive a check.

Release tags and manual wheel builds always run the full wheel build. An
untagged version on `main` also forces full C++ and Python CI, even for a
subsequent docs-only commit, before automatic publishing can proceed.
Release tags and manual wheel builds always run the full wheel build. CI
routing edits run the full relevant matrix on pull requests. After an already
released version reaches `main`, a push changing only the routing files and
Markdown reruns Python lint and selector tests without repeating platform
builds. An untagged version on `main` still forces full C++ and Python CI,
even for a subsequent docs-only commit, before automatic publishing can proceed.

## Publishing a release

Expand Down
Loading