diff --git a/.github/workflows/lint-pr-title.yml b/.github/workflows/lint-pr-title.yml index 4938e6e5a..52c20e77a 100644 --- a/.github/workflows/lint-pr-title.yml +++ b/.github/workflows/lint-pr-title.yml @@ -1,6 +1,6 @@ name: 'Lint PR title' on: - pull_request_target: + pull_request: types: - opened - edited diff --git a/README.md b/README.md index 0029a2cf8..2b72b4914 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ jobs: - uses: amannn/action-semantic-pull-request@v1.2.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Optionally you can configure which types are allowed. + # Default: https://github.com/commitizen/conventional-commit-types + with: + types: fix, feat ``` Note the usage of [`pull_request_target`](https://github.blog/2020-08-03-github-actions-improvements-for-fork-and-pull-request-workflows/) as the event trigger is necessary for a fork-based workflow so the API token is valid for status reporting. diff --git a/action.yml b/action.yml index f21c72f13..85ac342ef 100644 --- a/action.yml +++ b/action.yml @@ -7,3 +7,6 @@ runs: branding: icon: 'shield' color: 'green' +inputs: + types: + description: "Provide custom types if you don't want the default ones from https://www.conventionalcommits.org" diff --git a/src/index.js b/src/index.js index 70e423b2f..225d6d222 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,11 @@ module.exports = async function run() { try { const client = new github.GitHub(process.env.GITHUB_TOKEN); + let types; + if (process.env.INPUT_TYPES) { + types = process.env.INPUT_TYPES.split(',').map((type) => type.trim()); + } + const contextPullRequest = github.context.payload.pull_request; if (!contextPullRequest) { throw new Error( @@ -32,7 +37,7 @@ module.exports = async function run() { let validationError; if (!isWip) { try { - await validatePrTitle(pullRequest.title); + await validatePrTitle(pullRequest.title, types); } catch (error) { validationError = error; } diff --git a/src/validatePrTitle.js b/src/validatePrTitle.js index 10a50d1c4..42978a3f9 100644 --- a/src/validatePrTitle.js +++ b/src/validatePrTitle.js @@ -2,24 +2,37 @@ const conventionalCommitsConfig = require('conventional-changelog-conventionalco const conventionalCommitTypes = require('conventional-commit-types'); const parser = require('conventional-commits-parser').sync; -module.exports = async function validatePrTitle(prTitle) { +const defaultTypes = Object.keys(conventionalCommitTypes.types); + +module.exports = async function validatePrTitle(prTitle, types = defaultTypes) { const {parserOpts} = await conventionalCommitsConfig(); const result = parser(prTitle, parserOpts); + function printAvailableTypes() { + return `Available types:\n${types + .map((type) => { + let bullet = ` - ${type}`; + + if (types === defaultTypes) { + bullet += `: ${conventionalCommitTypes.types[type].description}`; + } + + return bullet; + }) + .join('\n')}`; + } + if (!result.type) { throw new Error( - `No release type found in pull request title "${prTitle}".` + - '\n\nAdd a prefix like "fix: ", "feat: " or "feat!: " to indicate what kind of release this pull request corresponds to. The title should match the commit mesage format as specified by https://www.conventionalcommits.org/.' + `No release type found in pull request title "${prTitle}". Add a prefix to indicate what kind of release this pull request corresponds to (see https://www.conventionalcommits.org/).\n\n${printAvailableTypes()}` ); } - const allowedTypes = Object.keys(conventionalCommitTypes.types); - if (!allowedTypes.includes(result.type)) { + if (!types.includes(result.type)) { throw new Error( - `Unknown release type "${result.type}" found in pull request title "${prTitle}".` + - `\n\nPlease use one of these recognized types: ${allowedTypes.join( - ', ' - )}.` + `Unknown release type "${ + result.type + }" found in pull request title "${prTitle}". \n\n${printAvailableTypes()}` ); } }; diff --git a/src/validatePrTitle.test.js b/src/validatePrTitle.test.js index 28b623ba5..6b1b2f7c0 100644 --- a/src/validatePrTitle.test.js +++ b/src/validatePrTitle.test.js @@ -1,6 +1,6 @@ const validatePrTitle = require('./validatePrTitle'); -it('detects valid PR titles', async () => { +it('allows valid PR titles that use the default types', async () => { const inputs = [ 'fix: Fix bug', 'fix!: Fix bug', @@ -10,8 +10,7 @@ it('detects valid PR titles', async () => { ]; for (let index = 0; index < inputs.length; index++) { - const input = inputs[index]; - await validatePrTitle(input); + await validatePrTitle(inputs[index]); } }); @@ -26,3 +25,22 @@ it('throws for PR titles with an unknown type', async () => { /Unknown release type "foo" found in pull request title "foo: Bar"./ ); }); + +describe('custom types', () => { + it('allows PR titles with a supported type', async () => { + const inputs = ['foo: Foobar', 'bar: Foobar', 'baz: Foobar']; + const types = ['foo', 'bar', 'baz']; + + for (let index = 0; index < inputs.length; index++) { + await validatePrTitle(inputs[index], types); + } + }); + + it('throws for PR titles with an unknown type', async () => { + await expect( + validatePrTitle('fix: Foobar', ['foo', 'bar']) + ).rejects.toThrow( + /Unknown release type "fix" found in pull request title "fix: Foobar"./ + ); + }); +});