Advance M7 workflows and release operations
This commit is contained in:
39
tools/web/check-rc-release-notes.mjs
Normal file
39
tools/web/check-rc-release-notes.mjs
Normal file
@@ -0,0 +1,39 @@
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const notesPath = path.join(repoRoot, "docs/web/RELEASE_NOTES.md");
|
||||
const notes = fs.readFileSync(notesPath, "utf8");
|
||||
const packageJson = JSON.parse(fs.readFileSync(path.join(repoRoot, "web/package.json"), "utf8"));
|
||||
const engine = JSON.parse(fs.readFileSync(path.join(repoRoot, "web/app/public/engine-manifest.json"), "utf8"));
|
||||
const ledger = JSON.parse(fs.readFileSync(path.join(repoRoot, "docs/status/parity-ledger.json"), "utf8"));
|
||||
|
||||
assert.match(notes, new RegExp(`^# Web Blender Modeler V1 ${packageJson.version.replaceAll(".", "\\.")} Release Notes`, "m"));
|
||||
assert.match(notes, new RegExp(`engine\\s+\`${engine.releaseId.replaceAll(".", "\\.")}\``));
|
||||
for (const capability of ["\.blend", "undo", "redo", "OffscreenCanvas", "single-thread", "pthread", "OPFS", "10M geometry", "8K textures", "SBOM"]) {
|
||||
assert.match(notes, new RegExp(capability, "i"), `release notes omit verified capability: ${capability}`);
|
||||
}
|
||||
for (const boundary of ["LOCAL_EXACT", "LOCAL_BOUNDED", "SERVER", "EXCLUDED", "Chromium-only", "not a browser port"]) {
|
||||
assert.ok(notes.includes(boundary), `release notes omit capability boundary: ${boundary}`);
|
||||
}
|
||||
const releaseReady = ledger.families.filter((family) => family.releaseStatus === "READY").length;
|
||||
const parityBlocked = ledger.families.filter((family) => family.parityStatus === "BLOCKED").length;
|
||||
assert.equal(releaseReady, 12);
|
||||
assert.equal(parityBlocked, 12);
|
||||
assert.ok(notes.includes(`All ${releaseReady} V1 family release slices are \`READY\``));
|
||||
assert.match(notes, new RegExp(`all ${parityBlocked} complete Blender 5\\.2 family parity states are\\s+\`BLOCKED\``));
|
||||
|
||||
const links = [...notes.matchAll(/\[[^\]]+\]\(([^)]+)\)/g)].map((match) => match[1]);
|
||||
assert.ok(links.length >= 5, "release notes do not link the capability and operations sources");
|
||||
for (const link of links) {
|
||||
assert.doesNotMatch(link, /^(?:https?:|\/)/, `release notes contain an external or absolute link: ${link}`);
|
||||
const source = link === "V1_SCOPE.md"
|
||||
? path.join(repoRoot, "docs/WEB_BLENDER_MODELER_V1_SCOPE.md")
|
||||
: link === "parity-ledger.json"
|
||||
? path.join(repoRoot, "docs/status/parity-ledger.json")
|
||||
: path.join(repoRoot, "docs/web", link);
|
||||
assert.ok(fs.statSync(source).isFile(), `release note link is unresolved: ${link}`);
|
||||
}
|
||||
process.stdout.write(`rc-release-notes-ok version=${packageJson.version} ready=${releaseReady} parityBlocked=${parityBlocked} links=${links.length}\n`);
|
||||
Reference in New Issue
Block a user