Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 42s
CI / tests-unit (push) Successful in 1m42s
CI / tests-integration (push) Successful in 1m47s
CI / tests-ui (push) Successful in 2m28s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m12s
The active-runtime assertion required process.versions.node to equal .nvmrc exactly, so any Node.js patch release broke `toolchain:check` and the act CI run even though package.json engines (>=26.10.0 <27) supports the newer runtime. Keep .nvmrc and the Docker base image exactly pinned for reproducibility (both still asserted), but validate the running runtime against the engines range instead. Verified: toolchain:check, lint, typecheck, i18n:check, hk:matrix:check and all 3391 tests pass.
74 lines
2.4 KiB
JavaScript
74 lines
2.4 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import { dirname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
const readProjectFile = (path) =>
|
|
readFileSync(resolve(projectRoot, path), "utf8");
|
|
|
|
const pinnedVersion = readProjectFile(".nvmrc").trim();
|
|
assert.match(
|
|
pinnedVersion,
|
|
/^\d+\.\d+\.\d+$/,
|
|
".nvmrc must pin an exact Node.js version",
|
|
);
|
|
|
|
const major = Number.parseInt(pinnedVersion.split(".")[0], 10);
|
|
const packageJson = JSON.parse(readProjectFile("package.json"));
|
|
|
|
assert.equal(
|
|
packageJson.engines?.node,
|
|
`>=${pinnedVersion} <${major + 1}`,
|
|
"package.json engines.node must match the .nvmrc release line",
|
|
);
|
|
assert.equal(
|
|
Number.parseInt(packageJson.devDependencies?.["@types/node"], 10),
|
|
major,
|
|
"@types/node must match the pinned Node.js major",
|
|
);
|
|
|
|
const nodeImages = [
|
|
...readProjectFile("Dockerfile").matchAll(
|
|
/^FROM\s+(?:--platform=\S+\s+)?node:([^\s]+)\s*/gim,
|
|
),
|
|
].map((match) => match[1]);
|
|
assert.ok(
|
|
nodeImages.length > 0,
|
|
"Dockerfile must declare a pinned Node.js base image",
|
|
);
|
|
for (const image of nodeImages) {
|
|
assert.equal(
|
|
image,
|
|
`${pinnedVersion}-alpine`,
|
|
"every Docker Node.js stage must match .nvmrc",
|
|
);
|
|
}
|
|
|
|
const cmpVersion = (a, b) => {
|
|
const pa = a.split(".").map((part) => Number.parseInt(part, 10));
|
|
const pb = b.split(".").map((part) => Number.parseInt(part, 10));
|
|
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
if (diff !== 0) return diff;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
// `.nvmrc` is the recommended version for reproducible local development and
|
|
// the exact Docker base image (both asserted above), but the *runtime* we run
|
|
// on may be any version the package.json engines range accepts. Requiring an
|
|
// exact patch match here would fail on every Node.js patch release, even when
|
|
// the version is explicitly supported.
|
|
if (!process.argv.includes("--static")) {
|
|
const active = process.versions.node;
|
|
const upperBound = `${major + 1}.0.0`;
|
|
assert.ok(
|
|
cmpVersion(active, pinnedVersion) >= 0 &&
|
|
cmpVersion(active, upperBound) < 0,
|
|
`the active Node.js runtime (${active}) must satisfy package.json engines.node (${packageJson.engines.node}); .nvmrc pins ${pinnedVersion} as the recommended version`,
|
|
);
|
|
}
|
|
|
|
console.log(`Node.js toolchain is aligned on ${pinnedVersion}`);
|