/** * Live/e2e mutual-exclusion guard. * * A live deploy and the e2e simulator can't run at the same time: the e2e * stack binds the same docker networks and hostnames a live deploy touches, * so a deploy fired while an e2e network is up (e.g. a leftover `--keep` run) * would collide. Both the deploy itself and the fast pre-flight check use this * helper to refuse before touching any infrastructure. */ import { execSync } from 'node:child_process'; import { tmpdir } from 'node:os'; /** One-line remediation, shared by the deploy error and the preflight error. */ export const E2E_CONFLICT_FIX = 'Stop e2e tests first: cele2e down'; /** Flat error string the deploy returns when an e2e stack is up. */ export const E2E_CONFLICT_MESSAGE = `Cannot deploy: e2e test containers are running. Live and e2e environments are mutually exclusive. ${E2E_CONFLICT_FIX}`; /** * Names of running `celilo-e2e-*` containers (empty = clear to deploy). * * Skipped (returns `[]`) when CELILO_DB_PATH points at a temp dir, since * integration tests run against throwaway DBs and never touch docker — they * must not trip over a developer's unrelated e2e stack. A docker failure * (not installed / not running) is treated as "clear": there's nothing to * conflict with. */ export function runningE2eContainers(): string[] { if (process.env.CELILO_DB_PATH?.startsWith(tmpdir())) return []; try { const running = execSync('docker ps --format "{{.Names}}" 2>/dev/null', { encoding: 'utf-8', timeout: 5000, }); return running.split('\n').filter((name) => name.startsWith('celilo-e2e-')); } catch { // docker not installed / not running — nothing to conflict with. return []; } }