mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-01 02:01:24 +00:00
test(publish): pin the rc-guard release-subject skip regex
The rc-guard release-PR skip is load-bearing (prevents an RC build racing the imminent stable-tag push on the release commit; the v1.6.4 race history is documented in the workflow comments) and its subject regex is subtle: nocasematch, anchored, optional (#NNNN) squash-merge suffix, full semver required. Add a unit test that extracts RELEASE_SUBJECT_RE from publish.yml (failing loudly if the Decide step changes) and exercises it under the same bash semantics via a child bash, following the build-web-optin.test.ts precedent of reading the workflow from tests.
This commit is contained in:
parent
c4ecf398de
commit
5c434ee7d6
1 changed files with 69 additions and 0 deletions
69
gitnexus/test/unit/publish-rc-guard.test.ts
Normal file
69
gitnexus/test/unit/publish-rc-guard.test.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import { readFileSync } from 'node:fs';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import path from 'node:path';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
/**
|
||||
* Regression coverage for the rc-guard release-PR skip in
|
||||
* .github/workflows/publish.yml. The `chore: release vX.Y.Z` subject match is
|
||||
* load-bearing: it prevents an RC build firing on the release-PR commit from
|
||||
* racing the imminent stable-tag push on the same SHA (see the v1.6.4 race
|
||||
* history referenced in the workflow comments). This test pins the exact
|
||||
* regex shipped in the workflow by extracting it from the YAML and running it
|
||||
* under the same bash semantics (`shopt -s nocasematch`, anchored POSIX ERE).
|
||||
*/
|
||||
const REPO_ROOT = path.resolve(__dirname, '../../..');
|
||||
const WORKFLOW = path.join(REPO_ROOT, '.github/workflows/publish.yml');
|
||||
|
||||
function releaseSubjectRegex(): string {
|
||||
const yaml = readFileSync(WORKFLOW, 'utf8');
|
||||
const match = yaml.match(/RELEASE_SUBJECT_RE='([^']+)'/);
|
||||
if (!match) {
|
||||
throw new Error('RELEASE_SUBJECT_RE not found in publish.yml — did the rc-guard Decide step change?');
|
||||
}
|
||||
return match[1];
|
||||
}
|
||||
|
||||
function subjectMatches(subject: string, regex: string): boolean {
|
||||
const script = [
|
||||
'set -euo pipefail',
|
||||
'shopt -s nocasematch',
|
||||
`SUBJECT=${JSON.stringify(subject)}`,
|
||||
`REGEX=${JSON.stringify(regex)}`,
|
||||
'[[ "$SUBJECT" =~ $REGEX ]] && echo MATCH || echo NO_MATCH',
|
||||
'shopt -u nocasematch',
|
||||
].join('\n');
|
||||
const out = execFileSync('bash', ['-c', script], { encoding: 'utf8' }).trim();
|
||||
return out === 'MATCH';
|
||||
}
|
||||
|
||||
describe('rc-guard release-subject regex (publish.yml)', () => {
|
||||
const regex = releaseSubjectRegex();
|
||||
|
||||
it('matches canonical release subjects', () => {
|
||||
expect(subjectMatches('chore: release v1.6.4', regex)).toBe(true);
|
||||
expect(subjectMatches('chore: release v10.20.30', regex)).toBe(true);
|
||||
});
|
||||
|
||||
it('matches squash-merge subjects with the (#NNNN) suffix', () => {
|
||||
expect(subjectMatches('chore: release v1.6.4 (#1474)', regex)).toBe(true);
|
||||
});
|
||||
|
||||
it('stays case-insensitive for IDE auto-capitalization', () => {
|
||||
expect(subjectMatches('Chore: Release v1.2.3', regex)).toBe(true);
|
||||
});
|
||||
|
||||
it('does not match ordinary chore commits', () => {
|
||||
expect(subjectMatches('chore: bump deps (#1500)', regex)).toBe(false);
|
||||
});
|
||||
|
||||
it('does not match release-like subjects with extra suffixes or prefixes', () => {
|
||||
expect(subjectMatches('chore: release v1.6.4 hotfix', regex)).toBe(false);
|
||||
expect(subjectMatches('revert: chore: release v1.6.4', regex)).toBe(false);
|
||||
});
|
||||
|
||||
it('requires a full semver', () => {
|
||||
expect(subjectMatches('chore: release v1.6', regex)).toBe(false);
|
||||
expect(subjectMatches('chore: release v1.6.x', regex)).toBe(false);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue