mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
fix(release): bind forward 6.4.4 checkpoint to release train
The held regression candidate needs an honest forward beta above published 6.4.3-rc.1. Bind only 6.4.4 to release/v6.4 without capturing patch 40 or weakening candidate checks. Exercise the actual release and rehearsal branch-policy shell and retain historical rollback mapping.
Change-source: pulse-maintainer
(cherry picked from commit 64dba483d0)
This commit is contained in:
@@ -23,6 +23,11 @@
|
||||
"prerelease_branch": "release/v6.4",
|
||||
"stable_branch": "release/v6.4"
|
||||
},
|
||||
{
|
||||
"version_prefix": "6.4.4",
|
||||
"prerelease_branch": "release/v6.4",
|
||||
"stable_branch": "release/v6.4"
|
||||
},
|
||||
{
|
||||
"version_prefix": "6.5.",
|
||||
"prerelease_branch": "release/v6.5",
|
||||
|
||||
@@ -287,6 +287,19 @@ without the other lanes changing the candidate underneath it.
|
||||
moving `main` can no longer invalidate the compiler's exact-SHA binding
|
||||
between dispatch and compilation, which is what failed run 33579042375.
|
||||
Earlier `6.4.x` versions keep their historical `main` mapping.
|
||||
8. The forward regression checkpoint `v6.4.4-beta.1` uses the same
|
||||
`release/v6.4` line, with an explicit `6.4.4` mapping for beta, RC and
|
||||
eventual stable. This is a maturity reset, not new feature scope: a
|
||||
`6.4.3-beta.N` would sort below the published `v6.4.3-rc.1`.
|
||||
`v6.4.4-beta.1` advances both that preview and stable `v6.4.1`;
|
||||
`v6.4.1` remains the rollback target. Later qualification proceeds through
|
||||
`v6.4.4-rc.N` and exact same-version stable promotion, including a fresh
|
||||
72-hour clean RC soak. Beta time does not count. Mapping is preparation,
|
||||
not readiness or publication authority: failed candidate checks still
|
||||
require repair or an evidence-based disposition under the existing gates.
|
||||
Land the mapping and resolver contract on canonical main and backport it
|
||||
to the release line before taking a fresh bound packet. Unlisted patches
|
||||
and new product work retain their existing mapping and scope.
|
||||
|
||||
## Paid Pro Artifact Lineage
|
||||
|
||||
|
||||
@@ -442,7 +442,18 @@ def legacy_release_line_for_version(
|
||||
reverse=True,
|
||||
)
|
||||
for line in legacy_release_lines:
|
||||
if normalized_version.startswith(line["version_prefix"]):
|
||||
prefix = line["version_prefix"]
|
||||
# A complete patch version binds only that version, not e.g. 6.4.40.
|
||||
# Trailing-dot prefixes continue to bind the whole minor/major line.
|
||||
if prefix.endswith("."):
|
||||
matches = normalized_version.startswith(prefix)
|
||||
else:
|
||||
matches = (
|
||||
normalized_version == prefix
|
||||
or normalized_version.startswith(prefix + "-")
|
||||
or normalized_version.startswith(prefix + "+")
|
||||
)
|
||||
if matches:
|
||||
return line
|
||||
return None
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import tempfile
|
||||
import textwrap
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -239,6 +244,46 @@ class ControlPlaneAuditTest(unittest.TestCase):
|
||||
"pulse/release-5.1.25",
|
||||
)
|
||||
|
||||
def test_forward_patch_train_uses_actual_control_plane(self) -> None:
|
||||
for version in ("6.4.4-beta.1", "v6.4.4-beta.2", "6.4.4-rc.1",
|
||||
"6.4.4", "v6.4.4+build.1", "6.4.3-rc.1", "6.4.3"):
|
||||
with self.subTest(version=version):
|
||||
self.assertEqual(release_branch_for_version(version), "release/v6.4")
|
||||
for version in ("6.4.1", "6.4.2", "6.4.5-beta.1", "6.4.40-beta.1",
|
||||
"6.4.30", "6.3.20", "6.6.0-beta.1"):
|
||||
with self.subTest(version=version):
|
||||
self.assertEqual(release_branch_for_version(version), "main")
|
||||
self.assertEqual(release_branch_for_version("6.5.10-beta.1"), "release/v6.5")
|
||||
|
||||
def test_forward_patch_workflow_branch_contract(self) -> None:
|
||||
# Execute the real branch-policy shell only, never dispatch a workflow.
|
||||
for workflow in ("create-release.yml", "release-dry-run.yml"):
|
||||
content = (REPO_ROOT / ".github/workflows" / workflow).read_text()
|
||||
match = re.search(
|
||||
r"(?ms)^ - name: Resolve required release branch\n"
|
||||
r".*?^ run: \|\n((?: [^\n]*\n|\n)+)", content
|
||||
)
|
||||
self.assertIsNotNone(match)
|
||||
script = textwrap.dedent(match.group(1))
|
||||
for branch in ("main", "release/v6.4"):
|
||||
with self.subTest(workflow=workflow, branch=branch), tempfile.TemporaryDirectory() as tmp:
|
||||
output = os.path.join(tmp, "output")
|
||||
result = subprocess.run(
|
||||
["bash", "-euo", "pipefail", "-c", script],
|
||||
cwd=REPO_ROOT, capture_output=True, text=True,
|
||||
env={**os.environ, "GITHUB_OUTPUT": output,
|
||||
"VERSION_INPUT": "6.4.4-beta.1",
|
||||
"WORKFLOW_OUTPUT_1": "6.4.4-beta.1",
|
||||
"WORKFLOW_OUTPUT_2": branch},
|
||||
)
|
||||
rejects = workflow == "create-release.yml" and branch == "main"
|
||||
self.assertEqual(result.returncode, 1 if rejects else 0, result.stderr)
|
||||
if rejects:
|
||||
self.assertIn("must run from release/v6.4", result.stdout)
|
||||
else:
|
||||
self.assertRegex(Path(output).read_text(),
|
||||
r"^required_branch<<([^\n]+)\nrelease/v6.4\n\1\n$")
|
||||
|
||||
def test_audit_flags_stale_active_target(self) -> None:
|
||||
report = audit_control_plane_payload(
|
||||
VALID_PAYLOAD,
|
||||
|
||||
Reference in New Issue
Block a user