"""Optional migration audit collection for the local release console.""" from __future__ import annotations import json import subprocess import sys from .model import MigrationTrackSnapshot from .workspace import META_ROOT def collect_migration_snapshots(*, timeout: int = 30) -> tuple[MigrationTrackSnapshot, ...]: return tuple(collect_migration_snapshot(track, timeout=timeout) for track in ("release", "dev")) def collect_migration_snapshot(track: str, *, timeout: int) -> MigrationTrackSnapshot: script = META_ROOT / "tools" / "release" / "release-migration-audit.py" try: result = subprocess.run( [sys.executable, str(script), "--track", track, "--json"], cwd=META_ROOT, check=False, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout, ) except subprocess.TimeoutExpired: return MigrationTrackSnapshot(track=track, ok=False, ran=False, error="migration audit timed out") if result.returncode != 0: return MigrationTrackSnapshot( track=track, ok=False, ran=True, error=(result.stderr or result.stdout).strip() or f"migration audit exited with {result.returncode}", ) try: payload = json.loads(result.stdout) except json.JSONDecodeError as exc: return MigrationTrackSnapshot(track=track, ok=False, ran=True, error=f"could not parse audit JSON: {exc}") graph_errors = tuple(str(item) for item in payload.get("graph_errors") or ()) strict_errors = tuple(str(item) for item in payload.get("strict_errors") or ()) return MigrationTrackSnapshot( track=track, ok=not graph_errors and not strict_errors, ran=True, graph_errors=graph_errors, strict_errors=strict_errors, )