107 lines
4.3 KiB
JavaScript
107 lines
4.3 KiB
JavaScript
/*
|
|
FNXC:UpdateChannels 2026-07-24-09:40:
|
|
Guards the release version-anchor contract:
|
|
- after a stable ships, the next beta is based on THAT stable version;
|
|
- no release (either channel) may number at or below the newest published stable.
|
|
Regression context: v0.73.0 was cut on `release` while `main` stayed in the
|
|
0.72.0-anchored pre-mode cycle, so the next beta would have been v0.73.0-beta.7
|
|
(below the shipped v0.73.0) and `pnpm dev` on main still reported the beta.
|
|
*/
|
|
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
|
|
import {
|
|
compareReleaseVersions,
|
|
evaluateBetaCycleAnchor,
|
|
isVersionAheadOfStable,
|
|
latestStableVersionFromTags,
|
|
setPackageJsonVersions,
|
|
} from "../lib/release-version-anchor.mjs";
|
|
|
|
test("compareReleaseVersions ranks a prerelease below its stable", () => {
|
|
assert.ok(compareReleaseVersions("0.73.0-beta.6", "0.73.0") < 0);
|
|
assert.ok(compareReleaseVersions("0.73.0", "0.73.0-beta.6") > 0);
|
|
assert.equal(compareReleaseVersions("0.73.0", "0.73.0"), 0);
|
|
});
|
|
|
|
test("compareReleaseVersions compares numeric identifiers numerically", () => {
|
|
assert.ok(compareReleaseVersions("0.73.0-beta.9", "0.73.0-beta.10") < 0);
|
|
assert.ok(compareReleaseVersions("0.9.0", "0.73.0") < 0);
|
|
assert.ok(compareReleaseVersions("0.73.1", "0.73.0") > 0);
|
|
});
|
|
|
|
test("latestStableVersionFromTags ignores prerelease tags", () => {
|
|
const tags = [
|
|
"v0.72.0",
|
|
"v0.73.0",
|
|
"v0.73.0-beta.0",
|
|
"v0.73.0-beta.6",
|
|
"v0.74.0-beta.0",
|
|
"not-a-tag",
|
|
];
|
|
assert.equal(latestStableVersionFromTags(tags), "0.73.0");
|
|
assert.equal(latestStableVersionFromTags(tags.join("\n")), "0.73.0");
|
|
assert.equal(latestStableVersionFromTags(["v0.73.0-beta.1"]), null);
|
|
assert.equal(latestStableVersionFromTags([]), null);
|
|
});
|
|
|
|
test("a beta cycle anchored below a shipped stable is re-anchored on that stable", () => {
|
|
// The exact v0.73.0 shape: pre.json still snapshots the 0.72.0 cycle base.
|
|
assert.deepEqual(
|
|
evaluateBetaCycleAnchor({ cycleBase: "0.72.0", latestStable: "0.73.0" }),
|
|
{ stale: true, anchor: "0.73.0" },
|
|
);
|
|
});
|
|
|
|
test("a beta cycle already at or above the shipped stable is left alone", () => {
|
|
assert.deepEqual(
|
|
evaluateBetaCycleAnchor({ cycleBase: "0.73.0", latestStable: "0.73.0" }),
|
|
{ stale: false, anchor: "0.73.0" },
|
|
);
|
|
assert.deepEqual(
|
|
evaluateBetaCycleAnchor({ cycleBase: "0.74.0", latestStable: "0.73.0" }),
|
|
{ stale: false, anchor: "0.74.0" },
|
|
);
|
|
});
|
|
|
|
test("with no stable tag yet, no cycle is considered stale", () => {
|
|
assert.deepEqual(
|
|
evaluateBetaCycleAnchor({ cycleBase: "0.1.0", latestStable: null }),
|
|
{ stale: false, anchor: "0.1.0" },
|
|
);
|
|
});
|
|
|
|
test("isVersionAheadOfStable rejects releases at or below the newest stable", () => {
|
|
// The bug: the next beta of a stale cycle numbers beneath the shipped stable.
|
|
assert.equal(isVersionAheadOfStable("0.73.0-beta.7", "0.73.0"), false);
|
|
assert.equal(isVersionAheadOfStable("0.73.0", "0.73.0"), false);
|
|
assert.equal(isVersionAheadOfStable("0.72.9", "0.73.0"), false);
|
|
// Both channels' healthy shapes stay allowed.
|
|
assert.equal(isVersionAheadOfStable("0.73.1-beta.0", "0.73.0"), true);
|
|
assert.equal(isVersionAheadOfStable("0.74.0-beta.0", "0.73.0"), true);
|
|
assert.equal(isVersionAheadOfStable("0.74.0", "0.73.0"), true);
|
|
assert.equal(isVersionAheadOfStable("0.1.0", null), true);
|
|
});
|
|
|
|
test("setPackageJsonVersions re-anchors only the files that need it", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "fusion-anchor-test-"));
|
|
const root = join(dir, "package.json");
|
|
const cli = join(dir, "cli.package.json");
|
|
const missing = join(dir, "nope.package.json");
|
|
writeFileSync(root, JSON.stringify({ name: "root", version: "0.73.0-beta.6" }, null, 2) + "\n");
|
|
writeFileSync(cli, JSON.stringify({ name: "cli", version: "0.73.0" }, null, 2) + "\n");
|
|
|
|
const rewritten = setPackageJsonVersions([root, cli, missing], "0.73.0");
|
|
|
|
// Already-anchored and absent files are left alone; the stale one is rewritten.
|
|
assert.deepEqual(rewritten, [root]);
|
|
assert.equal(JSON.parse(readFileSync(root, "utf8")).version, "0.73.0");
|
|
assert.equal(JSON.parse(readFileSync(cli, "utf8")).version, "0.73.0");
|
|
// Unrelated fields survive the rewrite.
|
|
assert.equal(JSON.parse(readFileSync(root, "utf8")).name, "root");
|
|
});
|