fix(release-gate): skip duplicate CI work and stop live LLM blowups
Shared paths like db.mjs were pulling PAGE/DATA live agent suites into every hotfix. Keep those cases for actual page-data changes, resume passed suites on the same artifact, and fail fast on Docker/port issues instead of rerunning 100+ scenarios. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user