Files

42 lines
2.6 KiB
Python

#!/usr/bin/env python3
"""Owned worktree gate, with a fresh process group and bounded cleanup per command."""
import json, os, signal, subprocess, sys, time
from pathlib import Path
root = Path(__file__).resolve().parents[4]
scratch = Path(sys.argv[1]); scratch.mkdir(parents=True, exist_ok=True)
env = {**os.environ, 'TMPDIR': str(scratch), 'MOSAIC_REQUIRE_EDITOR_BUILD': '1'}
env.pop('MOSAIC_LIVE_PROVIDER', None)
node = ['node', '--test', '--test-reporter=tap', '--test-concurrency=1', '--test-timeout=30000']
steps = [('editor-build', 120, ['npm', 'run', 'build:editor'], root / 'packages/webui'),
('webui-full', 900, node + ['packages/webui/tests/'], root),
('plugins-full', 300, node + ['packages/plugins/tests/'], root),
('bus-full', 1200, node + ['packages/bus/tests/'], root)]
steps += [(p.stem, 1200, ['bash', str(p)], root) for p in sorted((root / 'scripts').glob('test-*.sh'))]
if '--scripts-only' in sys.argv[2:]:
steps = [step for step in steps if step[0].startswith('test-')]
if '--t9-reruns' in sys.argv[2:]:
steps = [(f't9-rerun-{i}', 120, node + ['packages/bus/tests/library-credential.test.mjs'], root) for i in range(1, 4)] + [('bus-rerun', 1200, node + ['packages/bus/tests/'], root)]
results = []
summary = scratch / ('scripts-summary.json' if '--scripts-only' in sys.argv[2:] else 'rerun-summary.json' if '--t9-reruns' in sys.argv[2:] else 'gate-summary.json')
for name, limit, command, cwd in steps:
started = time.monotonic(); signals = []
with (scratch / (name + '.tap')).open('w') as log:
child = subprocess.Popen(['timeout', '-k', '10', str(limit), *command], cwd=cwd, env=env,
stdout=log, stderr=subprocess.STDOUT, start_new_session=True)
try:
code = child.wait(timeout=limit + 15)
except subprocess.TimeoutExpired:
os.killpg(child.pid, signal.SIGKILL); signals.append('KILL'); code = child.wait()
finally:
# This group was created for this command; never signal any other seat's group.
try:
os.killpg(child.pid, signal.SIGTERM); signals.append('TERM'); time.sleep(.2)
try: os.killpg(child.pid, signal.SIGKILL); signals.append('KILL')
except ProcessLookupError: pass
except ProcessLookupError: pass
entry = {'step': name, 'command': command, 'cwd': str(cwd), 'outerSeconds': limit,
'exit': code, 'seconds': round(time.monotonic()-started, 3), 'cleanupSignals': signals}
results.append(entry); summary.write_text(json.dumps(results, indent=2) + '\n')
print(json.dumps(entry), flush=True)
if code: sys.exit(code if 0 < code < 126 else 1)