Pin the Node toolchain, remove runtime npm repair, make CI and E2E truthful
Template tests / tests (pull_request) Failing after 1m26s
Template tests / tests (pull_request) Failing after 1m26s
Phase 0 of the improvement plan (ai_prompts/prompt4.md): make the baseline reproducible and stop the test runner from masking real failures. - Pin Node >= 22.12 (engines + .nvmrc + engine-strict); every entry point fails fast with clear guidance instead of dying late with ERR_REQUIRE_ESM inside the packaging dependency graph. - electron-launcher.js is diagnostics-only: all runtime npm install/rebuild/ repair paths are removed. npm ci on the pinned toolchain is the only supported install path (README + GETTING_STARTED updated). - Refuse to silently launch unsandboxed on Linux: --no-sandbox now requires an explicit STEPFORGE_ALLOW_NO_SANDBOX/ELECTRON_DISABLE_SANDBOX opt-in and is otherwise a hard error with actionable fixes; user-namespace sandboxing is detected and preferred. - Click-capture E2E no longer converts startup crashes into "SKIPPED": the only allowed skip is the upfront absence of a display server. A missing shared library or crash now fails with the startup log. Same guard added to the startup smoke check. - GitHub CI: run on pull_request, pin Node from .nvmrc, drop the macOS matrix entry (not a support target), and audit production and full dependency trees as separate signals. Gitea CI: pull_request trigger + pinned Node. - Refresh package-lock on Node 22/npm 10 and remediate the form-data and undici advisories (npm audit: 0 vulnerabilities, prod and full tree). - Stop tracking generated machine-specific build reports (build/build_report.md, build/artifacts_manifest.json). Verified: 203 unit tests pass; repo-structure, startup-smoke, unit-workflows, sample-artifacts, and build-release checks pass locally with a real Electron launch. The click self-test now truthfully reports the pre-existing Linux arm/debounce capture failures (also red on Gitea CI main run 177) instead of hiding behind SKIPPED; that defect is scheduled for the capture-fix PR. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
'use strict';
|
||||
|
||||
// Hard prerequisite check for the supported Node toolchain.
|
||||
//
|
||||
// The locked dependency graph (notably the electron-builder packaging
|
||||
// toolchain) requires Node >= 22.12. Older Nodes fail late with confusing
|
||||
// errors (ERR_REQUIRE_ESM deep inside dependencies) instead of a clear
|
||||
// message, so every entry point calls this first.
|
||||
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
function parseVersion(version) {
|
||||
const match = /^v?(\d+)\.(\d+)\.(\d+)/.exec(String(version).trim());
|
||||
if (!match) return null;
|
||||
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
||||
}
|
||||
|
||||
function compareVersions(a, b) {
|
||||
for (let i = 0; i < 3; i += 1) {
|
||||
if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function requiredNodeVersion(projectRoot = path.join(__dirname, '..')) {
|
||||
const pkg = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
|
||||
const range = pkg.engines && pkg.engines.node ? String(pkg.engines.node) : null;
|
||||
if (!range) return null;
|
||||
const match = /(\d+\.\d+\.\d+)/.exec(range);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
function checkNodeVersion({
|
||||
currentVersion = process.versions.node,
|
||||
projectRoot = path.join(__dirname, '..'),
|
||||
} = {}) {
|
||||
const required = requiredNodeVersion(projectRoot);
|
||||
if (!required) return { ok: true, required: null, current: currentVersion };
|
||||
|
||||
const current = parseVersion(currentVersion);
|
||||
const minimum = parseVersion(required);
|
||||
if (!current || !minimum) return { ok: true, required, current: currentVersion };
|
||||
|
||||
return {
|
||||
ok: compareVersions(current, minimum) >= 0,
|
||||
required,
|
||||
current: currentVersion,
|
||||
};
|
||||
}
|
||||
|
||||
function assertSupportedNode(options = {}) {
|
||||
const result = checkNodeVersion(options);
|
||||
if (result.ok) return result;
|
||||
|
||||
const message = [
|
||||
`StepForge requires Node ${result.required} or newer; this is Node ${result.current}.`,
|
||||
'',
|
||||
'Install the pinned toolchain (see .nvmrc) and reinstall dependencies:',
|
||||
'',
|
||||
' nvm install && nvm use # or install Node 22 LTS another way',
|
||||
' npm ci',
|
||||
'',
|
||||
'Older Nodes fail unpredictably inside the packaging dependency graph,',
|
||||
'so this check stops early instead.',
|
||||
].join('\n');
|
||||
|
||||
const error = new Error(message);
|
||||
error.code = 'STEPFORGE_UNSUPPORTED_NODE';
|
||||
throw error;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
assertSupportedNode,
|
||||
checkNodeVersion,
|
||||
compareVersions,
|
||||
parseVersion,
|
||||
requiredNodeVersion,
|
||||
};
|
||||
Reference in New Issue
Block a user