This repository has been archived on 2026-11-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
platform-ci/tests/test_finalize_version.py
forge-recoveryandClaude Sonnet 5.5 a36f17b857
KofTwentyTwo/ci-policy: ci / fork-guard (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / go-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / go-nix-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / gradle-2 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / gradle-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / java-docker-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / java-maven-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / manifests-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / nix-7 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / node-8 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / python-9 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-10 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-11 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-12 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / source-config-13 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / source-config-14 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-2 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-7 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / not-enrolled (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / content-validate-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / standards-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / node-matrix-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / source-config-15 (pull_request) Blocked by required conditions
KofTwentyTwo/ci-policy: Shared source and config CI / verify (pull_request) Blocked by required conditions
KofTwentyTwo/ci-policy: Shared source and config CI / secrets (pull_request) Blocked by required conditions
KofTwentyTwo/ci-policy: Shared source and config CI / gate (pull_request) Waiting for needed jobs
KofTwentyTwo/ci-policy: ci / ci-result (pull_request) Waiting for needed jobs
KofTwentyTwo/ci-policy: native / fork-deny (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-2 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-7 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-8 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-9 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-10 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-11 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-12 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-13 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-14 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-15 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-16 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-17 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-18 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-19 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / native-result (pull_request) Canceled after 6s
feat(ci): advance shared pipeline capabilities
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 10:30:25 +00:00

169 lines
8.9 KiB
Python

"""The `finalize-version` command and the `version_write_back` configuration contract. UNTESTED: written while test execution was suspended; nothing is run, signed, pushed or contacted.
The forge, run trust, artifact selection and the write itself are patched at the module boundary: these tests pin what the command reads, refuses and passes on, not the write (see
`test_source_lifecycle.py`).
"""
import unittest
from types import SimpleNamespace
from typing import Any, cast
from unittest.mock import patch
import yaml
from platform_ci.__main__ import main
from platform_ci.configuration import ConfigurationError, WriteBackPolicy, parse_project_configuration
from platform_ci.delivery.errors import DeliveryError
from platform_ci.delivery.finalize_version import finalize_version
from platform_ci.delivery.publisher import RunInProgressError
from platform_ci.delivery.source_lifecycle import Fatal, NotYetPublished
from tests.support import example_mapping
SHA = "a" * 40
PLATFORM = "b" * 40
MODULE = "platform_ci.delivery.finalize_version"
def _configuration(*, tag_driven: bool = False, write_back: object = None, central: bool = False, publish: bool = True) -> dict[str, object]:
"""The Maven publication example with one channel (branch- or tag-driven) that may declare `version_write_back`."""
configuration = example_mapping("maven-publication.ci.yaml")
channel: dict[str, object] = {"trigger": {"push_tags": ["v*.*.*"]} if tag_driven else {"push_branches": ["release/**"]}, "versioning": "maven-release"}
if tag_driven:
channel["tag_policy"] = "stable"
if central:
channel["central_completion"] = True
if write_back is not None:
channel["version_write_back"] = write_back
publications = {"library-packages": {"component": "library", "artifact": "packages", "destination": "company-packages", "channels": ["candidate"]}} if publish else {}
configuration["release"] = {"channels": {"candidate": channel}, "publications": publications}
return configuration
def _environment(ref: str = "refs/heads/release/1.6", **overrides: str) -> dict[str, str]:
values = {
"CI_EVENT_NAME": "push",
"CI_EVENT_REF": ref,
"CI_SOURCE_REVISION": SHA,
"CI_REPOSITORY": "Org/repo",
"CI_REPOSITORY_ID": "7",
"CI_RUN_ID": "50",
"CI_RUN_ATTEMPT": "1",
"CI_PLATFORM_REVISION": PLATFORM,
"CI_SCOPED_SOURCE_ID": "3",
"CI_WORKFLOW_SHA": "c" * 40,
"GITHUB_SERVER_URL": "https://git.kof22.com",
"FORGE_TOKEN": "job-token",
}
return values | overrides
def _artifact(version: str | None = "1.6.0-RC.1") -> Any:
inputs = None if version is None else SimpleNamespace(version=version)
return SimpleNamespace(manifest=SimpleNamespace(build_inputs=inputs))
class ConfigurationContractTest(unittest.TestCase):
def test_a_branch_driven_channel_opts_in_and_defaults_are_closed(self) -> None:
channel = parse_project_configuration(_configuration(write_back={"require_push": True})).channels[0]
self.assertEqual(channel.version_write_back, WriteBackPolicy(require_push=True))
self.assertIsNone(parse_project_configuration(_configuration()).channels[0].version_write_back)
def test_a_tag_driven_channel_names_the_branch_it_writes_to(self) -> None:
channel = parse_project_configuration(_configuration(tag_driven=True, write_back={"target_branch": "main"})).channels[0]
self.assertEqual(channel.version_write_back, WriteBackPolicy(target_branch="main"))
def test_each_invalid_declaration_is_refused(self) -> None:
cases: dict[str, dict[str, object]] = {
"other file": _configuration(write_back={"file": "build.gradle"}),
"branch target on a branch channel": _configuration(write_back={"target_branch": "main"}),
"tag channel without a target": _configuration(tag_driven=True, write_back={}),
"bad require_push": _configuration(write_back={"require_push": "yes"}),
"unknown field": _configuration(write_back={"token": "x"}),
"not a mapping": _configuration(write_back="yes"),
"no maven publication": _configuration(write_back={}, publish=False),
}
for name, configuration in cases.items():
with self.subTest(name), self.assertRaises(ConfigurationError):
parse_project_configuration(configuration)
def test_a_channel_with_both_trigger_kinds_cannot_write_back(self) -> None:
configuration = _configuration(write_back={})
cast("dict[str, dict[str, dict[str, Any]]]", configuration["release"])["channels"]["candidate"]["trigger"]["push_tags"] = ["v*.*.*"]
with self.assertRaises(ConfigurationError):
parse_project_configuration(configuration)
def _run(environment: dict[str, str], configuration: dict[str, object] | None, *, artifacts: dict[str, Any] | None = None, trusted: bool = True, select_error: Exception | None = None, **injected: Any) -> tuple[list[str], dict[str, Any]]:
"""Run the command with the forge boundary patched; return its lines and the keyword arguments `postpublish` received."""
seen: dict[str, Any] = {}
def postpublish(ctx: Any, policy: Any, **keywords: Any) -> dict[str, str]:
seen.update(keywords, ctx=ctx, policy=policy)
return {"status": "pushed", "reason": "", "pushed_sha": "d" * 40}
content = None if configuration is None else yaml.safe_dump(configuration).encode()
selector = patch(f"{MODULE}.select_artifacts", side_effect=select_error) if select_error else patch(f"{MODULE}.select_artifacts", return_value=(artifacts or {"library-linux-amd64": _artifact()}, []))
with (
patch(f"{MODULE}.require_repository"),
patch(f"{MODULE}.current_workflow_trust", return_value=object() if trusted else None),
patch(f"{MODULE}.read_file", return_value=content),
selector,
patch(f"{MODULE}.selected_artifact_files", return_value=("file",)),
patch(f"{MODULE}.postpublish", side_effect=postpublish),
patch(f"{MODULE}.SourceWriter"),
patch(f"{MODULE}.VersionGit"),
patch(f"{MODULE}.legacy.package_client"),
patch(f"{MODULE}.load_runtime_catalog"),
):
lines = finalize_version(environment, forge=cast("Any", object()), **injected)
return lines, seen
class FinalizeVersionTest(unittest.TestCase):
def test_a_branch_run_passes_the_recorded_version_and_the_released_branch(self) -> None:
lines, seen = _run(_environment(), _configuration(write_back={"require_push": True}, central=True))
self.assertEqual((seen["version"], seen["ctx"].branch, seen["ctx"].tag, seen["central_required"], seen["owner"], seen["repository_id"]), ("1.6.0-RC.1", "release/1.6", "", True, "Org", 7))
self.assertEqual(seen["policy"], WriteBackPolicy(require_push=True))
self.assertEqual((seen["ctx"].run, seen["ctx"].attempt, seen["ctx"].sha, seen["ctx"].repository), (50, 1, SHA, "Org/repo"))
self.assertIn("pushed", lines[0])
def test_a_tag_run_writes_to_the_configured_branch_and_binds_the_tag(self) -> None:
_, seen = _run(_environment("refs/tags/v1.6.0"), _configuration(tag_driven=True, write_back={"target_branch": "main"}))
self.assertEqual((seen["ctx"].branch, seen["ctx"].tag, seen["central_required"]), ("main", "v1.6.0", False))
def test_no_matching_opt_in_writes_nothing(self) -> None:
for environment, configuration in (
(_environment(), _configuration()),
(_environment("refs/heads/develop"), _configuration(write_back={})),
(_environment(), None),
):
lines, seen = _run(environment, configuration)
self.assertEqual(seen, {})
self.assertIn("nothing to write back", lines[0])
def test_incomplete_identity_and_foreign_forge_are_refused_before_any_read(self) -> None:
for overrides in ({"CI_EVENT_NAME": "pull_request"}, {"CI_SOURCE_REVISION": "abc"}, {"FORGE_TOKEN": ""}, {"GITHUB_SERVER_URL": "https://example.com"}, {"CI_RUN_ATTEMPT": ""}, {"CI_PLATFORM_REVISION": ""}, {"CI_EVENT_REF": "refs/pull/1/merge"}):
with self.subTest(overrides), self.assertRaises(DeliveryError):
finalize_version(_environment(**overrides))
def test_an_unproven_workflow_is_refused(self) -> None:
with self.assertRaises(DeliveryError):
_run(_environment(), _configuration(write_back={}), trusted=False)
def test_a_bundle_without_build_inputs_is_fatal(self) -> None:
with self.assertRaises(Fatal):
_run(_environment(), _configuration(write_back={}), artifacts={"library-linux-amd64": _artifact(None)})
def test_an_unfinished_release_run_is_not_yet_published(self) -> None:
with self.assertRaises(NotYetPublished):
_run(_environment(), _configuration(write_back={}), select_error=RunInProgressError("run 9 has not finished"))
class EntryPointTest(unittest.TestCase):
def test_the_command_is_registered_and_fails_closed_without_the_workflow_environment(self) -> None:
self.assertEqual(main(["finalize-version"], environment={}), 1)
if __name__ == "__main__":
unittest.main()