Complete guided release console workflow
Dependency Audit / dependency-audit (push) Successful in 2m35s
Deployment Installer / deployment-installer (push) Successful in 6s
Security Audit / security-audit (push) Failing after 15s

This commit is contained in:
2026-07-31 05:46:50 +02:00
parent b4248a849e
commit f1fd143ef5
13 changed files with 2332 additions and 117 deletions
+176 -13
View File
@@ -9,6 +9,7 @@ import tempfile
from types import SimpleNamespace
import unittest
from unittest.mock import patch
import zipfile
META_ROOT = Path(__file__).resolve().parents[1]
@@ -17,6 +18,7 @@ if str(RELEASE_ROOT) not in sys.path:
sys.path.insert(0, str(RELEASE_ROOT))
from govoplan_release.model import RepositorySpec # noqa: E402
from govoplan_release.artifact_identity import inspect_python_wheel # noqa: E402
from govoplan_release.git_state import sanitized_git_environment # noqa: E402
from govoplan_release.release_execution import ( # noqa: E402
ExecutorSpec,
@@ -30,6 +32,7 @@ from govoplan_release.release_execution import ( # noqa: E402
require_trusted_release_runtime,
verify_frozen_repository_tag_receipt,
verify_repository_preflight_binding,
verify_candidate_installation,
_clone_catalog_sources,
_checkout_frozen_source,
_flatpak_proxy_environment,
@@ -489,20 +492,180 @@ class ReleaseExecutionTests(unittest.TestCase):
expected_receipt={"kind": "repository_state"},
)
def test_commit_step_has_no_durable_executor(self) -> None:
self.assertIsNone(
executor_spec(
{
"id": "govoplan-files:commit",
"status": "planned",
"mutating": True,
"repo": "govoplan-files",
"source_binding": {
"kind": "repository_state",
},
}
)
def test_commit_step_has_narrow_confirmation(self) -> None:
spec = executor_spec(
{
"id": "govoplan-files:commit",
"status": "planned",
"mutating": True,
"repo": "govoplan-files",
"source_binding": {
"kind": "repository_state",
},
}
)
self.assertIsNotNone(spec)
self.assertEqual("commit", spec.kind)
self.assertEqual("COMMIT", spec.confirmation)
def test_version_and_commit_executors_bind_only_release_metadata(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir:
workspace = Path(temp_dir)
repository = workspace / "govoplan-files"
remote = workspace / "files.git"
_git(workspace, "init", "--bare", str(remote))
_git(workspace, "init", "-b", "main", str(repository))
_git(repository, "config", "user.name", "Release Test")
_git(repository, "config", "user.email", "release@example.test")
(repository / "pyproject.toml").write_text(
'[project]\nname = "govoplan-files"\nversion = "1.2.3"\n',
encoding="utf-8",
)
_git(repository, "add", "pyproject.toml")
_git(repository, "commit", "-m", "Initial")
_git(repository, "remote", "add", "origin", str(remote))
_git(repository, "push", "-u", "origin", "main")
repository_spec = _repository_spec(remote)
plan_step = {
"id": "govoplan-files:version",
"repo": "govoplan-files",
"source_binding": {"kind": "repository_state"},
}
with (
patch(
"govoplan_release.release_execution.load_repository_specs",
return_value=(repository_spec,),
),
patch(
"govoplan_release.release_execution.require_trusted_release_runtime"
),
):
before = repository_state_receipt(
repo="govoplan-files",
target_tag="v1.2.4",
workspace_root=workspace,
)
_result, updated = execute_repository_step(
spec=ExecutorSpec(
"version",
"UPDATE",
"version_metadata_updated",
True,
),
plan_step=plan_step,
repo_versions={"govoplan-files": "1.2.4"},
workspace_root=workspace,
remote="origin",
expected_receipt=before,
)
self.assertFalse(updated["worktree_clean"])
self.assertNotEqual(
before["worktree_sha256"],
updated["worktree_sha256"],
)
plan_step["id"] = "govoplan-files:commit"
_result, committed = execute_repository_step(
spec=ExecutorSpec(
"commit",
"COMMIT",
"release_commit_created",
True,
),
plan_step=plan_step,
repo_versions={"govoplan-files": "1.2.4"},
workspace_root=workspace,
remote="origin",
expected_receipt=updated,
)
self.assertTrue(committed["worktree_clean"])
self.assertNotEqual(before["head"], committed["head"])
self.assertIn(
'version = "1.2.4"',
(repository / "pyproject.toml").read_text(encoding="utf-8"),
)
def test_candidate_installation_verifies_installed_metadata(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir:
workspace = Path(temp_dir)
repository = workspace / "govoplan-files"
repository.mkdir()
(repository / "pyproject.toml").write_text(
'[project]\nname = "govoplan-files"\nversion = "1.2.4"\n',
encoding="utf-8",
)
artifacts = workspace / "candidate" / "artifacts"
artifacts.mkdir(parents=True)
wheel = artifacts / "govoplan_files-1.2.4-py3-none-any.whl"
members = {
"govoplan_files/__init__.py": '__version__ = "1.2.4"\n',
"govoplan_files-1.2.4.dist-info/METADATA": (
"Metadata-Version: 2.1\n"
"Name: govoplan-files\n"
"Version: 1.2.4\n"
),
"govoplan_files-1.2.4.dist-info/WHEEL": (
"Wheel-Version: 1.0\n"
"Generator: release-test\n"
"Root-Is-Purelib: true\n"
"Tag: py3-none-any\n"
),
}
record = "\n".join(f"{name},," for name in members)
record += "\ngovoplan_files-1.2.4.dist-info/RECORD,,\n"
with zipfile.ZipFile(wheel, "w") as archive:
for name, content in members.items():
archive.writestr(name, content)
archive.writestr(
"govoplan_files-1.2.4.dist-info/RECORD",
record,
)
identity = inspect_python_wheel(wheel)
channels = workspace / "candidate" / "channels"
channels.mkdir()
(channels / "stable.json").write_text(
json.dumps(
{
"release": {
"selected_units": [
{
"repo": "govoplan-files",
"version": "1.2.4",
}
],
"artifacts": [
{
"package_name": "govoplan-files",
"archive_sha256": identity.archive_sha256,
}
],
},
"core_release": {},
"modules": [
{
"python_package": "govoplan-files",
"python_ref": (
"govoplan-files @ "
"git+ssh://git@example.test/GovOPlaN/"
"govoplan-files.git@v1.2.4"
),
}
],
}
)
+ "\n",
encoding="utf-8",
)
result = verify_candidate_installation(
candidate_path=workspace / "candidate",
repo_versions={"govoplan-files": "1.2.4"},
)
self.assertEqual("verified", result["status"])
self.assertEqual("govoplan-files", result["packages"][0]["repo"])
self.assertEqual("1.2.4", result["packages"][0]["version"])
def test_frozen_checkout_uses_receipt_commit_not_live_worktree(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir: