* test(#3833): failing-first suite for the PR mergeability preflight * chore(#3833): gate every PR compute lane behind a mergeability preflight * fix(#3833): assert the preflight gate on parsed yaml and guard status-function if * fix(#3833): run stub-backed cli tests in-process to avoid a spawnsync deadlock * fix(#3833): fail the preflight open when its script is absent at the base sha --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -39,6 +39,10 @@ const PROTECTED_WORKFLOWS = new Set([
|
||||
'mutation.yml',
|
||||
'security-scan.yml',
|
||||
'release.yml',
|
||||
// #3833: the reusable gate every `pull_request` compute lane depends on —
|
||||
// marking it inert would let a change to the gate itself ship without ever
|
||||
// running the full matrix it is responsible for enforcing.
|
||||
'pr-mergeable-preflight.yml',
|
||||
]);
|
||||
for (const wf of PROTECTED_WORKFLOWS) {
|
||||
if (INERT_WORKFLOWS.has(wf)) {
|
||||
@@ -341,19 +345,48 @@ function missingRuleTestFiles(rules) {
|
||||
return [...referenced].filter(f => !existsSync(path.join(__dirname, '..', f))).sort();
|
||||
}
|
||||
|
||||
// Fail loudly at module load, mirroring the PROTECTED_WORKFLOWS check above —
|
||||
// this fires on EVERY invocation of the CLI (including the real `changes` job
|
||||
// in .github/workflows/test.yml), not only when a test suite happens to run.
|
||||
{
|
||||
const missing = missingRuleTestFiles(RULES);
|
||||
if (missing.length > 0) {
|
||||
throw new Error(
|
||||
`ci-test-scope: RULES reference test file(s) that do not exist on disk ` +
|
||||
`(silent coverage hole — see #2758):\n ${missing.join('\n ')}`,
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Every PROTECTED_WORKFLOWS member that does not exist on disk.
|
||||
* The name list and the real filenames are two surfaces over one fact
|
||||
* (#3833): without this, renaming or deleting a gating workflow silently
|
||||
* un-protects it and CI stays green while the protection is gone. Same
|
||||
* shape and rationale as missingRuleTestFiles() above.
|
||||
*/
|
||||
function missingProtectedWorkflows(names = PROTECTED_WORKFLOWS) {
|
||||
return [...names]
|
||||
.filter(name => !existsSync(path.join(__dirname, '..', '.github', 'workflows', name)))
|
||||
.sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared module-load assertion for the two "this list names something that
|
||||
* does not exist on disk" guards above. Both are silent-coverage-hole guards:
|
||||
* a name that no longer resolves stops selecting/protecting anything while CI
|
||||
* stays green, so both must fail loudly at load rather than at test time.
|
||||
*/
|
||||
function assertNoneMissing(missing, summary, issueRef) {
|
||||
if (missing.length === 0) return;
|
||||
throw new Error(`ci-test-scope: ${summary} (${issueRef}):\n ${missing.join('\n ')}`);
|
||||
}
|
||||
|
||||
// Fail loudly at module load — this fires on EVERY invocation of the CLI
|
||||
// (including the real `changes` job in .github/workflows/test.yml), not only
|
||||
// when a test suite happens to run.
|
||||
assertNoneMissing(
|
||||
missingRuleTestFiles(RULES),
|
||||
'RULES reference test file(s) that do not exist on disk (silent coverage hole)',
|
||||
'see #2758',
|
||||
);
|
||||
|
||||
// A PROTECTED_WORKFLOWS entry naming a file that does not exist means the
|
||||
// workflow was renamed or deleted without updating this list, silently
|
||||
// un-protecting it while CI stays green.
|
||||
assertNoneMissing(
|
||||
missingProtectedWorkflows(PROTECTED_WORKFLOWS),
|
||||
'PROTECTED_WORKFLOWS reference workflow file(s) that do not exist on disk (silent protection hole)',
|
||||
'see #3833',
|
||||
);
|
||||
|
||||
function usage() {
|
||||
return [
|
||||
'Usage:',
|
||||
@@ -590,4 +623,4 @@ if (require.main === module) {
|
||||
runMain(main);
|
||||
}
|
||||
|
||||
module.exports = { RULES, missingRuleTestFiles };
|
||||
module.exports = { RULES, missingRuleTestFiles, PROTECTED_WORKFLOWS, INERT_WORKFLOWS, missingProtectedWorkflows };
|
||||
|
||||
Reference in New Issue
Block a user