mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
fix(release): let alpha tags publish from their exact changelog heading
Shipped alpha tags carry a dedicated ## X-alpha.N heading with no base section (see v2026.6.20-alpha.1's tagged CHANGELOG.md); the renderer and candidate provenance now prefer that dedicated heading for alpha and correction tags while beta/stable remain pinned to the stable base section per #103222.
This commit is contained in:
@@ -8,7 +8,7 @@ import { fileURLToPath } from "node:url";
|
||||
import { stripLeadingPackageManagerSeparator } from "./lib/arg-utils.mjs";
|
||||
import { readBoundedResponseText } from "./lib/bounded-response.mjs";
|
||||
import {
|
||||
correctionVersionForTag,
|
||||
dedicatedSectionVersionForTag,
|
||||
extractChangelogReleaseSections,
|
||||
extractChangelogSection,
|
||||
formatShippedBaselineExclusions,
|
||||
@@ -489,18 +489,19 @@ export function validateCandidateChangelogProvenance({
|
||||
isAncestor = gitIsAncestor,
|
||||
loadShippedBaseline = loadCandidateShippedBaseline,
|
||||
}) {
|
||||
// Validate the same section the renderer publishes: correction tags may
|
||||
// carry their own heading, and alpha tags may fall back to Unreleased.
|
||||
// Validate the same section the renderer publishes: alpha and correction
|
||||
// tags may carry their own heading, and alpha tags may fall back to
|
||||
// Unreleased.
|
||||
let section;
|
||||
let sectionVersion = version;
|
||||
let usesAlphaUnreleasedFallback = false;
|
||||
const correctionVersion = correctionVersionForTag(tag);
|
||||
if (correctionVersion && correctionVersion !== version) {
|
||||
const dedicatedVersion = dedicatedSectionVersionForTag(tag);
|
||||
if (dedicatedVersion && dedicatedVersion !== version) {
|
||||
try {
|
||||
section = extractChangelogSection(changelog, correctionVersion);
|
||||
sectionVersion = correctionVersion;
|
||||
section = extractChangelogSection(changelog, dedicatedVersion);
|
||||
sectionVersion = dedicatedVersion;
|
||||
} catch {
|
||||
// The correction has no dedicated section; validate the base section.
|
||||
// No dedicated section; validate the base section.
|
||||
}
|
||||
}
|
||||
if (section === undefined) {
|
||||
|
||||
@@ -230,24 +230,25 @@ function compactReleaseNotes(section, repository, tag) {
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
export function correctionVersionForTag(tag) {
|
||||
// Numeric-correction tags (vX-N) may carry their own changelog heading;
|
||||
// alpha/beta prerelease tags never do.
|
||||
export function dedicatedSectionVersionForTag(tag) {
|
||||
// Correction (vX-N) and alpha tags may carry their own exact changelog
|
||||
// heading; beta and stable bodies must come from the stable base section.
|
||||
const taggedVersion = tag.replace(/^v/u, "");
|
||||
const isCorrection =
|
||||
/-[1-9][0-9]*$/u.test(taggedVersion) && !/-(?:alpha|beta)\.[1-9][0-9]*$/u.test(taggedVersion);
|
||||
return isCorrection ? taggedVersion : undefined;
|
||||
if (/-beta\.[1-9][0-9]*$/u.test(taggedVersion)) {
|
||||
return undefined;
|
||||
}
|
||||
return /-(?:alpha\.)?[1-9][0-9]*$/u.test(taggedVersion) ? taggedVersion : undefined;
|
||||
}
|
||||
|
||||
export function releaseNotesSectionForTag(changelog, version, tag) {
|
||||
// Correction tags prefer their own exact heading when the changelog carries
|
||||
// one; otherwise they fall back to the base version.
|
||||
const correctionVersion = correctionVersionForTag(tag);
|
||||
if (correctionVersion && correctionVersion !== version) {
|
||||
// Alpha and correction tags prefer their own exact heading when the
|
||||
// changelog carries one; otherwise they fall back to the base version.
|
||||
const dedicatedVersion = dedicatedSectionVersionForTag(tag);
|
||||
if (dedicatedVersion && dedicatedVersion !== version) {
|
||||
try {
|
||||
return extractChangelogSection(changelog, correctionVersion);
|
||||
return extractChangelogSection(changelog, dedicatedVersion);
|
||||
} catch {
|
||||
// The correction has no dedicated section; use the base version below.
|
||||
// No dedicated section; use the base version below.
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -239,6 +239,33 @@ describe("GitHub release-note rendering", () => {
|
||||
).toThrow("cannot be compacted without a complete contribution record");
|
||||
});
|
||||
|
||||
it("prefers an alpha tag's exact changelog heading over the Unreleased fallback", () => {
|
||||
// Shipped alpha tags carry their own heading with no base section,
|
||||
// matching the tagged CHANGELOG.md shape of v2026.6.20-alpha.1.
|
||||
const changelog = [
|
||||
"# Changelog",
|
||||
"",
|
||||
"## 2026.7.1-alpha.2",
|
||||
"",
|
||||
"- Alpha-only fix.",
|
||||
"",
|
||||
"## 2026.6.11",
|
||||
"",
|
||||
"- Previous release.",
|
||||
"",
|
||||
].join("\n");
|
||||
const rendered = renderGithubReleaseNotes({
|
||||
changelog,
|
||||
version,
|
||||
tag: "v2026.7.1-alpha.2",
|
||||
repository,
|
||||
});
|
||||
|
||||
expect(rendered.body).toContain("## 2026.7.1-alpha.2");
|
||||
expect(rendered.body).toContain("Alpha-only fix.");
|
||||
expect(rendered.body).not.toContain("Previous release.");
|
||||
});
|
||||
|
||||
it("permits the Unreleased fallback only for alpha tags", () => {
|
||||
const changelog = changelogFor("- **PR #123** fix: example.").replace(
|
||||
"## 2026.7.1",
|
||||
|
||||
Reference in New Issue
Block a user