Files
Web_FreeCAD_Bitbybit/scripts/check-freecad-wasm-sdk-build-plan.mjs
wangdequan f64b78865c
Some checks failed
real-verification / chrome (push) Has been cancelled
real-verification / freecad-oracle (push) Has been cancelled
real-verification / wasm (push) Has been cancelled
feat: complete production naming and reference lifecycle gates
2026-08-14 10:10:30 -04:00

49 lines
4.5 KiB
JavaScript

import { readFile } from 'node:fs/promises'
import { resolve } from 'node:path'
import { execFile } from 'node:child_process'
import { promisify } from 'node:util'
const root = resolve(new URL('..', import.meta.url).pathname)
const plan = JSON.parse(await readFile(resolve(root, 'config/freecad-wasm-sdk-build-plan.json'), 'utf8'))
const fail = (message) => { throw new Error(`FreeCAD wasm SDK build plan: ${message}`) }
const lockedCommit = '0108fd4b4850cc46e625b60e53cea7a7bbe69f8d'
if (plan.schemaVersion !== 1 || plan.scope !== 'candidate-only-freecad-wasm-sdk-build') fail('unsupported schema or scope.')
if (plan.baseline?.freecadVersion !== '1.1.1' || plan.baseline?.sourceCommit !== lockedCommit || plan.baseline?.emscriptenVersion !== '3.1.69' || plan.baseline?.target !== 'wasm32-emscripten') fail('baseline is not locked to FreeCAD 1.1.1 and Emscripten 3.1.69 wasm32.')
if (plan.configuration?.productionPublication !== false) fail('candidate SDK build cannot publish production artifacts.')
if (plan.boundary?.freecadNamingBuildStatus !== 'production-linked' || plan.boundary?.exTsn02 !== 'completed' || plan.boundary?.systemExact !== false || plan.boundary?.workerLinked !== true || plan.boundary?.callbacks?.length !== 3) fail('production boundary must identify the linked callback-complete Worker while retaining non-exact system status.')
if (JSON.stringify(plan.requiredArchives) !== JSON.stringify(['FreeCADBase', 'FreeCADApp', 'Part', 'Python'])) fail('required archive list is incomplete or reordered.')
const expectedDependencies = [
['Qt6', '6.8.2', 'npm run build:qt6-freecad-wasm'],
['yaml-cpp', '0.8.0', 'npm run build:yaml-cpp-wasm'],
['ICU', '68.2', 'npm run build:icu-wasm'],
['CPython', '3.13.5', 'npm run build:cpython-wasm'],
['Xerces-C', '3.2.4', 'npm run build:xerces-c-wasm'],
['Boost', '1.83.0', 'npm run build:boost-wasm'],
]
if (JSON.stringify(plan.dependencyBuilds?.map(({ name, version, command }) => [name, version, command])) !== JSON.stringify(expectedDependencies)) fail('dependency build order, versions, or commands changed.')
for (const dependency of plan.dependencyBuilds) {
if (!Array.isArray(dependency.targetArchives) || dependency.targetArchives.length === 0) fail(`${dependency.name} has no target archive contract.`)
}
if (plan.dependencyBuilds.find(({ name }) => name === 'yaml-cpp')?.sourceCommit !== 'f7320141120f720aecc4c32be25586e7da9eb978') fail('yaml-cpp source commit is not locked.')
if (plan.dependencyBuilds.find(({ name }) => name === 'ICU')?.sourceSha256 !== 'c79193dee3907a2199b8296a93b52c5cb74332c26f3d167269487680d479d625') fail('ICU source hash is not locked.')
if (plan.dependencyBuilds.find(({ name }) => name === 'CPython')?.sourceSha256 !== '93e583f243454e6e9e4588ca2c2662206ad961659863277afcdb96801647d640') fail('CPython source hash is not locked.')
if (plan.dependencyBuilds.find(({ name }) => name === 'Xerces-C')?.sourceSha256 !== '075bc57940da0f9be6dd183c550c8ce0b9833e4550dc382048377a1a5e3b2bd9') fail('Xerces-C source hash is not locked.')
if (plan.dependencyBuilds.find(({ name }) => name === 'Boost')?.sourceSha256 !== '6478edfe2f3305127cffe8caf73ea0176c53769f4bf1585be237eb30798c3b8e') fail('Boost source hash is not locked.')
const sourceDir = resolve(root, plan.source.path)
const execFileAsync = promisify(execFile)
let sourceCommit = null
try {
sourceCommit = (await execFileAsync('git', ['-C', sourceDir, 'rev-parse', 'HEAD'])).stdout.trim()
} catch (error) {
fail(`cannot inspect source checkout: ${error instanceof Error ? error.message : String(error)}`)
}
if (sourceCommit !== lockedCommit) fail(`source checkout is ${sourceCommit}, expected ${lockedCommit}.`)
let dirty = ''
try { dirty = (await execFileAsync('git', ['-C', sourceDir, 'status', '--porcelain'])).stdout.trim() } catch (error) { fail(`cannot inspect source status: ${error instanceof Error ? error.message : String(error)}`) }
if (plan.source.requiredClean && dirty) fail('source checkout has uncommitted changes.')
const emcc = process.env.EMCC || 'emcc'
let emccVersion = ''
try { emccVersion = (await execFileAsync(emcc, ['--version'])).stdout.split('\n')[0].trim() } catch (error) { fail(`cannot inspect Emscripten: ${error instanceof Error ? error.message : String(error)}`) }
if (!emccVersion.includes('3.1.69')) fail(`Emscripten version is not 3.1.69: ${emccVersion}`)
console.log(JSON.stringify({ status: 'freecad-wasm-sdk-build-plan-pass', sourceCommit, sourceClean: dirty.length === 0, emcc: emccVersion, productionPublication: false, boundary: plan.boundary }, null, 2))