Files
horizon-airdef/tools/ci/rust_changes.py
T
Ludovic Marie dbbe3a45d9 CI: check the launcher's workspace on every push to main and on pull requests that touch it
verify's cargo runs never build launcher/ (its own workspace), so #2059 and the
registry ratings commit each passed alone and left main's launcher failing to
compile (E0061). The new launcher job runs its rustfmt, clippy -D warnings and lib
tests when a pull request changes the launcher, a crate it builds or the root
manifests, and on every push to main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 16:29:09 +01:00

52 lines
2.0 KiB
Python

#!/usr/bin/env python3
"""Keep verify's Rust steps for any change beyond website content or documentation.
--launcher: whether the change is built into the launcher, its own workspace (release_train.LAUNCHER_PATHS).
"""
import argparse
import subprocess
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
import release_train # noqa: E402
# The root workspace's manifest and toolchain files: the launcher's path crates inherit from them.
ROOT_RUST = {"Cargo.toml", "Cargo.lock", "rust-toolchain.toml", "rustfmt.toml", "clippy.toml"}
# The check itself: a change to it runs it.
LAUNCHER_CHECK = {".github/workflows/ci.yml", "tools/ci/rust_changes.py", "tools/release_train.py"}
def needs_rust(paths):
# horizon-theme's Rust tests check that the generated website tokens match.
return any(path == "website/src/tokens.css" or not (
path.startswith(("website/", "docs/")) or path.endswith(".md")
) for path in paths)
def needs_launcher(paths):
return any(path in ROOT_RUST or path in LAUNCHER_CHECK or (
path.startswith(tuple(release_train.LAUNCHER_PATHS))
and not path.startswith(tuple(release_train.LAUNCHER_IGNORED))
and not path.endswith(".md")
) for path in paths)
def changed_paths(base, head):
# Renames must include deletions too: moving source into docs still affects Rust.
output = subprocess.check_output([
"git", "diff", "--name-only", "--no-renames", "-z", f"{base}...{head}", "--",
])
return [path for path in output.decode("utf-8").split("\0") if path]
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("base")
parser.add_argument("head")
parser.add_argument("--launcher", action="store_true", help="answer for the launcher instead")
args = parser.parse_args()
needs = needs_launcher if args.launcher else needs_rust
print(f"required={str(needs(changed_paths(args.base, args.head))).lower()}")