import { cpSync, mkdirSync } from 'node:fs'; import { join, resolve } from 'node:path'; import { spawn } from 'node:child_process'; import lockfile from 'proper-lockfile'; import { cleanupOwnedRunDir } from './e2e-run-dir.mjs'; const root = resolve(import.meta.dirname, '..'); const runDir = process.env.E2E_RUN_TMP; if (!runDir) throw new Error('E2E_RUN_TMP is required'); const lockDir = join(root, 'node_modules', '.cache', 'maestro-e2e-build.lock'); const cacheDir = join(root, 'node_modules', '.cache'); mkdirSync(cacheDir, { recursive: true }); const run = (command, args, env = process.env) => new Promise((resolveRun, reject) => { const child = spawn(command, args, { cwd: root, env, stdio: 'inherit' }); child.once('error', reject); child.once('exit', code => code === 0 ? resolveRun() : reject(new Error(`${command} exited ${code}`))); }); const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'; let server; try { const releaseBuildLock = await lockfile.lock(cacheDir, { lockfilePath: lockDir, stale: 120_000, retries: { retries: 600, factor: 1, minTimeout: 100, maxTimeout: 100 }, }); try { await run(npm, ['run', 'build:server']); await run(npm, ['run', 'build:ui']); cpSync(join(root, 'dist'), join(runDir, 'dist'), { recursive: true }); cpSync(join(root, 'ui', 'dist'), join(runDir, 'ui-dist'), { recursive: true }); mkdirSync(join(runDir, 'scripts'), { recursive: true }); cpSync(join(root, 'scripts', 'setup-lib.mjs'), join(runDir, 'scripts', 'setup-lib.mjs')); } finally { await releaseBuildLock(); } server = spawn(process.execPath, [join(runDir, 'dist', 'main.js')], { cwd: root, env: { ...process.env, UI_DIST_PATH: join(runDir, 'ui-dist') }, stdio: 'inherit', }); const stop = () => server?.kill('SIGTERM'); process.on('SIGINT', stop); process.on('SIGTERM', stop); const code = await new Promise((resolveExit, reject) => { server.once('error', reject); server.once('exit', resolveExit); }); process.exitCode = typeof code === 'number' ? code : 0; } finally { cleanupOwnedRunDir({ cacheRoot: process.env.E2E_CACHE_ROOT, directory: runDir, prefix: process.env.E2E_RUN_PREFIX, token: process.env.E2E_RUN_TOKEN, }); }