from __future__ import annotations import os import subprocess from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[2] SCRIPT = REPO_ROOT / ".github/scripts/merge-ready/compute-gate.sh" # A representative FAILED bullet list, the shape evaluate-checks.sh emits. FAILED = "- `E2E Tests (shard 0/4)` (still pending or cancelled)\n" def _run( tmp_path: Path, *, eval_outcome: str = "failure", failed: str = FAILED, ) -> dict[str, str]: """Run compute-gate.sh with the given env and parse its GITHUB_OUTPUT. The script makes no ``gh`` calls -- it is a pure function of its env -- so we just set the inputs and read back ``state`` / ``short_desc`` / ``long_desc``. """ out_file = tmp_path / "gh_output" out_file.touch() env = os.environ.copy() env.update( { "EVAL": eval_outcome, "FAILED": failed, "GITHUB_OUTPUT": str(out_file), } ) proc = subprocess.run( ["bash", str(SCRIPT)], env=env, capture_output=True, text=True, timeout=30, ) assert proc.returncode == 0, f"script failed: {proc.stderr}" return _parse_github_output(out_file.read_text()) def _parse_github_output(text: str) -> dict[str, str]: """Parse GITHUB_OUTPUT, honoring both ``k=v`` and ``k< None: """A green CI eval yields state=success and the merging-now message.""" out = _run(tmp_path, eval_outcome="success") assert out["state"] == "success" assert "merging now" in out["long_desc"] def test_red_gate_is_failure(tmp_path: Path) -> None: """A red CI eval lists the failing checks and yields state=failure.""" out = _run(tmp_path, eval_outcome="failure") assert out["state"] == "failure" assert "gate not green yet" in out["long_desc"] def test_short_desc_never_exceeds_140_chars(tmp_path: Path) -> None: """The 140-char commit status limit is respected.""" out = _run(tmp_path, eval_outcome="failure") assert len(out["short_desc"]) <= 140