mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 09:39:25 +00:00
fix(release): keep two extended-stable months eligible (#154777)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
This commit is contained in:
parent
18d49c068e
commit
32fbb3c6f3
7 changed files with 58 additions and 36 deletions
|
|
@ -20,9 +20,9 @@ Read `extended-stable-backports.md`; a clean cherry-pick, green
|
|||
release checks, or a regenerated baseline does not by itself explain the
|
||||
maintenance risk.
|
||||
|
||||
Use this path only for the trailing completed month's `.33+` Gateway
|
||||
distribution: the `openclaw` npm package, official npm plugins, and matching
|
||||
Docker Gateway images. Treat
|
||||
Use this path only for a `.33+` Gateway distribution from either of the two
|
||||
trailing completed months: the `openclaw` npm package, official npm plugins,
|
||||
and matching Docker Gateway images. Treat
|
||||
`docs/reference/RELEASING.md`,
|
||||
`scripts/openclaw-npm-extended-stable-release.mjs`, and the release workflows
|
||||
on pinned current `main` as the exact command and validation contract.
|
||||
|
|
|
|||
|
|
@ -20,12 +20,12 @@ train. Continue an existing beta train with its next `beta.N` when appropriate,
|
|||
otherwise increment the highest stable/beta patch and start at `beta.1`.
|
||||
Prefer `-beta.N`, never new numeric-only beta suffixes.
|
||||
|
||||
| Track | Branch/version | Registry selector |
|
||||
| --------------- | -------------------------------------------------------------- | ---------------------------------------------------------------- |
|
||||
| Regular beta | `release/YYYY.M.PATCH`, `YYYY.M.PATCH-beta.N` | `beta` |
|
||||
| Regular stable | `release/YYYY.M.PATCH`, `YYYY.M.PATCH` | `beta` by default; intentional publication/promotion to `latest` |
|
||||
| Extended stable | `extended-stable/YYYY.M.33`, trailing completed month's `.33+` | `extended-stable` |
|
||||
| Development | moving main | not a release |
|
||||
| Track | Branch/version | Registry selector |
|
||||
| --------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
||||
| Regular beta | `release/YYYY.M.PATCH`, `YYYY.M.PATCH-beta.N` | `beta` |
|
||||
| Regular stable | `release/YYYY.M.PATCH`, `YYYY.M.PATCH` | `beta` by default; intentional publication/promotion to `latest` |
|
||||
| Extended stable | `extended-stable/YYYY.M.33`, either trailing completed month's `.33+` | `extended-stable` |
|
||||
| Development | moving main | not a release |
|
||||
|
||||
Use the release preparation controller before manual version edits:
|
||||
|
||||
|
|
|
|||
|
|
@ -11,15 +11,15 @@ read_when:
|
|||
OpenClaw exposes four user-facing update channels:
|
||||
|
||||
- stable: the promoted regular release on npm `latest`
|
||||
- extended-stable: the trailing completed month's `.33+` maintenance line on
|
||||
npm `extended-stable`
|
||||
- extended-stable: a `.33+` maintenance line from either of the two trailing
|
||||
completed months on npm `extended-stable`
|
||||
- beta: prerelease tags on npm `beta`
|
||||
- dev: the moving head of `main`
|
||||
|
||||
Extended-stable ships the trailing month's Gateway, official npm plugins, and
|
||||
Docker images without moving regular `latest` or `main` selectors. Each release
|
||||
also has a GitHub Release with shared validation evidence that is never marked
|
||||
Latest.
|
||||
Extended-stable ships a Gateway from either of the two trailing completed
|
||||
months, along with official npm plugins and Docker images, without moving
|
||||
regular `latest` or `main` selectors. Each release also has a GitHub Release
|
||||
with shared validation evidence that is never marked Latest.
|
||||
|
||||
Tideclaw alpha builds are a separate internal prerelease track (npm dist-tag `alpha`), covered under [NPM workflow inputs](#npm-workflow-inputs) and [Release test boxes](#release-test-boxes).
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ Tideclaw alpha builds are a separate internal prerelease track (npm dist-tag `al
|
|||
- Alpha/nightly builds use the next unreleased patch train and increment only `alpha.N` for repeated builds. Once that patch has a beta, new alpha builds move to the following patch.
|
||||
- npm versions are immutable: never delete, republish, or reuse a published tag. Cut the next prerelease number or the next monthly patch instead.
|
||||
- `latest` continues to follow the current regular/daily npm line. For core and every published official plugin, `beta` must always resolve to a version greater than or equal to `latest` under semver ordering; a same-train prerelease is older than its final release.
|
||||
- `extended-stable` means the supported trailing-month Gateway distribution, beginning at patch `33`; patch `34` and later are maintenance releases on that monthly line
|
||||
- `extended-stable` means a supported Gateway distribution from either trailing completed month, beginning at patch `33`; patch `34` and later are maintenance releases on that monthly line
|
||||
- Regular final and regular correction releases publish to npm `beta` by default; release operators can target `latest` explicitly, or promote a vetted beta build later
|
||||
- Gateway extended-stable publishes core, every npm-publishable official plugin,
|
||||
and its Docker images at one exact version; see the dedicated workflow below.
|
||||
|
|
@ -164,9 +164,10 @@ bytes still require their own qualification.
|
|||
For completed month `YYYY.M`, create `extended-stable/YYYY.M.33` and publish
|
||||
`.33+` from that branch. Tag, branch, checkout, package version, preflight, and
|
||||
validation must identify one commit. Before `.33`, protected `main` must contain
|
||||
a final version below patch `33` exactly one calendar month later, making the
|
||||
release the trailing completed month. Maintenance patches remain eligible only
|
||||
while that holds; the older line retires when `main` advances another month.
|
||||
a final version below patch `33` one or two calendar months later, making the
|
||||
release one of the two trailing completed months. Maintenance patches remain
|
||||
eligible only while that holds; the older line retires when `main` advances a
|
||||
third month.
|
||||
The shared publisher checks live `main` before dispatching publication children;
|
||||
each plugin checks it again immediately before npm publication, including
|
||||
trusted-main recovery. Saved qualification does not authorize a retired line.
|
||||
|
|
|
|||
|
|
@ -203,12 +203,19 @@ export function validateActiveExtendedStableLine(releaseVersion, mainPackageVers
|
|||
}
|
||||
const mainCalendarMonth = mainVersion.year * 12 + mainVersion.month;
|
||||
const releaseCalendarMonth = releaseVersionParsed.year * 12 + releaseVersionParsed.month;
|
||||
// Keep one active trailing-month line; advancing main another month retires the older line.
|
||||
if (mainCalendarMonth - releaseCalendarMonth !== 1) {
|
||||
const expectedYear = mainVersion.month === 1 ? mainVersion.year - 1 : mainVersion.year;
|
||||
const expectedMonth = mainVersion.month === 1 ? 12 : mainVersion.month - 1;
|
||||
// Keep both trailing completed months eligible so maintenance can finish shortly after
|
||||
// main enters a new month. Advancing main a third month retires the older line.
|
||||
const monthDifference = mainCalendarMonth - releaseCalendarMonth;
|
||||
if (monthDifference < 1 || monthDifference > 2) {
|
||||
const allowedMonths = [mainCalendarMonth - 1, mainCalendarMonth - 2]
|
||||
.map((calendarMonth) => {
|
||||
const year = Math.floor((calendarMonth - 1) / 12);
|
||||
const month = ((calendarMonth - 1) % 12) + 1;
|
||||
return `${year}.${month}`;
|
||||
})
|
||||
.join(" or ");
|
||||
throw new Error(
|
||||
`Extended-stable publishes only the trailing completed month: protected main ${mainPackageVersion} allows ${expectedYear}.${expectedMonth}.PATCH, not ${releaseVersion}. Retire the older line; publishing a retired line requires an explicit maintainer decision.`,
|
||||
`Extended-stable publishes only the two trailing completed months: protected main ${mainPackageVersion} allows ${allowedMonths}.PATCH, not ${releaseVersion}. Retire the older line; publishing a retired line requires an explicit maintainer decision.`,
|
||||
);
|
||||
}
|
||||
if (classifyReleaseTrain(mainVersion) !== "stable") {
|
||||
|
|
|
|||
|
|
@ -11,19 +11,21 @@ const nodeExecutable = resolveTestNodeExecPath();
|
|||
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
|
||||
|
||||
describe("extended-stable live publication eligibility", () => {
|
||||
it("retires the same qualified candidate when main advances, including the year boundary", () => {
|
||||
it("keeps both trailing months eligible across the year boundary", () => {
|
||||
expect(() => validateActiveExtendedStableLine("2026.12.34", "2027.1.1")).not.toThrow();
|
||||
expect(() => validateActiveExtendedStableLine("2026.12.34", "2027.2.1")).toThrow(
|
||||
"only the trailing completed month",
|
||||
expect(() => validateActiveExtendedStableLine("2026.12.34", "2027.2.1")).not.toThrow();
|
||||
expect(() => validateActiveExtendedStableLine("2026.12.34", "2027.3.1")).toThrow(
|
||||
"only the two trailing completed months",
|
||||
);
|
||||
});
|
||||
|
||||
it.skipIf(process.platform === "win32").each([
|
||||
{ mainVersion: "2026.8.1", expectedStatus: 42, expectedError: "" },
|
||||
{ mainVersion: "2026.9.1", expectedStatus: 42, expectedError: "" },
|
||||
{
|
||||
mainVersion: "2026.9.1",
|
||||
mainVersion: "2026.10.1",
|
||||
expectedStatus: 1,
|
||||
expectedError: "only the trailing completed month",
|
||||
expectedError: "only the two trailing completed months",
|
||||
},
|
||||
{
|
||||
mainVersion: "unavailable",
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ describe("extended-stable npm release request", () => {
|
|||
mainPackageVersion: "2026.7.2",
|
||||
};
|
||||
|
||||
it("accepts .33 and later patches only in the trailing completed month", () => {
|
||||
it("accepts .33 and later patches in either trailing completed month", () => {
|
||||
expect(validateExtendedStableNpmReleaseRequest(valid)).toEqual({
|
||||
extendedStable: true,
|
||||
releaseVersion: "2026.6.33",
|
||||
|
|
@ -237,6 +237,12 @@ describe("extended-stable npm release request", () => {
|
|||
packageVersion: "2026.6.34",
|
||||
}),
|
||||
).toMatchObject({ extendedStable: true, releaseVersion: "2026.6.34" });
|
||||
expect(
|
||||
validateExtendedStableNpmReleaseRequest({
|
||||
...valid,
|
||||
mainPackageVersion: "2026.8.1",
|
||||
}),
|
||||
).toMatchObject({ extendedStable: true, releaseVersion: "2026.6.33" });
|
||||
expect(
|
||||
validateExtendedStableNpmReleaseRequest({
|
||||
...valid,
|
||||
|
|
@ -252,12 +258,12 @@ describe("extended-stable npm release request", () => {
|
|||
});
|
||||
|
||||
it.each([
|
||||
["main two months ahead", "2026.8.1", "2026.7"],
|
||||
["main many months ahead", "2027.1.1", "2026.12"],
|
||||
["main a year-plus ahead", "2028.12.32", "2028.11"],
|
||||
])("rejects %s", (_label, mainPackageVersion, expectedMonth) => {
|
||||
["main three months ahead", "2026.9.1", "2026.8 or 2026.7"],
|
||||
["main many months ahead", "2027.1.1", "2026.12 or 2026.11"],
|
||||
["main a year-plus ahead", "2028.12.32", "2028.11 or 2028.10"],
|
||||
])("rejects %s", (_label, mainPackageVersion, expectedMonths) => {
|
||||
expect(() => validateExtendedStableNpmReleaseRequest({ ...valid, mainPackageVersion })).toThrow(
|
||||
`Extended-stable publishes only the trailing completed month: protected main ${mainPackageVersion} allows ${expectedMonth}.PATCH, not 2026.6.33. Retire the older line; publishing a retired line requires an explicit maintainer decision.`,
|
||||
`Extended-stable publishes only the two trailing completed months: protected main ${mainPackageVersion} allows ${expectedMonths}.PATCH, not 2026.6.33. Retire the older line; publishing a retired line requires an explicit maintainer decision.`,
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -480,7 +480,13 @@ describe("plugin npm extended-stable workflow", () => {
|
|||
toolingTrusted: true,
|
||||
candidateMoved: false,
|
||||
mainVersion: "2026.9.1",
|
||||
expectedFailure: "only the trailing completed month",
|
||||
},
|
||||
{
|
||||
publishTag: "extended-stable",
|
||||
toolingTrusted: true,
|
||||
candidateMoved: false,
|
||||
mainVersion: "2026.10.1",
|
||||
expectedFailure: "only the two trailing completed months",
|
||||
},
|
||||
{
|
||||
publishTag: "extended-stable",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue