diff --git a/README.md b/README.md index 3a52b187..7134e9a9 100644 --- a/README.md +++ b/README.md @@ -63,10 +63,12 @@ feat(ui): Add `Button` component ```yml with: # Configure which types are allowed (newline-delimited). + # These are regex patterns auto-wrapped in `^ $`. # Default: https://github.com/commitizen/conventional-commit-types types: | fix feat + JIRA-\d+ # Configure which scopes are allowed (newline-delimited). # These are regex patterns auto-wrapped in `^ $`. scopes: | diff --git a/action.yml b/action.yml index a233ca77..e6501a21 100644 --- a/action.yml +++ b/action.yml @@ -9,7 +9,7 @@ branding: color: 'green' inputs: types: - description: "Provide custom types (newline delimited) if you don't want the default ones from https://www.conventionalcommits.org." + description: "Provide custom types (newline delimited) if you don't want the default ones from https://www.conventionalcommits.org. These are regex patterns auto-wrapped in `^ $`." required: false scopes: description: 'Configure which scopes are allowed (newline delimited). These are regex patterns auto-wrapped in `^ $`.' diff --git a/src/validatePrTitle.js b/src/validatePrTitle.js index cc88fd5d..aa80cb42 100644 --- a/src/validatePrTitle.js +++ b/src/validatePrTitle.js @@ -71,7 +71,7 @@ export default async function validatePrTitle( raiseError(`No subject found in pull request title "${prTitle}".`); } - if (!types.includes(result.type)) { + if (!types.some((type) => new RegExp(`^${type}$`).test(result.type))) { raiseError( `Unknown release type "${ result.type diff --git a/src/validatePrTitle.test.js b/src/validatePrTitle.test.js index eed3af01..4d2d2c5d 100644 --- a/src/validatePrTitle.test.js +++ b/src/validatePrTitle.test.js @@ -39,6 +39,86 @@ it('throws for PR titles with an unknown type', async () => { ); }); +describe('regex types', () => { + const headerPattern = /^([\w-]*)(?:\(([\w$.\-*/ ]*)\))?: (.*)$/; + + it('allows a regex matching type', async () => { + await validatePrTitle('JIRA-123: Bar', { + types: ['JIRA-\\d+'], + headerPattern + }); + }); + + it('can be used for dynamic Jira keys', async () => { + const inputs = ['JIRA-123', 'P-123', 'INT-31', 'CONF-0']; + + for (let index = 0; index < inputs.length; index++) { + await validatePrTitle(`${inputs[index]}: did the thing`, { + types: ['[A-Z]+-\\d+'], + headerPattern + }); + } + }); + + it('throws for PR titles without a type', async () => { + await expect( + validatePrTitle('Fix JIRA-123 bug', { + types: ['JIRA-\\d+'], + headerPattern + }) + ).rejects.toThrow( + 'No release type found in pull request title "Fix JIRA-123 bug".' + ); + }); + + it('throws for PR titles with only a type', async () => { + await expect( + validatePrTitle('JIRA-123:', { + types: ['JIRA-\\d+'], + headerPattern + }) + ).rejects.toThrow( + 'No release type found in pull request title "JIRA-123:".' + ); + }); + + it('throws for PR titles without a subject', async () => { + await expect( + validatePrTitle('JIRA-123: ', { + types: ['JIRA-\\d+'], + headerPattern + }) + ).rejects.toThrow('No subject found in pull request title "JIRA-123: ".'); + }); + + it('throws for PR titles that do not match the regex', async () => { + await expect( + validatePrTitle('CONF-123: ', { + types: ['JIRA-\\d+'], + headerPattern + }) + ).rejects.toThrow('No subject found in pull request title "CONF-123: ".'); + }); + + it('throws when an unknown type is detected for auto-wrapping regex', async () => { + await expect( + validatePrTitle('JIRA-123A: Bar', { + types: ['JIRA-\\d+'], + headerPattern + }) + ).rejects.toThrow( + 'Unknown release type "JIRA-123A" found in pull request title "JIRA-123A: Bar". \n\nAvailable types:\n - JIRA-\\d+' + ); + }); + + it('allows scopes when using a regex for the type', async () => { + await validatePrTitle('JIRA-123(core): Bar', { + types: ['JIRA-\\d+'], + headerPattern + }); + }); +}); + describe('defined scopes', () => { it('allows a missing scope by default', async () => { await validatePrTitle('fix: Bar');