diff --git a/docs/release-control/control_plane.json b/docs/release-control/control_plane.json index 01c133a8fd..ce5fb0a5a0 100644 --- a/docs/release-control/control_plane.json +++ b/docs/release-control/control_plane.json @@ -28,6 +28,11 @@ "prerelease_branch": "release/v6.4", "stable_branch": "release/v6.4" }, + { + "version_prefix": "6.4.5", + "prerelease_branch": "release/v6.4", + "stable_branch": "release/v6.4" + }, { "version_prefix": "6.5.", "prerelease_branch": "release/v6.5", diff --git a/docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md b/docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md index 1c9c33f54f..2e1396ce51 100644 --- a/docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md +++ b/docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md @@ -307,6 +307,15 @@ without the other lanes changing the candidate underneath it. to the release line before taking a fresh bound packet. Unlisted patches and new product work retain their existing mapping and scope. +9. The following reliability patch `v6.4.5` also uses `release/v6.4`, + explicitly mapped for beta, RC and stable. It remains separate from the + selected `v6.4.4` candidates: this mapping does not change their source, + version or qualification. Land the mapping and resolver tests on main, + then adapt them to the release line at the following patch checkpoint + before selecting a `v6.4.5` candidate. Unlisted patches still use their + existing branch policy. Normal qualification, checkpoint spacing and + exact-RC soak requirements remain unchanged. + ## Paid Pro Artifact Lineage 1. Customer-facing private Pulse Pro archives and private Pulse Pro Docker images diff --git a/scripts/release_control/control_plane_audit_test.py b/scripts/release_control/control_plane_audit_test.py index 4b4a2c8c33..a8f37ad9ed 100644 --- a/scripts/release_control/control_plane_audit_test.py +++ b/scripts/release_control/control_plane_audit_test.py @@ -246,10 +246,12 @@ class ControlPlaneAuditTest(unittest.TestCase): 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"): + "6.4.4", "v6.4.4+build.1", "6.4.3-rc.1", "6.4.3", + "6.4.5-beta.1", "v6.4.5-beta.2", "6.4.5-rc.1", + "6.4.5", "v6.4.5+build.1"): 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", + for version in ("6.4.1", "6.4.2", "6.4.6-beta.1", "6.4.50-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") @@ -265,24 +267,25 @@ class ControlPlaneAuditTest(unittest.TestCase): ) 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$") + for version in ("6.4.4-beta.1", "6.4.5-beta.1", "6.4.5-rc.1", "6.4.5"): + for branch in ("main", "release/v6.4"): + with self.subTest(workflow=workflow, branch=branch, version=version), 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": version, + "WORKFLOW_OUTPUT_1": version, + "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(