"""Fail when generated build metadata has drifted from .build_number.""" from __future__ import annotations import ast import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] def backend_build_number() -> str: tree = ast.parse((ROOT / "backend/app/build_info.py").read_text(encoding="utf-8-sig")) for node in tree.body: if isinstance(node, ast.Assign) and any( isinstance(target, ast.Name) and target.id == "BUILD_NUMBER" for target in node.targets ): return str(ast.literal_eval(node.value)) raise RuntimeError("backend/app/build_info.py does not define BUILD_NUMBER") def main() -> None: expected = (ROOT / ".build_number").read_text(encoding="utf-8-sig").strip() package = json.loads((ROOT / "frontend/package.json").read_text(encoding="utf-8")) package_lock = json.loads((ROOT / "frontend/package-lock.json").read_text(encoding="utf-8")) values = { "backend/app/build_info.py": backend_build_number(), "frontend/package.json": str(package.get("version") or ""), "frontend/package-lock.json": str(package_lock.get("version") or ""), "frontend/package-lock.json root package": str(package_lock.get("packages", {}).get("", {}).get("version") or ""), } drifted = {name: value for name, value in values.items() if value != expected} if drifted: details = ", ".join(f"{name}={value!r}" for name, value in drifted.items()) raise SystemExit(f"Build metadata differs from .build_number ({expected!r}): {details}") print(f"Build metadata is synchronized: {expected}") if __name__ == "__main__": main()