From 2434d71c2f71afe4ce7f64c723cd18aebd2b2aeb Mon Sep 17 00:00:00 2001 From: Simeon Cheeseman Date: Fri, 26 Apr 2019 23:06:04 +0900 Subject: [PATCH] feat: config based is-ignored overrides (#595) * feat: config based is-ignored overrides * style: apply formatting * refactor: simplify configurable is-ignored --- @commitlint/is-ignored/src/index.js | 25 ++++++++++++++--- @commitlint/is-ignored/src/index.test.js | 34 ++++++++++++++++++++++++ @commitlint/lint/src/index.js | 4 ++- @commitlint/lint/src/index.test.js | 28 +++++++++++++++++++ @commitlint/load/src/index.js | 15 ++++++++--- docs/reference-configuration.md | 23 +++++++++++++++- 6 files changed, 121 insertions(+), 8 deletions(-) diff --git a/@commitlint/is-ignored/src/index.js b/@commitlint/is-ignored/src/index.js index fe8d4d2fe5..81982cce8c 100644 --- a/@commitlint/is-ignored/src/index.js +++ b/@commitlint/is-ignored/src/index.js @@ -1,6 +1,6 @@ import semver from 'semver'; -const WILDCARDS = [ +export const WILDCARDS = [ c => c.match( /^((Merge pull request)|(Merge (.*?) into (.*?)|(Merge branch (.*?)))(?:\r?\n)*$)/m @@ -21,6 +21,25 @@ const WILDCARDS = [ c => c.match(/^Auto-merged (.*?) into (.*)/) ]; -export default function isIgnored(commit = '') { - return WILDCARDS.some(w => w(commit)); +export default function isIgnored(commit = '', opts = {}) { + const ignores = typeof opts.ignores === 'undefined' ? [] : opts.ignores; + + if (!Array.isArray(ignores)) { + throw new Error( + `ignores must be of type array, received ${ignores} of type ${typeof ignores}` + ); + } + + const invalids = ignores.filter(c => typeof c !== 'function'); + + if (invalids.length > 0) { + throw new Error( + `ignores must be array of type function, received items of type: ${invalids + .map(i => typeof i) + .join(', ')}` + ); + } + + const base = opts.defaults === false ? [] : WILDCARDS; + return [...base, ...ignores].some(w => w(commit)); } diff --git a/@commitlint/is-ignored/src/index.test.js b/@commitlint/is-ignored/src/index.test.js index 3a24892bdd..5d1a8becf1 100644 --- a/@commitlint/is-ignored/src/index.test.js +++ b/@commitlint/is-ignored/src/index.test.js @@ -117,3 +117,37 @@ test('should return true for automatic merge commits', t => { test('should return false for commits containing, but not starting, with merge branch', t => { t.false(isIgnored('foo bar Merge branch xxx')); }); + +test('should return false for ignored message if defaults is false', t => { + t.false( + isIgnored('Auto-merged develop into master', { + defaults: false + }) + ); +}); + +test('should return false for ignored message if custom ignores and defaults is false', t => { + t.false( + isIgnored('Auto-merged develop into master', { + defaults: false + }) + ); +}); + +test('should throw error if ignores is not an array', t => { + const ignoredString = 'this should be ignored'; + t.throws(() => { + isIgnored(ignoredString, { + ignores: 'throws error' + }); + }); +}); + +test('should return true for custom ignores as function', t => { + const ignoredString = 'this should be ignored'; + t.true( + isIgnored(ignoredString, { + ignores: [c => c === ignoredString] + }) + ); +}); diff --git a/@commitlint/lint/src/index.js b/@commitlint/lint/src/index.js index bb3148aaaa..25e2fd64c9 100644 --- a/@commitlint/lint/src/index.js +++ b/@commitlint/lint/src/index.js @@ -15,7 +15,9 @@ const buildCommitMesage = ({header, body, footer}) => { export default async (message, rules = {}, opts = {}) => { // Found a wildcard match, skip - if (isIgnored(message)) { + if ( + isIgnored(message, {defaults: opts.defaultIgnores, ignores: opts.ignores}) + ) { return { valid: true, errors: [], diff --git a/@commitlint/lint/src/index.test.js b/@commitlint/lint/src/index.test.js index 9e1cd3bd95..80ac3d8e8b 100644 --- a/@commitlint/lint/src/index.test.js +++ b/@commitlint/lint/src/index.test.js @@ -38,6 +38,34 @@ test('positive on ignored message and broken rule', async t => { t.is(actual.input, 'Revert "some bogus commit"'); }); +test('negative on ignored message, disabled ignored messages and broken rule', async t => { + const actual = await lint( + 'Revert "some bogus commit"', + { + 'type-empty': [2, 'never'] + }, + { + defaultIgnores: false + } + ); + t.false(actual.valid); +}); + +test('positive on custom ignored message and broken rule', async t => { + const ignoredMessage = 'some ignored custom message'; + const actual = await lint( + ignoredMessage, + { + 'type-empty': [2, 'never'] + }, + { + ignores: [c => c === ignoredMessage] + } + ); + t.true(actual.valid); + t.is(actual.input, ignoredMessage); +}); + test('positive on stub message and opts', async t => { const actual = await lint( 'foo-bar', diff --git a/@commitlint/load/src/index.js b/@commitlint/load/src/index.js index 9dd20b9388..d617be64d5 100644 --- a/@commitlint/load/src/index.js +++ b/@commitlint/load/src/index.js @@ -8,7 +8,16 @@ import loadPlugin from './utils/loadPlugin'; const w = (a, b) => (Array.isArray(b) ? b : undefined); const valid = input => - pick(input, 'extends', 'plugins', 'rules', 'parserPreset', 'formatter'); + pick( + input, + 'extends', + 'rules', + 'plugins', + 'parserPreset', + 'formatter', + 'ignores', + 'defaultIgnores' + ); export default async (seed = {}, options = {cwd: process.cwd()}) => { const loaded = await loadConfig(options.cwd, options.file); @@ -17,8 +26,8 @@ export default async (seed = {}, options = {cwd: process.cwd()}) => { // Merge passed config with file based options const config = valid(merge(loaded.config, seed)); const opts = merge( - {extends: [], plugins: [], rules: {}, formatter: '@commitlint/format'}, - pick(config, 'extends', 'plugins') + {extends: [], rules: {}, formatter: '@commitlint/format'}, + pick(config, 'extends', 'plugins', 'ignores', 'defaultIgnores') ); // Resolve parserPreset key diff --git a/docs/reference-configuration.md b/docs/reference-configuration.md index 24aea96af8..06aff5fa91 100644 --- a/docs/reference-configuration.md +++ b/docs/reference-configuration.md @@ -26,6 +26,14 @@ type Config = { * Rules to check against */ rules?: {[name: string]: Rule}; + /* + * Custom list of Messages to Ignore, string values will be compiled as RegExp + */ + ignoredMessages?: Array boolean>; + /* + * If this is true we will not use any of the default is-ignored rules + */ + disableDefaultIgnoredMessages?: boolean; } const Configuration: Config = { @@ -49,7 +57,20 @@ const Configuration: Config = { */ rules: { 'type-enum': [2, 'always', ['foo']] - } + }, + /* + * These RegExp and functions are used to ignore messages that shouldn't be linted + */ + ignoredMessages: [ + '^Entire Message to Ignore$', + /^(ci|github):/, + (commit) => commit === '' + ], + /* + * If this is true then the default ignores like `Merge commit` are not ignored + * and will cause commitlint to fail + */ + disableDefaultIgnoredMessages: true }; module.exports = Configuration;