Prepare v6.0.2 release
Some checks are pending
Build and Test / Secret Scan (push) Waiting to run
Build and Test / Frontend & Backend (push) Waiting to run

This commit is contained in:
rcourtman 2026-07-04 23:19:42 +01:00
parent d029e4dc42
commit c0ae794dc9
13 changed files with 110 additions and 36 deletions

View file

@ -6,7 +6,7 @@ set -euo pipefail
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
DOCKER_IMAGE_REPO="${DOCKER_IMAGE_REPO:-rcourtman/pulse}"
CANONICAL_DEFAULT_PULSE_VERSION="6.0.1"
CANONICAL_DEFAULT_PULSE_VERSION="6.0.2"
resolve_default_pulse_version() {
if [ -n "${PULSE_IMAGE_VERSION:-}" ]; then

View file

@ -673,6 +673,9 @@ func TestDeploymentDefaultsPinVersionedImagesAndHelmDocsChecksum(t *testing.T) {
t.Fatalf("Helm Chart.yaml must pin the governed release version, missing %s:\n%s", needle, chart)
}
}
if previous, ok := previousStablePatchVersion(version); ok && strings.Contains(chart, "v"+previous) {
t.Fatalf("Helm Chart.yaml must not retain the previous stable patch tag v%s:\n%s", previous, chart)
}
chartReadmeBytes, err := os.ReadFile(repoFile("deploy", "helm", "pulse", "README.md"))
if err != nil {
@ -688,6 +691,9 @@ func TestDeploymentDefaultsPinVersionedImagesAndHelmDocsChecksum(t *testing.T) {
t.Fatalf("Helm README.md must reflect the governed release version, missing %s:\n%s", needle, chartReadme)
}
}
if previous, ok := previousStablePatchVersion(version); ok && strings.Contains(chartReadme, previous) {
t.Fatalf("Helm README.md must not retain the previous stable patch version %s:\n%s", previous, chartReadme)
}
helmPagesBytes, err := os.ReadFile(repoFile(".github", "workflows", "helm-pages.yml"))
if err != nil {

View file

@ -1,9 +1,11 @@
package installtests
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"testing"
)
@ -25,6 +27,21 @@ func isPrereleaseVersion(version string) bool {
return strings.Contains(version, "-")
}
func previousStablePatchVersion(version string) (string, bool) {
if isPrereleaseVersion(version) {
return "", false
}
parts := strings.Split(version, ".")
if len(parts) != 3 {
return "", false
}
patch, err := strconv.Atoi(parts[2])
if err != nil || patch <= 0 {
return "", false
}
return fmt.Sprintf("%s.%s.%d", parts[0], parts[1], patch-1), true
}
func TestInstallDockerScriptUsesConfiguredImageRepoDefault(t *testing.T) {
workDir := t.TempDir()
version := currentReleaseVersion(t)
@ -105,6 +122,9 @@ func TestRepoDockerComposeDefaultPinsCurrentVersion(t *testing.T) {
if !isPrereleaseVersion(version) && version != "6.0.0" && strings.Contains(text, "rcourtman/pulse:6.0.0") {
t.Fatalf("stable patch repo docker-compose.yml must move off the initial GA image tag:\n%s", text)
}
if previous, ok := previousStablePatchVersion(version); ok && strings.Contains(text, "rcourtman/pulse:"+previous) {
t.Fatalf("repo docker-compose.yml must not retain the previous stable patch image tag %s:\n%s", previous, text)
}
if strings.Contains(text, ":latest") {
t.Fatalf("repo docker-compose.yml must not default to a floating latest tag:\n%s", text)
}
@ -130,6 +150,9 @@ func TestInstallDockerScriptFallbackPinsCurrentVersion(t *testing.T) {
if !isPrereleaseVersion(version) && version != "6.0.0" && strings.Contains(text, `CANONICAL_DEFAULT_PULSE_VERSION="6.0.0"`) {
t.Fatalf("stable patch install-docker.sh fallback must move off the initial GA image tag:\n%s", text)
}
if previous, ok := previousStablePatchVersion(version); ok && strings.Contains(text, `CANONICAL_DEFAULT_PULSE_VERSION="`+previous+`"`) {
t.Fatalf("install-docker.sh fallback must not retain the previous stable patch version %s:\n%s", previous, text)
}
}
func runInstallDockerScript(t *testing.T, workDir string, envVars ...string) {

View file

@ -111,61 +111,61 @@ class ResolveReleasePromotionTest(unittest.TestCase):
def test_stable_patch_hotfix_can_omit_promoted_prerelease(self) -> None:
metadata = resolver.resolve_metadata(
version="6.0.1",
version="6.0.2",
promoted_from_tag_input="",
rollback_version_input="6.0.0",
rollback_version_input="6.0.1",
ga_date_input="",
v5_eos_date_input="",
hotfix_exception=True,
hotfix_reason_input="Patch release for v6.0.0 upgrade and monitoring fixes.",
hotfix_reason_input="Patch release for v6.0.1 agent upgrade recovery.",
release_notes_input="",
tag_exists_fn=lambda tag: tag == "v6.0.0",
tag_exists_fn=lambda tag: tag == "v6.0.1",
)
self.assertEqual(metadata["promoted_from_tag"], "")
self.assertEqual(metadata["rollback_tag"], "v6.0.0")
self.assertEqual(metadata["rollback_command"], "./scripts/install.sh --version v6.0.0")
self.assertEqual(metadata["rollback_tag"], "v6.0.1")
self.assertEqual(metadata["rollback_command"], "./scripts/install.sh --version v6.0.1")
self.assertEqual(metadata["hotfix_exception"], "true")
self.assertEqual(
metadata["hotfix_reason"],
"Patch release for v6.0.0 upgrade and monitoring fixes.",
"Patch release for v6.0.1 agent upgrade recovery.",
)
self.assertEqual(metadata["soak_hours"], "")
def test_stable_patch_without_promoted_tag_requires_hotfix_exception(self) -> None:
with self.assertRaisesRegex(ValueError, "Stable promotion requires promoted_from_tag"):
resolver.resolve_metadata(
version="6.0.1",
version="6.0.2",
promoted_from_tag_input="",
rollback_version_input="6.0.0",
rollback_version_input="6.0.1",
ga_date_input="",
v5_eos_date_input="",
hotfix_exception=False,
hotfix_reason_input="",
release_notes_input="",
tag_exists_fn=lambda tag: tag == "v6.0.0",
tag_exists_fn=lambda tag: tag == "v6.0.1",
)
def test_stable_patch_hotfix_without_promoted_tag_requires_reason(self) -> None:
with self.assertRaisesRegex(ValueError, "hotfix_reason is required"):
resolver.resolve_metadata(
version="6.0.1",
version="6.0.2",
promoted_from_tag_input="",
rollback_version_input="6.0.0",
rollback_version_input="6.0.1",
ga_date_input="",
v5_eos_date_input="",
hotfix_exception=True,
hotfix_reason_input="",
release_notes_input="",
tag_exists_fn=lambda tag: tag == "v6.0.0",
tag_exists_fn=lambda tag: tag == "v6.0.1",
)
def test_stable_hotfix_requires_reason(self) -> None:
with self.assertRaisesRegex(ValueError, "hotfix_reason is required"):
resolver.resolve_metadata(
version="6.0.1",
promoted_from_tag_input="6.0.1-rc.1",
rollback_version_input="6.0.0",
version="6.0.2",
promoted_from_tag_input="6.0.2-rc.1",
rollback_version_input="6.0.1",
ga_date_input="",
v5_eos_date_input="",
hotfix_exception=True,
@ -181,9 +181,9 @@ class ResolveReleasePromotionTest(unittest.TestCase):
def test_stable_rejects_short_soak_without_hotfix(self) -> None:
with self.assertRaisesRegex(ValueError, "hours of prerelease soak"):
resolver.resolve_metadata(
version="6.0.1",
promoted_from_tag_input="6.0.1-rc.1",
rollback_version_input="6.0.0",
version="6.0.2",
promoted_from_tag_input="6.0.2-rc.1",
rollback_version_input="6.0.1",
ga_date_input="",
v5_eos_date_input="",
hotfix_exception=False,