Files
openswarm/scripts/ci/verify-release-readiness.js
T

55 lines
2.7 KiB
JavaScript

#!/usr/bin/env node
// The v* tag gate. Reads preflight-tunings.json (produced by the aggregator) and asserts every platform has the required number of consecutive clean dogfood runs AND zero outstanding tuning candidates. Exits non-zero if any platform isn't ready, blocking the release workflow from publishing.
'use strict';
const fs = require('fs');
const path = require('path');
const h = require('./lib/app-harness');
function parseArgs(argv) {
const out = { tunings: null, requirePlatforms: ['win32', 'darwin'] };
for (let i = 0; i < argv.length; i++) {
if (argv[i] === '--tunings') out.tunings = argv[++i];
else if (argv[i] === '--require') out.requirePlatforms = argv[++i].split(',');
}
return out;
}
function main() {
const args = parseArgs(process.argv.slice(2));
const tuningsPath = args.tunings || path.join(h.REPO_ROOT, 'scripts', 'ci', 'preflight-tunings.json');
let tunings;
try { tunings = JSON.parse(fs.readFileSync(tuningsPath, 'utf8')); }
catch (e) { process.stderr.write(`\nRELEASE-READINESS FAIL: cannot read ${tuningsPath}: ${e && e.message}\n Run dogfood-aggregator first to generate it.\n`); process.exit(1); }
process.stdout.write(`Release readiness check: ${tuningsPath}\n`);
process.stdout.write(`Tunings generated at: ${tunings.generatedAt}\n`);
let failed = 0;
const r = tunings.releaseReadiness || {};
if (!r.perPlatform) { process.stderr.write(' FAIL no perPlatform block in tunings\n'); process.exit(1); }
for (const p of args.requirePlatforms) {
const slot = r.perPlatform[p];
if (!slot) { process.stderr.write(` FAIL required platform "${p}" has no runs yet\n`); failed++; continue; }
if (!slot.ready) { process.stderr.write(` FAIL ${p}: ${slot.tailSize}/${r.minRuns} runs in tail, ${slot.tailMismatches} mismatch(es)\n`); failed++; }
else process.stdout.write(` ok ${p}: ${slot.tailSize}/${r.minRuns} consecutive clean runs\n`);
}
// No outstanding demotion candidates (each is an unresolved false-positive source).
const demoteCount = (tunings.demote || []).length;
if (demoteCount > 0) {
process.stderr.write(` FAIL ${demoteCount} check(s) flagged for demotion - resolve before tagging:\n`);
for (const d of tunings.demote) process.stderr.write(` - ${d.platform}/${d.check}: warnRate=${(d.warnRate * 100).toFixed(1)}%\n`);
failed++;
} else {
process.stdout.write(' ok no demotion candidates outstanding\n');
}
if (failed) { process.stderr.write(`\nRELEASE-READINESS FAIL: ${failed} blocker(s); do not tag v*.\n`); process.exit(1); }
process.stdout.write('\nRELEASE-READINESS PASS: every platform has the required consecutive clean dogfood runs; tagging is unblocked.\n');
process.exit(0);
}
main();