fix: harden release gate and page delivery
Memind CI / Test, build, and release guards (push) Failing after 12m3s
Memind CI / Test, build, and release guards (push) Failing after 12m3s
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env node
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
|
||||
import { assertPortalRuntimePath, hashArtifact } from '../release-gate/artifact.mjs';
|
||||
import { validateGateReport } from '../release-gate/report.mjs';
|
||||
import { runCommand } from '../release-gate/runner.mjs';
|
||||
|
||||
const ROOT = path.resolve(new URL('..', import.meta.url).pathname);
|
||||
|
||||
function parseArgs(argv) {
|
||||
const options = {
|
||||
artifact: path.join(ROOT, '.runtime', 'portal'),
|
||||
report: null,
|
||||
};
|
||||
for (let index = 2; index < argv.length; index += 1) {
|
||||
const arg = argv[index];
|
||||
if (arg === '--artifact') options.artifact = path.resolve(argv[++index] ?? '');
|
||||
else if (arg === '--report') options.report = path.resolve(argv[++index] ?? '');
|
||||
else throw new Error(`Unknown argument: ${arg}`);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
async function git(...args) {
|
||||
const result = await runCommand('git', args, { cwd: ROOT, timeoutMs: 30_000 });
|
||||
if (result.code !== 0) throw new Error(`git ${args.join(' ')} failed`);
|
||||
return result.stdout.trim();
|
||||
}
|
||||
|
||||
try {
|
||||
const options = parseArgs(process.argv);
|
||||
options.artifact = assertPortalRuntimePath(options.artifact, { repoRoot: ROOT });
|
||||
const commitSha = await git('rev-parse', 'HEAD');
|
||||
const reportPath = options.report ?? path.join(ROOT, '.release-gate', commitSha, 'report.json');
|
||||
const [raw, artifact] = await Promise.all([
|
||||
fs.readFile(reportPath, 'utf8'),
|
||||
hashArtifact(options.artifact),
|
||||
]);
|
||||
const report = JSON.parse(raw);
|
||||
const validation = validateGateReport(report, {
|
||||
expectedCommit: commitSha,
|
||||
expectedArtifactSha256: artifact.sha256,
|
||||
expectedBranch: 'main',
|
||||
});
|
||||
if (!validation.valid) {
|
||||
const blocking = report.scenarios.filter(
|
||||
(scenario) => !['passed', 'not_applicable'].includes(scenario.status),
|
||||
);
|
||||
const preview = blocking
|
||||
.slice(0, 20)
|
||||
.map((scenario) => `${scenario.id}:${scenario.status}`)
|
||||
.join(', ');
|
||||
const structural = validation.errors.filter(
|
||||
(message) => !/^[A-Z]+-\d{2} is (failed|skipped|blocked|unknown)$/.test(message),
|
||||
);
|
||||
throw new Error([
|
||||
'Gate report rejected.',
|
||||
`blocking_scenarios=${blocking.length}`,
|
||||
`preview=${preview}${blocking.length > 20 ? ', ...' : ''}`,
|
||||
...structural.map((message) => `- ${message}`),
|
||||
].join('\n'));
|
||||
}
|
||||
console.log(`Gate report verified: ${reportPath}`);
|
||||
console.log(`commit=${commitSha}`);
|
||||
console.log(`artifact_sha256=${artifact.sha256}`);
|
||||
} catch (error) {
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user