From 9bc2858eb211629d9369e4fbc7c9d3d5f966837b Mon Sep 17 00:00:00 2001 From: SimeonC Date: Fri, 15 Mar 2019 19:20:34 +0900 Subject: [PATCH 1/3] feat: config based is-ignored overrides --- @commitlint/is-ignored/src/index.js | 32 +++++++++++-- @commitlint/is-ignored/src/index.test.js | 59 ++++++++++++++++++++++++ @commitlint/lint/src/index.js | 2 +- @commitlint/lint/src/index.test.js | 28 +++++++++++ @commitlint/load/src/index.js | 12 ++++- docs/reference-configuration.md | 23 ++++++++- 6 files changed, 149 insertions(+), 7 deletions(-) diff --git a/@commitlint/is-ignored/src/index.js b/@commitlint/is-ignored/src/index.js index fe8d4d2fe5..76c0324eff 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,32 @@ 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 = {}) { + let wildcards = []; + if (opts.ignoredMessages) { + if (opts.disableDefaultIgnoredMessages) { + wildcards = wildcards.concat(WILDCARDS); + } + if (!Array.isArray(opts.ignoredMessages)) { + throw new Error('ignoredMessages must be an Array'); + } + opts.ignoredMessages.forEach(ignoreConfig => { + if (typeof ignoreConfig === 'function') { + wildcards.push(ignoreConfig); + } else if (ignoreConfig instanceof RegExp) { + wildcards.push(c => c.match(ignoreConfig)); + } else if (typeof ignoreConfig === 'string') { + wildcards.push(c => c.match(new RegExp(ignoreConfig))); + } else { + throw new Error( + 'ignoredMessage element must be a function, string or RegExp' + ); + } + }); + } else if (opts.disableDefaultIgnoredMessages) { + return false; + } else { + wildcards = WILDCARDS; + } + return wildcards.some(w => w(commit)); } diff --git a/@commitlint/is-ignored/src/index.test.js b/@commitlint/is-ignored/src/index.test.js index 3a24892bdd..ddf0f70ce7 100644 --- a/@commitlint/is-ignored/src/index.test.js +++ b/@commitlint/is-ignored/src/index.test.js @@ -117,3 +117,62 @@ 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 disableDefaultIgnoredMessages is true', t => { + t.false( + isIgnored('Auto-merged develop into master', { + disableDefaultIgnoredMessages: true + }) + ); +}); + +test('should return false for ignored message if custom ignoredMessages and disableDefaultIgnoredMessages is true', t => { + t.false( + isIgnored('Auto-merged develop into master', { + disableDefaultIgnoredMessages: true, + ignoredMessages: [] + }) + ); +}); + +test('should throw error if ignoredMessages is not an array', t => { + const ignoredString = 'this should be ignored'; + t.throws( + isIgnored(ignoredString, { + ignoredMessages: 'throws error' + }) + ); +}); + +test('should return true for custom ignoredMessages as function', t => { + const ignoredString = 'this should be ignored'; + t.true( + isIgnored(ignoredString, { + ignoredMessages: [c => c === ignoredString] + }) + ); +}); + +test('should return true for custom ignoredMessages as RegExp', t => { + t.true( + isIgnored('Should Ignore', { + ignoredMessages: [/^should ignore$/i] + }) + ); +}); + +test('should return true for custom ignoredMessages as string', t => { + t.true( + isIgnored('Should Ignore', { + ignoredMessages: ['[sS]hould [iI]gnore'] + }) + ); +}); + +test('should throw error if ignoredMessage value is not an RegExp, string or function', t => { + t.throws( + isIgnored('some commit message', { + ignoredMessages: [true] + }) + ); +}); diff --git a/@commitlint/lint/src/index.js b/@commitlint/lint/src/index.js index 2d2a0527e0..335f7633f6 100644 --- a/@commitlint/lint/src/index.js +++ b/@commitlint/lint/src/index.js @@ -15,7 +15,7 @@ const buildCommitMesage = ({header, body, footer}) => { export default async (message, rules = {}, opts = {}) => { // Found a wildcard match, skip - if (isIgnored(message)) { + if (isIgnored(message, opts)) { return { valid: true, errors: [], diff --git a/@commitlint/lint/src/index.test.js b/@commitlint/lint/src/index.test.js index 9152438b73..b0f75ea072 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'] + }, + { + disableDefaultIgnoredMessages: true + } + ); + 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'] + }, + { + ignoredMessages: [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 bedf967d61..4fef2b83ea 100644 --- a/@commitlint/load/src/index.js +++ b/@commitlint/load/src/index.js @@ -7,7 +7,15 @@ import resolveFrom from 'resolve-from'; const w = (a, b) => (Array.isArray(b) ? b : undefined); const valid = input => - pick(input, 'extends', 'rules', 'parserPreset', 'formatter'); + pick( + input, + 'extends', + 'rules', + 'parserPreset', + 'formatter', + 'ignoredMessages', + 'disableDefaultIgnoredMessages' + ); export default async (seed = {}, options = {cwd: process.cwd()}) => { const loaded = await loadConfig(options.cwd, options.file); @@ -17,7 +25,7 @@ export default async (seed = {}, options = {cwd: process.cwd()}) => { const config = valid(merge(loaded.config, seed)); const opts = merge( {extends: [], rules: {}, formatter: '@commitlint/format'}, - pick(config, 'extends') + pick(config, 'extends', 'ignoredMessages', 'disableDefaultIgnoredMessages') ); // 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; From ae895819ea79f63a092be3697ed305d558b03afd Mon Sep 17 00:00:00 2001 From: Mario Nebl Date: Fri, 26 Apr 2019 15:28:37 +0200 Subject: [PATCH 2/3] style: apply formatting --- @commitlint/load/src/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/@commitlint/load/src/index.js b/@commitlint/load/src/index.js index 510f9de86e..426e75caa1 100644 --- a/@commitlint/load/src/index.js +++ b/@commitlint/load/src/index.js @@ -12,7 +12,7 @@ const valid = input => input, 'extends', 'rules', - 'plugins', + 'plugins', 'parserPreset', 'formatter', 'ignoredMessages', @@ -27,7 +27,13 @@ export default async (seed = {}, options = {cwd: process.cwd()}) => { const config = valid(merge(loaded.config, seed)); const opts = merge( {extends: [], rules: {}, formatter: '@commitlint/format'}, - pick(config, 'extends', 'plugins', 'ignoredMessages', 'disableDefaultIgnoredMessages') + pick( + config, + 'extends', + 'plugins', + 'ignoredMessages', + 'disableDefaultIgnoredMessages' + ) ); // Resolve parserPreset key From 9cd95ca38be82cbe56d09f88f1948aede57dd627 Mon Sep 17 00:00:00 2001 From: Mario Nebl Date: Fri, 26 Apr 2019 16:03:29 +0200 Subject: [PATCH 3/3] refactor: simplify configurable is-ignored --- @commitlint/is-ignored/src/index.js | 45 ++++++++++------------- @commitlint/is-ignored/src/index.test.js | 47 ++++++------------------ @commitlint/lint/src/index.js | 4 +- @commitlint/lint/src/index.test.js | 4 +- @commitlint/load/src/index.js | 12 ++---- 5 files changed, 38 insertions(+), 74 deletions(-) diff --git a/@commitlint/is-ignored/src/index.js b/@commitlint/is-ignored/src/index.js index 76c0324eff..81982cce8c 100644 --- a/@commitlint/is-ignored/src/index.js +++ b/@commitlint/is-ignored/src/index.js @@ -22,31 +22,24 @@ export const WILDCARDS = [ ]; export default function isIgnored(commit = '', opts = {}) { - let wildcards = []; - if (opts.ignoredMessages) { - if (opts.disableDefaultIgnoredMessages) { - wildcards = wildcards.concat(WILDCARDS); - } - if (!Array.isArray(opts.ignoredMessages)) { - throw new Error('ignoredMessages must be an Array'); - } - opts.ignoredMessages.forEach(ignoreConfig => { - if (typeof ignoreConfig === 'function') { - wildcards.push(ignoreConfig); - } else if (ignoreConfig instanceof RegExp) { - wildcards.push(c => c.match(ignoreConfig)); - } else if (typeof ignoreConfig === 'string') { - wildcards.push(c => c.match(new RegExp(ignoreConfig))); - } else { - throw new Error( - 'ignoredMessage element must be a function, string or RegExp' - ); - } - }); - } else if (opts.disableDefaultIgnoredMessages) { - return false; - } else { - wildcards = WILDCARDS; + 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}` + ); } - return wildcards.some(w => w(commit)); + + 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 ddf0f70ce7..5d1a8becf1 100644 --- a/@commitlint/is-ignored/src/index.test.js +++ b/@commitlint/is-ignored/src/index.test.js @@ -118,61 +118,36 @@ test('should return false for commits containing, but not starting, with merge b t.false(isIgnored('foo bar Merge branch xxx')); }); -test('should return false for ignored message if disableDefaultIgnoredMessages is true', t => { +test('should return false for ignored message if defaults is false', t => { t.false( isIgnored('Auto-merged develop into master', { - disableDefaultIgnoredMessages: true + defaults: false }) ); }); -test('should return false for ignored message if custom ignoredMessages and disableDefaultIgnoredMessages is true', t => { +test('should return false for ignored message if custom ignores and defaults is false', t => { t.false( isIgnored('Auto-merged develop into master', { - disableDefaultIgnoredMessages: true, - ignoredMessages: [] + defaults: false }) ); }); -test('should throw error if ignoredMessages is not an array', t => { +test('should throw error if ignores is not an array', t => { const ignoredString = 'this should be ignored'; - t.throws( + t.throws(() => { isIgnored(ignoredString, { - ignoredMessages: 'throws error' - }) - ); + ignores: 'throws error' + }); + }); }); -test('should return true for custom ignoredMessages as function', t => { +test('should return true for custom ignores as function', t => { const ignoredString = 'this should be ignored'; t.true( isIgnored(ignoredString, { - ignoredMessages: [c => c === ignoredString] - }) - ); -}); - -test('should return true for custom ignoredMessages as RegExp', t => { - t.true( - isIgnored('Should Ignore', { - ignoredMessages: [/^should ignore$/i] - }) - ); -}); - -test('should return true for custom ignoredMessages as string', t => { - t.true( - isIgnored('Should Ignore', { - ignoredMessages: ['[sS]hould [iI]gnore'] - }) - ); -}); - -test('should throw error if ignoredMessage value is not an RegExp, string or function', t => { - t.throws( - isIgnored('some commit message', { - ignoredMessages: [true] + ignores: [c => c === ignoredString] }) ); }); diff --git a/@commitlint/lint/src/index.js b/@commitlint/lint/src/index.js index 1dbde9003a..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, opts)) { + 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 ddbbf124a9..80ac3d8e8b 100644 --- a/@commitlint/lint/src/index.test.js +++ b/@commitlint/lint/src/index.test.js @@ -45,7 +45,7 @@ test('negative on ignored message, disabled ignored messages and broken rule', a 'type-empty': [2, 'never'] }, { - disableDefaultIgnoredMessages: true + defaultIgnores: false } ); t.false(actual.valid); @@ -59,7 +59,7 @@ test('positive on custom ignored message and broken rule', async t => { 'type-empty': [2, 'never'] }, { - ignoredMessages: [c => c === ignoredMessage] + ignores: [c => c === ignoredMessage] } ); t.true(actual.valid); diff --git a/@commitlint/load/src/index.js b/@commitlint/load/src/index.js index 426e75caa1..d617be64d5 100644 --- a/@commitlint/load/src/index.js +++ b/@commitlint/load/src/index.js @@ -15,8 +15,8 @@ const valid = input => 'plugins', 'parserPreset', 'formatter', - 'ignoredMessages', - 'disableDefaultIgnoredMessages' + 'ignores', + 'defaultIgnores' ); export default async (seed = {}, options = {cwd: process.cwd()}) => { @@ -27,13 +27,7 @@ export default async (seed = {}, options = {cwd: process.cwd()}) => { const config = valid(merge(loaded.config, seed)); const opts = merge( {extends: [], rules: {}, formatter: '@commitlint/format'}, - pick( - config, - 'extends', - 'plugins', - 'ignoredMessages', - 'disableDefaultIgnoredMessages' - ) + pick(config, 'extends', 'plugins', 'ignores', 'defaultIgnores') ); // Resolve parserPreset key