import fs from 'node:fs'; import net from 'node:net'; import { spawnSync } from 'node:child_process'; export const GATE_SUITE_PORTS = Object.freeze({ 'runtime-sanitized-data-upgrade': 19085, 'page-data-product-scenarios': 19086, 'page-content-delivery-scenarios': 19087, 'runtime-production-homolog-cold-start': 19081, }); const DOCKER_SOCKET_CANDIDATES = [ process.env.DOCKER_HOST?.replace(/^unix:\/\//, ''), `${process.env.HOME ?? ''}/.docker/run/docker.sock`, '/var/run/docker.sock', ].filter(Boolean); export function dockerSocketExists() { return DOCKER_SOCKET_CANDIDATES.some((socketPath) => { try { return fs.existsSync(socketPath); } catch { return false; } }); } export function assertDockerDaemonAvailable() { if (!dockerSocketExists()) { throw new Error( 'Release gate REL-11 needs Docker; start Docker Desktop and retry. Missing docker.sock.', ); } const result = spawnSync('docker', ['info'], { encoding: 'utf8', timeout: 15_000, }); if (result.status !== 0) { throw new Error( `Release gate REL-11 needs a running Docker daemon: ${(result.stderr || result.error?.message || 'docker info failed').trim().slice(0, 500)}`, ); } } export function assertLoopbackPortAvailable(port, host = '127.0.0.1') { return new Promise((resolve, reject) => { const server = net.createServer(); server.once('error', (error) => { if (error?.code === 'EADDRINUSE') { reject(new Error( `Release gate port ${host}:${port} is already in use; stop the stale local gate process before retrying`, )); return; } reject(error); }); server.once('listening', () => { server.close((closeError) => { if (closeError) reject(closeError); else resolve(); }); }); server.listen(port, host); }); } export async function preflightImpactSuites(suites) { const ports = [...new Set( suites .map((suite) => GATE_SUITE_PORTS[suite.id]) .filter((port) => Number.isInteger(port)), )].sort((left, right) => left - right); for (const port of ports) { await assertLoopbackPortAvailable(port); } if (suites.some((suite) => suite.id === 'runtime-linux-dependency-closure')) { assertDockerDaemonAvailable(); } }