lankasailendra/BMCTESTMAIN
0
1"""Run every preflight and report. This is what CI calls.2 3 python scripts/validate_all.py4 5The workflow has referenced this file since it was written, but the file did not6exist — so CI ran no checks at all, which is how three preflights were able to7rot unnoticed (a dead `import json`, a leaked monkeypatch, and an assertion for a8policy that had been deliberately reversed).9 10A preflight that cannot import its dependencies is reported as SKIPPED, not as a11pass: CI installing a smaller dependency set than a developer has must never read12as a clean run. Exit code is non-zero if anything FAILED.13"""14 15import pathlib16import re17import subprocess18import sys19 20REPO = pathlib.Path(__file__).resolve().parent.parent21SCRIPTS = sorted(REPO.glob("scripts/preflight_*.py"))22# Only a THIRD-PARTY module that is not installed may be skipped. A missing NAME23# is always a repo change (a renamed or deleted symbol), and a missing MODULE24# that lives in this repo is too — both are exactly what CI exists to catch, so25# neither may be quietly downgraded to SKIP.26_MISSING_MODULE = re.compile(r"ModuleNotFoundError: No module named ['\"]([\w.]+)")27_REPO_IMPORT_ROOTS = (28 REPO / "src",29 REPO / "scripts",30 REPO / "reference" / "itsm",31 REPO / "reference" / "itsm" / "conftest_files",32 REPO / "reference" / "client_executor" / "itsm_runtime",33)34 35 36def _is_repo_module(name: str) -> bool:37 top = (name or "").split(".")[0]38 if not top:39 return False40 return any(41 (root / f"{top}.py").is_file() or (root / top / "__init__.py").is_file()42 for root in _REPO_IMPORT_ROOTS43 )44 45 46def _skippable(output: str) -> bool:47 """True only when a module this repo does not own is missing."""48 hits = _MISSING_MODULE.findall(output or "")49 return bool(hits) and not any(_is_repo_module(h) for h in hits)50 51 52results: list[tuple[str, str, str]] = []53for script in SCRIPTS:54 proc = subprocess.run(55 [sys.executable, str(script)],56 capture_output=True,57 text=True,58 cwd=str(REPO),59 )60 out = (proc.stdout or "") + (proc.stderr or "")61 if proc.returncode == 0:62 status, detail = "PASS", (out.strip().splitlines() or [""])[-1]63 elif _skippable(out):64 status = "SKIP"65 detail = next((ln.strip() for ln in out.splitlines() if _MISSING_MODULE.search(ln)), "")66 else:67 status = "FAIL"68 detail = next((ln.strip() for ln in reversed(out.splitlines()) if "FAIL" in ln), "") or (69 out.strip().splitlines()[-1] if out.strip() else ""70 )71 results.append((script.name, status, detail))72 print(f"[{status}] {script.name}" + (f" - {detail[:140]}" if detail else ""))73 74failed = [n for n, s, _ in results if s == "FAIL"]75skipped = [n for n, s, _ in results if s == "SKIP"]76print()77print(78 f"{len(results)} preflight(s): "79 f"{len(results) - len(failed) - len(skipped)} passed, "80 f"{len(failed)} failed, {len(skipped)} skipped"81)82if skipped:83 print("SKIPPED (dependency missing — these checked nothing): " + ", ".join(skipped))84if failed:85 print("FAILED: " + ", ".join(failed))86sys.exit(1 if failed else 0)87 