Files
govoplan/tests/test_release_migration_audit.py
T
zemion f1fd143ef5
Dependency Audit / dependency-audit (push) Successful in 2m35s
Deployment Installer / deployment-installer (push) Successful in 6s
Security Audit / security-audit (push) Failing after 15s
Complete guided release console workflow
2026-07-31 05:46:50 +02:00

223 lines
8.5 KiB
Python

from __future__ import annotations
import importlib.util
from pathlib import Path
import sys
import tempfile
import unittest
META_ROOT = Path(__file__).resolve().parents[1]
SCRIPT = META_ROOT / "tools" / "release" / "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"
depends_on: Union[str, None] = "core"
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.depends_on, ("core",))
self.assertEqual(migration.branch_labels, ())
def test_development_wrapper_uses_release_revision_metadata(self) -> None:
audit = load_audit_module()
with tempfile.TemporaryDirectory(prefix="migration-audit-test-") as directory:
root = Path(directory)
versions = root / "versions"
development = root / "dev_versions"
versions.mkdir()
development.mkdir()
release = versions / "1234_example.py"
release.write_text(
'revision = "1234"\n'
'down_revision = "base"\n'
'depends_on = "core"\n'
"branch_labels = None\n",
encoding="utf-8",
)
wrapper = development / release.name
wrapper.write_text(
"revision = _migration.revision\n"
"down_revision = _migration.down_revision\n"
"depends_on = _migration.depends_on\n"
"branch_labels = _migration.branch_labels\n",
encoding="utf-8",
)
migration = audit.parse_migration_file("govoplan-core", wrapper)
self.assertIsNotNone(migration)
self.assertEqual("1234", migration.revision)
self.assertEqual(("base",), migration.down_revisions)
self.assertEqual(("core",), migration.depends_on)
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])
def test_depends_on_participates_in_graph_validation_and_heads(self) -> None:
audit = load_audit_module()
migrations = [
audit.Migration("govoplan-core", Path("core.py"), "core", (), (), ()),
audit.Migration("govoplan-files", Path("files.py"), "files", (), ("core",), ()),
]
report = audit.build_report(
migrations,
baseline={"version": 1, "releases": []},
baseline_file=Path("docs/migration-release-baselines.json"),
workspace_root=Path("/workspace"),
)
self.assertEqual(report["graph_errors"], [])
self.assertEqual(report["current_heads"], ["files"])
def test_missing_depends_on_is_a_graph_error(self) -> None:
audit = load_audit_module()
migrations = [
audit.Migration("govoplan-files", Path("files.py"), "files", (), ("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 depends_on", report["graph_errors"][0])
def test_dev_track_does_not_emit_release_baseline_warnings(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": []},
baseline_file=Path("docs/migration-release-baselines.json"),
workspace_root=Path("/workspace"),
track="dev",
)
self.assertEqual(report["track"], "dev")
self.assertEqual(report["strict_errors"], [])
if __name__ == "__main__":
unittest.main()