mirror of
https://github.com/Sea-Haven-Industries/.github.git
synced 2026-10-03 13:53:23 +00:00
fix(policy): accept AP Jira keys in PR titles (#121)
This commit is contained in:
parent
123366c3f1
commit
e5691d8a7f
2 changed files with 15 additions and 14 deletions
9
.github/workflows/callable-pr-policy.yaml
vendored
9
.github/workflows/callable-pr-policy.yaml
vendored
|
|
@ -84,7 +84,7 @@ jobs:
|
||||||
function validateTitle(title, isDependabot, jiraMaybeExempt) {
|
function validateTitle(title, isDependabot, jiraMaybeExempt) {
|
||||||
const errs = [];
|
const errs = [];
|
||||||
if (title.length > 120) errs.push('Title is ' + title.length + ' chars — max 120');
|
if (title.length > 120) errs.push('Title is ' + title.length + ' chars — max 120');
|
||||||
const m = title.match(/^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|release)(\([^)]+\))?(!)?: (.+?)(\s+\((DEV|PLAT|SEC)-\d+\))?$/);
|
const m = title.match(/^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|release)(\([^)]+\))?(!)?: (.+?)(\s+\((DEV|PLAT|SEC|AP)-\d+\))?$/);
|
||||||
if (!m) {
|
if (!m) {
|
||||||
errs.push('Title must match: type(scope): description (KEY-NNN). Allowed types: ' + CONV_TYPES.join(' '));
|
errs.push('Title must match: type(scope): description (KEY-NNN). Allowed types: ' + CONV_TYPES.join(' '));
|
||||||
return errs;
|
return errs;
|
||||||
|
|
@ -94,13 +94,13 @@ jobs:
|
||||||
if (desc.endsWith('.')) errs.push('Description must not end with a period');
|
if (desc.endsWith('.')) errs.push('Description must not end with a period');
|
||||||
if (!/^[a-z]/.test(desc)) errs.push('Description must start with a lowercase letter');
|
if (!/^[a-z]/.test(desc)) errs.push('Description must start with a lowercase letter');
|
||||||
if (!isDependabot && !jiraSuffix && !jiraMaybeExempt) {
|
if (!isDependabot && !jiraSuffix && !jiraMaybeExempt) {
|
||||||
errs.push('Missing Jira key — expected (DEV-NNN), (PLAT-NNN), or (SEC-NNN) at end of title');
|
errs.push('Missing Jira key — expected (DEV-NNN), (PLAT-NNN), (SEC-NNN), or (AP-NNN) at end of title');
|
||||||
}
|
}
|
||||||
return errs;
|
return errs;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getJiraKey(title) {
|
function getJiraKey(title) {
|
||||||
const m = title.match(/\((DEV|PLAT|SEC)-(\d+)\)$/);
|
const m = title.match(/\((DEV|PLAT|SEC|AP)-(\d+)\)$/);
|
||||||
return m ? m[1] + '-' + m[2] : null;
|
return m ? m[1] + '-' + m[2] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,7 +113,7 @@ jobs:
|
||||||
errs.push('Branch "' + branch + '" must match prefix/kebab-case (no consecutive/trailing hyphens, no uppercase, one segment). Prefixes: feature fix hotfix chore docs refactor release');
|
errs.push('Branch "' + branch + '" must match prefix/kebab-case (no consecutive/trailing hyphens, no uppercase, one segment). Prefixes: feature fix hotfix chore docs refactor release');
|
||||||
return errs;
|
return errs;
|
||||||
}
|
}
|
||||||
if (/(?:DEV|PLAT|SEC|INFRA)-\d+/i.test(m[2])) errs.push('Branch segment must not contain a Jira key');
|
if (/(?:DEV|PLAT|SEC|AP|INFRA)-\d+/i.test(m[2])) errs.push('Branch segment must not contain a Jira key');
|
||||||
return errs;
|
return errs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -181,7 +181,6 @@ jobs:
|
||||||
const desc = m[4];
|
const desc = m[4];
|
||||||
if (!/^[a-z]/.test(desc)) errs.push('Commit description must start with a lowercase letter');
|
if (!/^[a-z]/.test(desc)) errs.push('Commit description must start with a lowercase letter');
|
||||||
if (desc.endsWith('.')) errs.push('Commit description must not end with a period');
|
if (desc.endsWith('.')) errs.push('Commit description must not end with a period');
|
||||||
if (/\s+\((DEV|PLAT|SEC)-\d+\)$/i.test(subject)) errs.push('Commit subject must not carry a Jira key suffix — only the PR title does');
|
|
||||||
return errs;
|
return errs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,10 @@ describe('validateTitle', () => {
|
||||||
assert.deepEqual(v.validateTitle('docs: add runbook (SEC-7)', false), []);
|
assert.deepEqual(v.validateTitle('docs: add runbook (SEC-7)', false), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('accepts AP Jira keys', () => {
|
||||||
|
assert.deepEqual(v.validateTitle('feat(frontend): scaffold vite spa and ci (AP-4)', false), []);
|
||||||
|
});
|
||||||
|
|
||||||
it('rejects inactive Jira projects (INFRA)', () => {
|
it('rejects inactive Jira projects (INFRA)', () => {
|
||||||
const errs = v.validateTitle('fix: patch (INFRA-1)', false);
|
const errs = v.validateTitle('fix: patch (INFRA-1)', false);
|
||||||
assert.ok(errs.length > 0, 'INFRA is inactive and should fail');
|
assert.ok(errs.length > 0, 'INFRA is inactive and should fail');
|
||||||
|
|
@ -214,6 +218,7 @@ describe('getJiraKey', () => {
|
||||||
it('extracts DEV key', () => assert.equal(v.getJiraKey('fix: thing (DEV-42)'), 'DEV-42'));
|
it('extracts DEV key', () => assert.equal(v.getJiraKey('fix: thing (DEV-42)'), 'DEV-42'));
|
||||||
it('extracts PLAT key', () => assert.equal(v.getJiraKey('chore: thing (PLAT-1)'), 'PLAT-1'));
|
it('extracts PLAT key', () => assert.equal(v.getJiraKey('chore: thing (PLAT-1)'), 'PLAT-1'));
|
||||||
it('extracts SEC key', () => assert.equal(v.getJiraKey('docs: thing (SEC-999)'), 'SEC-999'));
|
it('extracts SEC key', () => assert.equal(v.getJiraKey('docs: thing (SEC-999)'), 'SEC-999'));
|
||||||
|
it('extracts AP key', () => assert.equal(v.getJiraKey('feat(frontend): scaffold (AP-4)'), 'AP-4'));
|
||||||
it('returns null when no key', () => assert.equal(v.getJiraKey('chore: thing'), null));
|
it('returns null when no key', () => assert.equal(v.getJiraKey('chore: thing'), null));
|
||||||
it('returns null for mid-title key', () => assert.equal(v.getJiraKey('fix (DEV-1): something'), null));
|
it('returns null for mid-title key', () => assert.equal(v.getJiraKey('fix (DEV-1): something'), null));
|
||||||
});
|
});
|
||||||
|
|
@ -365,19 +370,16 @@ describe('validateCommitSubject', () => {
|
||||||
assert.deepEqual(v.validateCommitSubject('feat!: remove deprecated api'), []);
|
assert.deepEqual(v.validateCommitSubject('feat!: remove deprecated api'), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects subject with Jira key suffix', () => {
|
it('accepts subject with DEV Jira key suffix', () => {
|
||||||
const errs = v.validateCommitSubject('fix: patch (DEV-123)');
|
assert.deepEqual(v.validateCommitSubject('fix: patch (DEV-123)'), []);
|
||||||
assert.ok(errs.some(e => e.includes('Jira')), 'should reject Jira suffix: ' + errs.join('; '));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects subject with lowercase Jira key suffix (case-insensitive)', () => {
|
it('accepts subject with AP Jira key suffix', () => {
|
||||||
const errs = v.validateCommitSubject('fix: patch (dev-123)');
|
assert.deepEqual(v.validateCommitSubject('feat(frontend): scaffold vite spa and ci (AP-4)'), []);
|
||||||
assert.ok(errs.some(e => e.includes('Jira')), 'lowercase Jira suffix should also be rejected: ' + errs.join('; '));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects subject with plat Jira key suffix', () => {
|
it('accepts subject with PLAT Jira key suffix', () => {
|
||||||
const errs = v.validateCommitSubject('chore: update config (plat-5)');
|
assert.deepEqual(v.validateCommitSubject('chore: update config (PLAT-5)'), []);
|
||||||
assert.ok(errs.some(e => e.includes('Jira')), 'plat Jira suffix should be rejected: ' + errs.join('; '));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects non-conventional subject', () => {
|
it('rejects non-conventional subject', () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue