refactor(release): move the version-anchor package.json rewrite into the shared lib

Makes the re-anchor file mutation unit-testable alongside the anchor decision.
This commit is contained in:
gsxdsm
2026-07-24 23:01:11 -07:00
parent dba9746287
commit 330e4970f0
3 changed files with 49 additions and 15 deletions

View File

@@ -10,12 +10,16 @@ Regression context: v0.73.0 was cut on `release` while `main` stayed in the
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", () => {
@@ -82,3 +86,21 @@ test("isVersionAheadOfStable rejects releases at or below the newest stable", ()
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");
});

View File

@@ -14,6 +14,8 @@ and the dev checkout (`pnpm dev`, dashboard version badge) still reported the
last beta.
*/
import { existsSync, readFileSync, writeFileSync } from "node:fs";
/**
* Prerelease-aware semver comparison: returns <0, 0, >0.
* `1.2.3-beta.1` sorts BELOW `1.2.3`; numeric prerelease identifiers compare
@@ -91,6 +93,27 @@ export function evaluateBetaCycleAnchor({ cycleBase, latestStable }) {
return { stale, anchor: stale ? latestStable : cycleBase };
}
/**
* Point each package.json at `version`, skipping files already there or absent.
* Used to re-anchor the fixed group (plus the workspace root) on the shipped
* stable before `changeset pre enter`, which snapshots these versions into
* pre.json's `initialVersions` and derives every X.Y.Z-beta.N from them.
*
* @returns {string[]} the paths actually rewritten, so a dry-run can restore them.
*/
export function setPackageJsonVersions(paths, version) {
const rewritten = [];
for (const path of paths) {
if (!existsSync(path)) continue;
const pkg = JSON.parse(readFileSync(path, "utf8"));
if (pkg.version === version) continue;
pkg.version = version;
writeFileSync(path, JSON.stringify(pkg, null, 2) + "\n");
rewritten.push(path);
}
return rewritten;
}
/**
* Backstop applied to both channels: a release must be strictly newer than the
* newest published stable. Catches hand-edited pre.json, a back-merge resolved

View File

@@ -52,6 +52,7 @@ import {
evaluateBetaCycleAnchor,
isVersionAheadOfStable,
latestStableVersionFromTags,
setPackageJsonVersions,
} from "./lib/release-version-anchor.mjs";
import {
archivePointerLine,
@@ -418,24 +419,12 @@ function readFixedGroupPackageNames() {
* Returns the list of rewritten paths so a dry-run can restore them.
*/
function rewriteFixedGroupVersions(version) {
const rewritten = [];
const paths = ["package.json"];
for (const name of readFixedGroupPackageNames()) {
const dir = findPackageDir(name);
if (!dir) continue;
const pkgPath = join(dir, "package.json");
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
if (pkg.version === version) continue;
pkg.version = version;
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
rewritten.push(pkgPath);
if (dir) paths.push(join(dir, "package.json"));
}
const rootPkg = JSON.parse(readFileSync("package.json", "utf8"));
if (rootPkg.version !== version) {
rootPkg.version = version;
writeFileSync("package.json", JSON.stringify(rootPkg, null, 2) + "\n");
rewritten.push("package.json");
}
return rewritten;
return setPackageJsonVersions(paths, version);
}
/**