diff --git a/@commitlint/core/src/library/ensure-contains.js b/@commitlint/core/src/library/ensure-contains.js new file mode 100644 index 0000000000..55b7a0e279 --- /dev/null +++ b/@commitlint/core/src/library/ensure-contains.js @@ -0,0 +1,9 @@ +export default (value, regex) => { + if (value === undefined) { + return false; + } + if (!(regex instanceof RegExp)) { + return false; + } + return regex.test(value); +}; diff --git a/@commitlint/core/src/library/ensure-contains.test.js b/@commitlint/core/src/library/ensure-contains.test.js new file mode 100644 index 0000000000..fb78ffeb33 --- /dev/null +++ b/@commitlint/core/src/library/ensure-contains.test.js @@ -0,0 +1,17 @@ +import test from 'ava'; +import ensure from './ensure-contains'; + +test('false for no params', t => { + const actual = ensure(); + t.is(actual, false); +}); + +test('true for /^foo/gi against foo', t => { + const actual = ensure('foo', /^foo/gi); + t.is(actual, true); +}); + +test('false for /^foo/gi against notfoo', t => { + const actual = ensure('notfoo', /^foo/gi); + t.is(actual, false); +}); \ No newline at end of file diff --git a/@commitlint/core/src/rules/footer-contains.js b/@commitlint/core/src/rules/footer-contains.js new file mode 100644 index 0000000000..6dc96681d8 --- /dev/null +++ b/@commitlint/core/src/rules/footer-contains.js @@ -0,0 +1,16 @@ +import ensureContains from '../library/ensure-contains'; +import message from '../library/message'; + +export default (parsed, when, value) => { + const negated = when === 'never'; + const result = value.length === 0 || ensureContains(parsed.footer, value); + + return [ + negated ? !result : result, + message([ + `footer content must`, + negated ? `not` : null, + `pass the regular expression: ${value.toString()}` + ]) + ]; +}; diff --git a/@commitlint/core/src/rules/footer-contains.test.js b/@commitlint/core/src/rules/footer-contains.test.js new file mode 100644 index 0000000000..59f1ad0eb9 --- /dev/null +++ b/@commitlint/core/src/rules/footer-contains.test.js @@ -0,0 +1,50 @@ +import test from 'ava'; +import parse from '../library/parse'; +import footerContains from './footer-contains'; + +const messages = { + empty: 'foo(bar): baz', + matched: 'chore: subject\nBREAKING CHANGE: something important', + matchedAlt: + 'chore: subject\n\nsomething something fixed that issue\n\ncloses #1', + unmatched: 'foo(bar): baz\n\nbody\n\nPROJEKT-001' +}; + +const parsed = { + empty: parse(messages.empty), + matched: parse(messages.matched), + matchedAlt: parse(messages.matchedAlt), + unmatched: parse(messages.unmatched) +}; + +test('footer-contains with no footer should not succeed', async t => { + const [actual] = footerContains(await parsed.empty, 'always', /qux$/gi); + const expected = false; + t.deepEqual(actual, expected); +}); + +test('footer-contains with matching footer should succeed', async t => { + const [actual] = footerContains( + await parsed.matched, + 'always', + /important$/gi + ); + const expected = true; + t.deepEqual(actual, expected); +}); + +test('footer-contains with alternate matching footer should succeed', async t => { + const [actual] = footerContains( + await parsed.matchedAlt, + 'always', + /Closes #\d+$/gi + ); + const expected = true; + t.deepEqual(actual, expected); +}); + +test('footer-contains with non-matching footer should not succeed', async t => { + const [actual] = footerContains(await parsed.unmatched, 'always', /qux$/gi); + const expected = false; + t.deepEqual(actual, expected); +}); diff --git a/@commitlint/core/src/rules/index.js b/@commitlint/core/src/rules/index.js index 4d62e894b8..34d47ee25c 100644 --- a/@commitlint/core/src/rules/index.js +++ b/@commitlint/core/src/rules/index.js @@ -5,6 +5,7 @@ export default { 'body-max-length': require('./body-max-length'), 'body-min-length': require('./body-min-length'), 'body-tense': require('./body-tense'), + 'footer-contains': require('./footer-contains'), 'footer-empty': require('./footer-empty'), 'footer-leading-blank': require('./footer-leading-blank'), 'footer-max-length': require('./footer-max-length'), diff --git a/docs/reference-rules.md b/docs/reference-rules.md index ead3a886a5..118f015ed0 100644 --- a/docs/reference-rules.md +++ b/docs/reference-rules.md @@ -71,6 +71,14 @@ Rule configurations are either of type `array` residing on a key with the rule's ] ``` +#### footer-contains +* **condition**: `footer` matches regular expression +* **rules**: `always` +* **value** +```js + RegExp +``` + #### footer-leading-blank * **condition**: `footer` begins with blank line * **rule**: `always`