diff --git a/plugins/magpie-setup/skills/isolated-setup-doctor/tests/test_probe_1_ssh_agent.py b/plugins/magpie-setup/skills/isolated-setup-doctor/tests/test_probe_1_ssh_agent.py index 6acdc70ea..b96889b19 100644 --- a/plugins/magpie-setup/skills/isolated-setup-doctor/tests/test_probe_1_ssh_agent.py +++ b/plugins/magpie-setup/skills/isolated-setup-doctor/tests/test_probe_1_ssh_agent.py @@ -69,9 +69,7 @@ def run_probe(self) -> str: "SSH_AUTH_SOCK": str(self.sock_path), "TMPDIR": str(self.tmp), } - result = subprocess.run( - ["bash", str(PROBE)], env=env, capture_output=True, text=True, check=True - ) + result = subprocess.run(["bash", str(PROBE)], env=env, capture_output=True, text=True, check=True) return result.stdout.strip() def test_counts_listed_identities(self) -> None: diff --git a/tools/dev/ci-pytest-batches.py b/tools/dev/ci-pytest-batches.py index 565f1cd4e..f1282214c 100644 --- a/tools/dev/ci-pytest-batches.py +++ b/tools/dev/ci-pytest-batches.py @@ -35,7 +35,8 @@ Prints a JSON array of `{"key", "name", "paths", "packages"}` for the workflow's matrix (`paths` and `packages` space-separated, in the same order; `packages` are the members' project names, so a job syncs only what its members declare). -`--changed-file` names a file listing the changed paths; omit it for a full run. +`--changed-file` names a file listing the changed paths, or `-` to read them from stdin; +omit it for a full run. `--paths` prints the picked member paths one per line instead, for the local `workspace-pytest` hook, so a commit runs the same members a pull request would. """ @@ -209,16 +210,18 @@ def batches(paths: list[str], weights: dict[str, int]) -> list[dict[str, str]]: def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) parser.add_argument("--root", type=Path, default=Path(".")) - parser.add_argument("--changed-file", type=Path, help="file listing a pull request's changed paths") + parser.add_argument( + "--changed-file", type=Path, help="file listing a pull request's changed paths, or - for stdin" + ) parser.add_argument("--paths", action="store_true", help="print the picked member paths, one per line") args = parser.parse_args(argv) changed = None if args.changed_file: - changed = [ - line.strip() - for line in args.changed_file.read_text(encoding="utf-8").splitlines() - if line.strip() - ] + if str(args.changed_file) == "-": + raw_lines = sys.stdin.read().splitlines() + else: + raw_lines = args.changed_file.read_text(encoding="utf-8").splitlines() + changed = [line.strip().replace("\\", "/") for line in raw_lines if line.strip()] paths = select(args.root, changed) if args.paths: for path in paths: diff --git a/tools/dev/run-workspace-check.sh b/tools/dev/run-workspace-check.sh index 2457370e8..84cba55d7 100755 --- a/tools/dev/run-workspace-check.sh +++ b/tools/dev/run-workspace-check.sh @@ -162,7 +162,7 @@ fi if [ "$CHECK_KEY" = "pytest" ] && [ "$#" -gt 0 ]; then # The list goes through stdin, not a temp file: a sandboxed agent may # not be able to write the system temp directory. - applicable=$(printf '%s\n' "$@" | python3 tools/dev/ci-pytest-batches.py --changed-file /dev/stdin --paths) + applicable=$(printf '%s\n' "$@" | python3 tools/dev/ci-pytest-batches.py --changed-file - --paths | tr -d '\r') status=$? if [ "$status" -ne 0 ]; then exit "$status" diff --git a/tools/dev/tests/test_ci_pytest_batches.py b/tools/dev/tests/test_ci_pytest_batches.py index 6959a8e3c..8fc716eb3 100644 --- a/tools/dev/tests/test_ci_pytest_batches.py +++ b/tools/dev/tests/test_ci_pytest_batches.py @@ -20,6 +20,7 @@ from __future__ import annotations import importlib.util +import io import json from pathlib import Path from types import ModuleType @@ -91,7 +92,12 @@ def test_a_change_behind_a_member_symlink_picks_the_member(tmp_path): root = _workspace(tmp_path, {"tools/a": PYTEST, "tools/b": PYTEST}) (root / "plugins" / "shared").mkdir(parents=True) (root / "tools" / "a" / "src").mkdir() - (root / "tools" / "a" / "src" / "shared").symlink_to(root / "plugins" / "shared") + try: + (root / "tools" / "a" / "src" / "shared").symlink_to( + root / "plugins" / "shared", target_is_directory=True + ) + except OSError as exc: + pytest.skip(f"symlinks not supported on this platform: {exc}") assert cpb.select(root, ["plugins/shared/x.py"]) == ["tools/a"] @@ -135,6 +141,13 @@ def test_the_shared_toolchain_does_not_make_a_dependent(tmp_path): assert cpb.select(root, ["tools/dev/src/z.py"]) == ["tools/dev"] +def test_the_cli_reads_stdin_with_dash(tmp_path, monkeypatch, capsys): + root = _workspace(tmp_path, {"tools/a": PYTEST, "tools/b": PYTEST}) + monkeypatch.setattr("sys.stdin", io.StringIO("tools\\a\\src\\x.py\ntools/b/tests/test_y.py\n")) + assert cpb.main(["--root", str(root), "--changed-file", "-", "--paths"]) == 0 + assert capsys.readouterr().out == "tools/a\ntools/b\n" + + def test_the_cli_prints_the_picked_paths(tmp_path, capsys): root = _workspace(tmp_path, {"tools/a": PYTEST, "tools/b": PYTEST}) changed = tmp_path / "changed.txt"