"""Temporary-repository support for architecture-lint tests.""" import json import subprocess import sys import tempfile import textwrap import unittest from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[2] LINTER = REPO_ROOT / "scripts" / "lint-architecture.py" sys.path.insert(0, str(LINTER.parent)) from architecture_lint.rules import RULES # noqa: E402 RUNTIME_RULE = "ARCH-RUNTIME-IMPORT" TASK_OFFICE_RULE = "ARCH-TASK-OFFICE-IMPORT" ROOT_STATE_RULE = "ARCH-FRONTEND-ROOT-STATE-CAST" RUNTIME_IMPORT = "github.com/kandev/kandev/internal/agent/runtime/lifecycle" OFFICE_IMPORT = "github.com/kandev/kandev/internal/office/models" RULE_FILES = {rule.id: rule.baseline_path.name for rule in RULES} class ArchitectureFixture(unittest.TestCase): def setUp(self) -> None: self.tempdir = tempfile.TemporaryDirectory() self.repo = Path(self.tempdir.name) self.git("init", "-q") self.git("config", "user.email", "test@example.com") self.git("config", "user.name", "Architecture Test") self.write_baseline() self.write_ledger([]) def tearDown(self) -> None: self.tempdir.cleanup() def git(self, *args: str) -> subprocess.CompletedProcess[str]: return subprocess.run( ["git", *args], cwd=self.repo, text=True, capture_output=True, check=True, ) def write(self, relative: str, content: str) -> None: path = self.repo / relative path.parent.mkdir(parents=True, exist_ok=True) path.write_text(textwrap.dedent(content).lstrip(), encoding="utf-8") def write_json(self, relative: str, content: object) -> None: self.write(relative, json.dumps(content, indent=2) + "\n") def write_baseline( self, *, runtime: list[dict[str, object]] | None = None, task_office: list[dict[str, object]] | None = None, root_state: list[dict[str, object]] | None = None, ) -> None: entries = {rule.id: [] for rule in RULES} entries.update( { RUNTIME_RULE: runtime or [], TASK_OFFICE_RULE: task_office or [], ROOT_STATE_RULE: root_state or [], } ) for rule in RULES: self.write_json( rule.baseline_path.as_posix(), {"version": 1, "rule": rule.id, "entries": entries[rule.id]}, ) def write_ledger(self, entries: list[dict[str, object]]) -> None: self.write_json( "config/architecture-lint/compatibility-ledger.json", {"version": 1, "entries": entries}, ) def track_all(self) -> None: self.git("add", ".") def run_cli(self, *args: str, cwd: Path | None = None) -> subprocess.CompletedProcess[str]: return subprocess.run( [sys.executable, str(LINTER), *args], cwd=cwd or self.repo, text=True, capture_output=True, check=False, ) def assert_diagnostic_location(self, result: subprocess.CompletedProcess[str], path: str, line: int) -> None: self.assertIn(path, result.stdout) self.assertTrue( f"{path}:{line}" in result.stdout or f"line={line}" in result.stdout, result.stdout, ) @staticmethod def runtime_entry(path: str) -> dict[str, str]: return {"path": path, "import": RUNTIME_IMPORT} def valid_ledger_entry(self, *, marker: str = "// compat: old-name") -> dict[str, object]: return { "id": "old-name-alias", "locator": { "path": "apps/backend/internal/example/compat.go", "marker": marker, }, "reason": "Older persisted callers still use the old name.", "owner": "backend maintainers", "introduced_on": "2026-01-15", "removal_condition": "Remove after all persisted callers have migrated.", "target_removal_date": "2099-12-31", }