Full SDK workspace: core, contracts, sdk, cli, browser-host, browser-kit, federation, omega-core, oracle, self-healing, strategies, tools, emacs. Clean extraction from the development monorepo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
105 lines
2.8 KiB
JavaScript
105 lines
2.8 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const { execFileSync } = require('child_process');
|
|
const { globSync } = require('glob');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
const args = process.argv.slice(2);
|
|
const nodeArgs = ['--import', 'tsx'];
|
|
const patterns = [];
|
|
const excludePatterns = [];
|
|
let perFile = false;
|
|
const nodeMajor = Number.parseInt(process.versions.node.split('.')[0], 10);
|
|
const nativeTestArgs = nodeMajor >= 22 ? ['--test-force-exit'] : [];
|
|
|
|
// Derive a unique package name for JUnit XML output
|
|
function getPackageName() {
|
|
try {
|
|
const pkg = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'));
|
|
return (pkg.name || 'unknown').replace(/[^a-zA-Z0-9-]/g, '_');
|
|
} catch {
|
|
return 'unknown';
|
|
}
|
|
}
|
|
|
|
let i = 0;
|
|
while (i < args.length) {
|
|
const arg = args[i];
|
|
if (arg === '--') {
|
|
i += 1;
|
|
break;
|
|
}
|
|
if (arg === '--per-file') {
|
|
perFile = true;
|
|
i += 1;
|
|
continue;
|
|
}
|
|
if (arg === '--exclude') {
|
|
const value = args[i + 1];
|
|
if (!value) {
|
|
console.error('Missing value for --exclude');
|
|
process.exit(1);
|
|
}
|
|
excludePatterns.push(value);
|
|
i += 2;
|
|
continue;
|
|
}
|
|
if (arg === '--import') {
|
|
const value = args[i + 1];
|
|
if (!value) {
|
|
console.error('Missing value for --import');
|
|
process.exit(1);
|
|
}
|
|
nodeArgs.push(arg, value);
|
|
i += 2;
|
|
continue;
|
|
}
|
|
nodeArgs.push(arg);
|
|
i += 1;
|
|
}
|
|
|
|
patterns.push(...args.slice(i));
|
|
|
|
if (patterns.length === 0) {
|
|
console.error('No test patterns provided');
|
|
process.exit(1);
|
|
}
|
|
|
|
const files = [...new Set(patterns.flatMap((pattern) => globSync(pattern)).sort())];
|
|
const excluded = new Set(excludePatterns.flatMap((pattern) => globSync(pattern)));
|
|
const filteredFiles = files.filter((file) => !excluded.has(file));
|
|
if (filteredFiles.length === 0) {
|
|
console.error('No test files found for patterns:', patterns.join(', '));
|
|
process.exit(1);
|
|
}
|
|
|
|
// When CI_JUNIT_DIR is set, add dual reporter: spec to stdout + junit to file
|
|
const junitArgs = [];
|
|
if (process.env.CI_JUNIT_DIR) {
|
|
const junitDir = process.env.CI_JUNIT_DIR;
|
|
const pkgName = getPackageName();
|
|
const junitFile = path.join(junitDir, `${pkgName}.xml`);
|
|
fs.mkdirSync(junitDir, { recursive: true });
|
|
junitArgs.push(
|
|
'--test-reporter=spec', '--test-reporter-destination=stdout',
|
|
'--test-reporter=junit', `--test-reporter-destination=${junitFile}`
|
|
);
|
|
}
|
|
|
|
const testRunnerArgs = junitArgs.length > 0 ? junitArgs : [];
|
|
|
|
if (perFile) {
|
|
for (const file of filteredFiles) {
|
|
execFileSync(process.execPath, [...nodeArgs, ...testRunnerArgs, ...nativeTestArgs, '--test', file], {
|
|
cwd: process.cwd(),
|
|
stdio: 'inherit',
|
|
});
|
|
}
|
|
} else {
|
|
execFileSync(process.execPath, [...nodeArgs, ...testRunnerArgs, ...nativeTestArgs, '--test', ...filteredFiles], {
|
|
cwd: process.cwd(),
|
|
stdio: 'inherit',
|
|
});
|
|
}
|