from __future__ import annotations import json from pathlib import Path import shutil import subprocess import tempfile import unittest META_ROOT = Path(__file__).resolve().parents[1] class ModulePackageWorkflowTests(unittest.TestCase): def test_template_enforces_tag_version_hash_and_registry_contract(self) -> None: workflow = ( META_ROOT / "tools/repo/templates/module-package-release.yml" ).read_text(encoding="utf-8") self.assertIn("GITEA_REPOSITORY: ${{ gitea.repository }}", workflow) self.assertNotIn("tag_protections", workflow) self.assertNotIn("secrets.GITEA_TOKEN", workflow) self.assertIn("git merge-base --is-ancestor", workflow) self.assertIn("does not match", workflow) self.assertIn("package-artifacts.json", workflow) self.assertIn("api/packages/GovOPlaN/pypi", workflow) self.assertIn("api/packages/GovOPlaN/npm", workflow) self.assertIn('npm publish "./${webui_packages[0]}"', workflow) self.assertIn("Check immutable registry state", workflow) self.assertIn('files[0].get("sha256") != expected_sha256', workflow) self.assertIn('if [[ "$PUBLISH_PYPI" == 1 ]]', workflow) self.assertIn('[[ "$PUBLISH_NPM" == 1 ]]', workflow) self.assertIn("GOVOPLAN_PACKAGE_TOKEN", workflow) self.assertIn("must resolve to an exact registry version", workflow) self.assertIn("git\\\\.add-ideas\\\\.de/(?:GovOPlaN|add-ideas)", workflow) self.assertIn("release package identity does not match", workflow) self.assertNotIn("Generic", workflow) @unittest.skipUnless(shutil.which("node"), "Node.js is required") def test_webui_publication_normalizes_internal_git_dependencies(self) -> None: workflow = ( META_ROOT / "tools/repo/templates/module-package-release.yml" ).read_text(encoding="utf-8") marker = " node <<'NODE'\n" script = workflow.split(marker, 1)[1].split("\n NODE", 1)[0] with tempfile.TemporaryDirectory() as temporary: root = Path(temporary) package_dir = root / ".package-webui" package_dir.mkdir() package_path = package_dir / "package.json" package_path.write_text( json.dumps( { "name": "@govoplan/core-webui", "version": "0.1.14", "private": True, "dependencies": { "@govoplan/access-webui": ( "git+ssh://git@git.add-ideas.de/GovOPlaN/" "govoplan-access.git#v0.1.11" ), "@govoplan/admin-webui": ( "git+ssh://git@git.add-ideas.de/add-ideas/" "govoplan-admin.git#v0.1.8" ) }, } ), encoding="utf-8", ) subprocess.run( ["node"], input=script, cwd=root, check=True, text=True, capture_output=True, ) package = json.loads(package_path.read_text(encoding="utf-8")) self.assertNotIn("private", package) self.assertEqual( "0.1.11", package["dependencies"]["@govoplan/access-webui"] ) self.assertEqual( "0.1.8", package["dependencies"]["@govoplan/admin-webui"] ) def test_sync_script_only_targets_packageable_govoplan_repositories(self) -> None: namespace: dict[str, object] = { "__file__": str(META_ROOT / "tools/repo/sync-module-package-workflows.py"), "__name__": "test_sync_module_package_workflows", } script = (META_ROOT / "tools/repo/sync-module-package-workflows.py").read_text( encoding="utf-8" ) exec(compile(script, str(namespace["__file__"]), "exec"), namespace) with tempfile.TemporaryDirectory() as temporary: parent = Path(temporary) package_repositories = namespace["package_repositories"] # The production inventory is authoritative, so a temporary parent # only exposes matching paths that are present in that inventory. known = parent / "govoplan-core" known.mkdir() (known / "pyproject.toml").write_text("[project]\n", encoding="utf-8") self.assertEqual(package_repositories(parent), (known,)) if __name__ == "__main__": unittest.main()