diff --git a/scripts/installtests/build_release_assets_test.go b/scripts/installtests/build_release_assets_test.go index 78f73b83c4..5771f29b5b 100644 --- a/scripts/installtests/build_release_assets_test.go +++ b/scripts/installtests/build_release_assets_test.go @@ -1301,11 +1301,6 @@ func TestCurrentPrereleasePacketTracksInstallMetadata(t *testing.T) { if _, _, ok := strings.Cut(version, "-"); !ok { t.Fatalf("current prerelease %q has no stable target", version) } - comparisonVersion, ok := previousPrereleaseVersion(version) - if !ok { - comparisonVersion = previous - } - releaseNotesPath := repoFile("docs", "releases", "RELEASE_NOTES_v"+version+".md") changelogPath := repoFile("docs", "releases", "V6_CHANGELOG_v"+version+".md") @@ -1319,16 +1314,23 @@ func TestCurrentPrereleasePacketTracksInstallMetadata(t *testing.T) { "The rollback target is stable `v"+previous+"`", ) assertFileDoesNotContain(t, releaseNotesPath, "## Fixes") - comparisonSummary := "This changelog describes the changes since `v" + comparisonVersion + "`" if version == "6.4.0-rc.10" { - comparisonSummary = "The `v6.4.0-rc.9` release staged an immutable draft, tag, and exact-version artifacts but did not activate publicly." + assertFileContainsAllNormalized(t, changelogPath, + "The `v6.4.0-rc.9` release staged an immutable draft, tag, and exact-version artifacts but did not activate publicly.") + } else { + content, err := os.ReadFile(changelogPath) + if err != nil { + t.Fatalf("read %s: %v", changelogPath, err) + } + if !prereleaseChangelogHasSupportedBase(string(content), version, previous) { + t.Fatalf("%s must describe changes since the previous numbered prerelease or stable v%s", changelogPath, previous) + } } assertFileContainsAllNormalized(t, changelogPath, "Version: `v"+version+"`", "Previous stable: `v"+previous+"`", "Rollback target: `v"+previous+"`", "Promotion path: ", - comparisonSummary, "Windows signing decision: prereleases publish checksum- and detached-signature-verified Windows agents without Authenticode", "Mobile decision: ", "no companion mobile build or store rollout is required", @@ -4952,6 +4954,44 @@ func TestCommittedReleaseVisualSidecarsCarrySelectionEvidence(t *testing.T) { } } +// Metadata defaults to the previous numbered prerelease. The release train can +// explicitly select the previous stable for a cumulative changelog instead. +func prereleaseChangelogHasSupportedBase(content, version, previousStable string) bool { + matches := regexp.MustCompile("This changelog describes the changes since `v([^`]+)`").FindAllStringSubmatch(normalizedInstallTestWhitespace(content), -1) + if len(matches) != 1 { + return false + } + base := matches[0][1] + if base == previousStable { + return true + } + previous, ok := previousPrereleaseVersion(version) + return ok && base == previous +} + +func TestPrereleaseChangelogSupportsIncrementalAndCumulativeBases(t *testing.T) { + for _, tc := range []struct { + name, version, content string + want bool + }{ + {"incremental beta", "6.6.0-beta.3", "This changelog describes the changes since `v6.6.0-beta.2`", true}, + {"cumulative beta", "6.6.0-beta.3", "This changelog describes the changes since\n`v6.5.0`", true}, + {"incremental candidate", "6.6.0-rc.2", "This changelog describes the changes since `v6.6.0-rc.1`", true}, + {"first beta", "6.6.0-beta.1", "This changelog describes the changes since `v6.5.0`", true}, + {"unrelated stable", "6.6.0-beta.3", "This changelog describes the changes since `v6.4.0`", false}, + {"older beta", "6.6.0-beta.3", "This changelog describes the changes since `v6.6.0-beta.1`", false}, + {"other stage", "6.6.0-rc.2", "This changelog describes the changes since `v6.6.0-beta.1`", false}, + {"missing comparison", "6.6.0-beta.3", "## Changes", false}, + {"conflicting comparisons", "6.6.0-beta.3", "This changelog describes the changes since `v6.5.0`\nThis changelog describes the changes since `v6.6.0-beta.2`", false}, + } { + t.Run(tc.name, func(t *testing.T) { + if got := prereleaseChangelogHasSupportedBase(tc.content, tc.version, "6.5.0"); got != tc.want { + t.Fatalf("supported base = %v, want %v", got, tc.want) + } + }) + } +} + func assertFileContainsAllNormalized(t *testing.T, path string, required ...string) { t.Helper() content, err := os.ReadFile(path) diff --git a/scripts/installtests/install_docker_sh_test.go b/scripts/installtests/install_docker_sh_test.go index d1fe60a96c..000bbcc8b8 100644 --- a/scripts/installtests/install_docker_sh_test.go +++ b/scripts/installtests/install_docker_sh_test.go @@ -301,8 +301,8 @@ func previousPrereleaseVersion(version string) (string, bool) { return "", false } -// The release train cuts several betas before its candidate. The second beta's changelog -// is written as the changes since the first, so the checks that read it must expect that. +// This predecessor is the metadata tool's default comparison base. A cumulative +// changelog can explicitly compare with the previous stable instead. func TestPreviousPrereleaseVersionFollowsItsOwnStage(t *testing.T) { for _, tc := range []struct { version, want string