GitNexus/.devcontainer/dependencies.test.cjs
Gergő Magyar b961e695ca
Some checks failed
Devcontainer Smoke / Config-transform unit tests (push) Has been cancelled
Devcontainer Smoke / Build devcontainer image (default) (push) Has been cancelled
Publish Development Images / publish (core) (push) Has been cancelled
Publish Development Images / publish (ui) (push) Has been cancelled
Devcontainer Smoke / Build devcontainer image (ui) (push) Has been cancelled
CodeQL / Analyze (python) (push) Waiting to run
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
Gitleaks / gitleaks (push) Waiting to run
Publish / ci (push) Blocked by required conditions
Publish / Classify release event (push) Waiting to run
Publish / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / Publish to npm (push) Blocked by required conditions
Publish / Build & Push RC Docker images (push) Blocked by required conditions
Scorecard / Scorecard analysis (push) Waiting to run
Skill copy sync / shipped skills drift guard (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-cli) (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-web) (push) Waiting to run
fix(devcontainer): refresh Node and streamline development (#3610)
2026-10-17 21:05:13 +00:00

252 lines
9.6 KiB
JavaScript

'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { execFileSync, spawnSync } = require('node:child_process');
const { ensureDependencies, markerName } = require('./dependencies.cjs');
function fixture(t) {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gn-dependencies-'));
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
fs.writeFileSync(
path.join(root, 'package.json'),
JSON.stringify({ dependencies: { example: '1.0.0' } }),
);
fs.writeFileSync(path.join(root, 'package-lock.json'), '{}');
let installs = 0;
const run = () => {
installs++;
fs.mkdirSync(path.join(root, 'node_modules/example'), { recursive: true });
fs.writeFileSync(path.join(root, 'node_modules/example/package.json'), '{}');
};
return { root, run, count: () => installs };
}
test('reuses completed dependency volumes and reinstalls after lockfile changes', (t) => {
const f = fixture(t);
assert.equal(ensureDependencies(f.root, { run: f.run }), true);
assert.equal(ensureDependencies(f.root, { run: f.run }), false);
fs.writeFileSync(path.join(f.root, 'package-lock.json'), '{"lockfileVersion":3}');
assert.equal(ensureDependencies(f.root, { run: f.run }), true);
assert.equal(f.count(), 2);
});
test('repairs a missing direct dependency even if the receipt matches', (t) => {
const f = fixture(t);
ensureDependencies(f.root, { run: f.run });
fs.rmSync(path.join(f.root, 'node_modules/example'), { recursive: true });
assert.equal(ensureDependencies(f.root, { run: f.run }), true);
});
test('runtime ABI changes and explicit repair invalidate reuse', (t) => {
const f = fixture(t);
ensureDependencies(f.root, { run: f.run });
const runtime = {
version: 'v22.23.3',
versions: { modules: 'different' },
platform: 'linux',
arch: 'arm64',
};
assert.equal(ensureDependencies(f.root, { run: f.run, runtime }), true);
assert.equal(ensureDependencies(f.root, { run: f.run, runtime, force: true }), true);
});
for (const group of ['dependencies', 'devDependencies', 'optionalDependencies']) {
test(`local file-dependency manifest changes in ${group} invalidate reuse`, (t) => {
const f = fixture(t);
const local = path.join(f.root, 'local');
fs.mkdirSync(local);
fs.writeFileSync(path.join(local, 'package.json'), '{"version":"1.0.0"}');
const manifest = { dependencies: { example: '1.0.0' } };
manifest[group] ??= {};
manifest[group].local = 'file:./local';
fs.writeFileSync(path.join(f.root, 'package.json'), JSON.stringify(manifest));
const run = () => {
f.run();
fs.mkdirSync(path.join(f.root, 'node_modules/local'), { recursive: true });
fs.copyFileSync(
path.join(local, 'package.json'),
path.join(f.root, 'node_modules/local/package.json'),
);
};
ensureDependencies(f.root, { run });
assert.equal(ensureDependencies(f.root, { run }), false);
fs.writeFileSync(path.join(local, 'package.json'), '{"version":"1.0.1"}');
assert.equal(ensureDependencies(f.root, { run }), true);
assert.equal(ensureDependencies(f.root, { run }), false);
assert.equal(f.count(), 2);
});
}
test('tracked native source and installer edits invalidate reuse', (t) => {
const f = fixture(t);
fs.mkdirSync(path.join(f.root, 'scripts'));
fs.mkdirSync(path.join(f.root, 'vendor'));
fs.mkdirSync(path.join(f.root, 'prebuilds/bundled'), { recursive: true });
fs.writeFileSync(path.join(f.root, 'scripts/build-tree-sitter-grammars.cjs'), '// original');
fs.writeFileSync(path.join(f.root, 'scripts/arm64-prebuild.cjs'), '// original validator');
fs.writeFileSync(path.join(f.root, 'prebuilds/bundled/manifest.json'), '{"schemaVersion":1}');
fs.writeFileSync(path.join(f.root, 'prebuilds/bundled/grammar.node'), Buffer.from([1, 2, 3]));
fs.writeFileSync(path.join(f.root, 'vendor/grammar.c'), '// original');
const git = (...args) =>
execFileSync(
'git',
[
'-c',
'core.hooksPath=/dev/null',
'-c',
'commit.gpgsign=false',
'-c',
'user.name=Fixture',
'-c',
'user.email=fixture@example.invalid',
...args,
],
{ cwd: f.root, stdio: 'pipe' },
);
git('init');
git(
'add',
'package.json',
'package-lock.json',
'scripts/build-tree-sitter-grammars.cjs',
'scripts/arm64-prebuild.cjs',
'prebuilds/bundled',
'vendor/grammar.c',
);
git('commit', '-m', 'fixture');
ensureDependencies(f.root, { run: f.run });
assert.equal(ensureDependencies(f.root, { run: f.run }), false);
fs.writeFileSync(path.join(f.root, 'vendor/grammar.c'), '// changed grammar');
assert.equal(ensureDependencies(f.root, { run: f.run }), true);
fs.writeFileSync(
path.join(f.root, 'scripts/build-tree-sitter-grammars.cjs'),
'// changed installer',
);
assert.equal(ensureDependencies(f.root, { run: f.run }), true);
for (const [file, content] of [
['scripts/arm64-prebuild.cjs', '// changed validator'],
['prebuilds/bundled/manifest.json', '{"schemaVersion":2}'],
['prebuilds/bundled/grammar.node', Buffer.from([4, 5, 6])],
]) {
fs.writeFileSync(path.join(f.root, file), content);
assert.equal(ensureDependencies(f.root, { run: f.run }), true, file);
assert.equal(ensureDependencies(f.root, { run: f.run }), false, file);
}
});
test('failed reinstall removes its receipt and is retried', (t) => {
const f = fixture(t);
ensureDependencies(f.root, { run: f.run });
assert.throws(
() =>
ensureDependencies(f.root, {
force: true,
run: () => {
throw new Error('install failed');
},
}),
/install failed/,
);
assert.equal(fs.existsSync(path.join(f.root, 'node_modules', markerName)), false);
assert.equal(ensureDependencies(f.root, { run: f.run }), true);
});
test('changing optional-grammar policy invalidates the core install receipt', (t) => {
const f = fixture(t);
const previous = process.env.GITNEXUS_SKIP_OPTIONAL_GRAMMARS;
t.after(() => {
if (previous === undefined) delete process.env.GITNEXUS_SKIP_OPTIONAL_GRAMMARS;
else process.env.GITNEXUS_SKIP_OPTIONAL_GRAMMARS = previous;
});
fs.mkdirSync(path.join(f.root, 'scripts'));
fs.writeFileSync(path.join(f.root, 'scripts/build-tree-sitter-grammars.cjs'), '// fixture');
execFileSync('git', ['init', '-q'], { cwd: f.root });
execFileSync(
'git',
[
'-c',
'core.hooksPath=/dev/null',
'-c',
'commit.gpgsign=false',
'-c',
'user.name=Fixture',
'-c',
'user.email=fixture@example.invalid',
'commit',
'--allow-empty',
'-m',
'fixture',
],
{ cwd: f.root, stdio: 'pipe' },
);
process.env.GITNEXUS_SKIP_OPTIONAL_GRAMMARS = '1';
assert.equal(ensureDependencies(f.root, { run: f.run }), true);
assert.equal(ensureDependencies(f.root, { run: f.run }), false);
delete process.env.GITNEXUS_SKIP_OPTIONAL_GRAMMARS;
assert.equal(ensureDependencies(f.root, { run: f.run }), true);
process.env.GITNEXUS_SKIP_OPTIONAL_GRAMMARS = '0';
assert.equal(ensureDependencies(f.root, { run: f.run }), false);
process.env.GITNEXUS_SKIP_OPTIONAL_GRAMMARS = '1';
assert.equal(ensureDependencies(f.root, { run: f.run }), true);
assert.equal(f.count(), 3);
});
test('cached lifecycle restores real Husky and rebuilds changed sources', (t) => {
const f = fixture(t);
fs.writeFileSync(path.join(f.root, 'package.json'), '{}');
for (const name of ['gitnexus', 'gitnexus-web', 'gitnexus-shared']) {
fs.mkdirSync(path.join(f.root, name));
fs.writeFileSync(path.join(f.root, name, 'package.json'), '{}');
fs.writeFileSync(path.join(f.root, name, 'package-lock.json'), '{}');
}
fs.mkdirSync(path.join(f.root, '.husky'));
fs.writeFileSync(path.join(f.root, '.husky/pre-commit'), 'exit 0\n');
const global = path.join(f.root, 'gitconfig');
fs.writeFileSync(global, '');
const env = {
...process.env,
PATH: `${f.root}:${process.env.PATH}`,
HUSKY: '',
GIT_CONFIG_GLOBAL: global,
GIT_CONFIG_NOSYSTEM: '1',
GIT_CONFIG_COUNT: '0',
GITNEXUS_FORCE_DEPS: '0',
GITNEXUS_DEV_UI: '0',
};
for (const key of ['GIT_DIR', 'GIT_COMMON_DIR', 'GIT_WORK_TREE', 'GIT_INDEX_FILE'])
delete env[key];
execFileSync('git', ['init', '-q'], { cwd: f.root, env });
const husky = path.resolve(__dirname, '../node_modules/husky/bin.js');
fs.writeFileSync(
path.join(f.root, 'npm'),
`#!${process.execPath}
const fs = require('node:fs');
const path = require('node:path');
const args = process.argv.slice(2);
if (args[0] === '--version') { console.log('10.9.2'); process.exit(0); }
fs.appendFileSync(${JSON.stringify(path.join(f.root, 'calls'))}, path.basename(process.cwd()) + ':' + args.join(' ') + '\\n');
if (args[0] === 'ci') fs.mkdirSync('node_modules', { recursive: true });
if (args.join(' ') === 'run prepare') require('node:child_process').execFileSync(process.execPath, [${JSON.stringify(husky)}], { stdio: 'inherit' });
`,
{ mode: 0o755 },
);
const invoke = () => {
const result = spawnSync(process.execPath, [path.join(__dirname, 'dependencies.cjs'), f.root], {
env,
encoding: 'utf8',
});
assert.equal(result.status, 0, result.stderr);
};
invoke();
fs.rmSync(path.join(f.root, '.husky/_'), { recursive: true });
fs.writeFileSync(path.join(f.root, 'calls'), '');
invoke();
const calls = fs.readFileSync(path.join(f.root, 'calls'), 'utf8');
assert.doesNotMatch(calls, /:ci/);
assert.match(calls, /:run prepare/);
assert.match(calls, /gitnexus:run build/);
assert.ok(fs.existsSync(path.join(f.root, '.husky/_/pre-commit')));
});