from __future__ import annotations import importlib.util from pathlib import Path import sys import tempfile import unittest ROOT = Path(__file__).resolve().parents[1] SCRIPT = ROOT / "scripts" / "release-migration-audit.py" def load_audit_module(): spec = importlib.util.spec_from_file_location("release_migration_audit", SCRIPT) if spec is None or spec.loader is None: raise RuntimeError(f"Could not load {SCRIPT}") module = importlib.util.module_from_spec(spec) sys.modules[spec.name] = module spec.loader.exec_module(module) return module class ReleaseMigrationAuditTests(unittest.TestCase): def test_typed_alembic_variables_are_parsed(self) -> None: audit = load_audit_module() with tempfile.TemporaryDirectory(prefix="migration-audit-test-") as directory: path = Path(directory) / "1234_example.py" path.write_text( """ from __future__ import annotations from typing import Sequence, Union revision: str = "1234" down_revision: Union[str, None] = "base" branch_labels: Union[str, Sequence[str], None] = None """, encoding="utf-8", ) migration = audit.parse_migration_file("govoplan-core", path) self.assertIsNotNone(migration) self.assertEqual(migration.revision, "1234") self.assertEqual(migration.down_revisions, ("base",)) self.assertEqual(migration.branch_labels, ()) def test_release_baseline_matches_current_heads_in_strict_report(self) -> None: audit = load_audit_module() migrations = [ audit.Migration("govoplan-core", Path("base.py"), "base", (), ()), audit.Migration("govoplan-core", Path("head.py"), "head", ("base",), ()), ] report = audit.build_report( migrations, baseline={ "version": 1, "releases": [ { "release": "0.1.0", "heads": [{"owner": "govoplan-core", "revision": "head"}], } ], }, baseline_file=Path("docs/migration-release-baselines.json"), workspace_root=Path("/workspace"), ) self.assertEqual(report["current_heads"], ["head"]) self.assertEqual(report["graph_errors"], []) self.assertEqual(report["strict_errors"], []) def test_owner_heads_are_accepted_for_subset_installs(self) -> None: audit = load_audit_module() migrations = [ audit.Migration("govoplan-core", Path("base.py"), "base", (), ()), audit.Migration("govoplan-core", Path("core_head.py"), "core-head", ("base",), ()), ] report = audit.build_report( migrations, baseline={ "version": 1, "releases": [ { "release": "0.1.0", "heads": [{"owner": "govoplan-files", "revision": "files-head"}], "owner_heads": [{"owner": "govoplan-core", "revisions": ["core-head"]}], } ], }, baseline_file=Path("docs/migration-release-baselines.json"), workspace_root=Path("/workspace"), ) self.assertEqual(report["current_heads"], ["core-head"]) self.assertEqual(report["strict_errors"], []) def test_records_current_release_baseline(self) -> None: audit = load_audit_module() migrations = [ audit.Migration("govoplan-core", Path("base.py"), "base", (), ()), audit.Migration("govoplan-core", Path("core_head.py"), "core-head", ("base",), ()), audit.Migration("govoplan-files", Path("files_head.py"), "files-head", ("core-head",), ()), ] report = audit.build_report( migrations, baseline={"version": 1, "releases": []}, baseline_file=Path("docs/migration-release-baselines.json"), workspace_root=Path("/workspace"), ) baseline = audit.record_release_baseline( {"version": 1, "releases": []}, report, release="0.2.0", replace=False, ) release = baseline["releases"][0] self.assertEqual(release["release"], "0.2.0") self.assertEqual(release["squash_policy"], "reviewed-manual") self.assertEqual(release["heads"], [{"owner": "govoplan-files", "revision": "files-head"}]) self.assertIn({"owner": "govoplan-core", "revisions": ["core-head"]}, release["owner_heads"]) def test_missing_down_revision_is_a_graph_error(self) -> None: audit = load_audit_module() migrations = [ audit.Migration("govoplan-core", Path("head.py"), "head", ("missing",), ()), ] report = audit.build_report( migrations, baseline={"version": 1, "releases": []}, baseline_file=Path("docs/migration-release-baselines.json"), workspace_root=Path("/workspace"), ) self.assertIn("references missing down_revision", report["graph_errors"][0]) if __name__ == "__main__": unittest.main()