From d19d0e8c477354a25d471d5664f3c84993467552 Mon Sep 17 00:00:00 2001 From: Mario Nebl Date: Mon, 1 May 2017 16:56:24 +0200 Subject: [PATCH 1/3] test: add test cases for footer-leading-blank --- test/rules/footer-leading-blank.js | 109 +++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 test/rules/footer-leading-blank.js diff --git a/test/rules/footer-leading-blank.js b/test/rules/footer-leading-blank.js new file mode 100644 index 0000000000..3ecd886f4f --- /dev/null +++ b/test/rules/footer-leading-blank.js @@ -0,0 +1,109 @@ +import test from 'ava'; +import {sync as parse} from 'conventional-commits-parser'; +import footerLeadingBlank from '../../source/rules/footer-leading-blank'; + +const messages = { + simple: 'chore: subject', + body: 'chore: subject\nbody', + trailing: 'chore: subject\nbody\n\n', + without: 'chore: subject\nbody\nBREAKING CHANGE: something important', + with: 'chore: subject\nbody\n\nBREAKING CHANGE: something important' +}; + +const parsed = { + simple: parse(messages.simple), + body: parse(messages.body), + trailing: parse(messages.trailing), + without: parse(messages.without), + with: parse(messages.with) +}; + +test('footer-leading-blank with simple message should succeed for empty keyword', t => { + const [actual] = footerLeadingBlank(parsed.simple); + const expected = true; + t.is(actual, expected); +}); + +test.failing('footer-leading-blank with simple message should succeed for "never"', t => { + const [actual] = footerLeadingBlank(parsed.simple, 'never'); + const expected = true; + t.is(actual, expected); +}); + +test('footer-leading-blank with simple message should succeed for "always"', t => { + const [actual] = footerLeadingBlank(parsed.simple, 'always'); + const expected = true; + t.is(actual, expected); +}); + +test('footer-leading-blank with body message should succeed for empty keyword', t => { + const [actual] = footerLeadingBlank(parsed.body); + const expected = true; + t.is(actual, expected); +}); + +test.failing('footer-leading-blank with body message should succeed for "never"', t => { + const [actual] = footerLeadingBlank(parsed.body, 'never'); + const expected = true; + t.is(actual, expected); +}); + +test('footer-leading-blank with body message should succeed for "always"', t => { + const [actual] = footerLeadingBlank(parsed.body, 'always'); + const expected = true; + t.is(actual, expected); +}); + +test('footer-leading-blank with trailing message should succeed for empty keyword', t => { + const [actual] = footerLeadingBlank(parsed.trailing); + const expected = true; + t.is(actual, expected); +}); + +test.failing('footer-leading-blank with trailing message should succeed for "never"', t => { + const [actual] = footerLeadingBlank(parsed.trailing, 'never'); + const expected = true; + t.is(actual, expected); +}); + +test('footer-leading-blank with trailing message should succeed for "always"', t => { + const [actual] = footerLeadingBlank(parsed.trailing, 'always'); + const expected = true; + t.is(actual, expected); +}); + +test.failing('footer-leading-blank without blank line before footer should fail for empty keyword', t => { + const [actual] = footerLeadingBlank(parsed.without); + const expected = false; + t.is(actual, expected); +}); + +test.failing('footer-leading-blank without blank line before footer should succeed for "never"', t => { + const [actual] = footerLeadingBlank(parsed.without, 'never'); + const expected = true; + t.is(actual, expected); +}); + +test.failing('footer-leading-blank without blank line before footer should fail for "always"', t => { + const [actual] = footerLeadingBlank(parsed.without, 'always'); + const expected = false; + t.is(actual, expected); +}); + +test('footer-leading-blank with blank line before footer should succeed for empty keyword', t => { + const [actual] = footerLeadingBlank(parsed.with); + const expected = true; + t.is(actual, expected); +}); + +test('footer-leading-blank with blank line before footer should fail for "never"', t => { + const [actual] = footerLeadingBlank(parsed.with, 'never'); + const expected = false; + t.is(actual, expected); +}); + +test('footer-leading-blank with blank line before footer should succeed for "always"', t => { + const [actual] = footerLeadingBlank(parsed.with, 'always'); + const expected = true; + t.is(actual, expected); +}); From 6b8f903050fd12efc51fa05594bb3ce57f6897c0 Mon Sep 17 00:00:00 2001 From: Mario Nebl Date: Mon, 1 May 2017 17:02:09 +0200 Subject: [PATCH 2/3] fix: succeed footer-leading-blank if no footer is found --- source/rules/footer-leading-blank.js | 8 ++++++++ test/rules/footer-leading-blank.js | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/source/rules/footer-leading-blank.js b/source/rules/footer-leading-blank.js index 1275c3d58f..8d41a2428a 100644 --- a/source/rules/footer-leading-blank.js +++ b/source/rules/footer-leading-blank.js @@ -1,12 +1,20 @@ export default (parsed, when) => { + // flunk if no footer is found + if (!parsed.footer) { + return [true]; + } + const negated = when === 'never'; + // get complete body split into lines const lines = (parsed.raw || '').split('\n').slice(2); + // check if the first line of body (if any) is empty const leadingBlank = lines.length > 0 ? lines[0].length === 0 : true; + return [ negated ? !leadingBlank : leadingBlank, [ diff --git a/test/rules/footer-leading-blank.js b/test/rules/footer-leading-blank.js index 3ecd886f4f..1f85fc7ab3 100644 --- a/test/rules/footer-leading-blank.js +++ b/test/rules/footer-leading-blank.js @@ -24,7 +24,7 @@ test('footer-leading-blank with simple message should succeed for empty keyword' t.is(actual, expected); }); -test.failing('footer-leading-blank with simple message should succeed for "never"', t => { +test('footer-leading-blank with simple message should succeed for "never"', t => { const [actual] = footerLeadingBlank(parsed.simple, 'never'); const expected = true; t.is(actual, expected); @@ -42,7 +42,7 @@ test('footer-leading-blank with body message should succeed for empty keyword', t.is(actual, expected); }); -test.failing('footer-leading-blank with body message should succeed for "never"', t => { +test('footer-leading-blank with body message should succeed for "never"', t => { const [actual] = footerLeadingBlank(parsed.body, 'never'); const expected = true; t.is(actual, expected); @@ -60,7 +60,7 @@ test('footer-leading-blank with trailing message should succeed for empty keywor t.is(actual, expected); }); -test.failing('footer-leading-blank with trailing message should succeed for "never"', t => { +test('footer-leading-blank with trailing message should succeed for "never"', t => { const [actual] = footerLeadingBlank(parsed.trailing, 'never'); const expected = true; t.is(actual, expected); From 5f7d6111ff9f6b9ce57e251821cb5d08dda853fb Mon Sep 17 00:00:00 2001 From: Mario Nebl Date: Mon, 1 May 2017 17:12:08 +0200 Subject: [PATCH 3/3] fix: sanitize check for leading blank line before footer --- source/index.js | 7 ++----- source/library/parse.js | 9 +++++++++ source/rules/footer-leading-blank.js | 12 +++++------- test/rules/footer-leading-blank.js | 8 ++++---- test/rules/scope-empty.js | 2 +- test/rules/scope-enum.js | 2 +- 6 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 source/library/parse.js diff --git a/source/index.js b/source/index.js index 4d5b4d22f1..607e0046d2 100644 --- a/source/index.js +++ b/source/index.js @@ -1,4 +1,3 @@ -import {sync as parse} from 'conventional-commits-parser'; import {merge} from 'lodash'; import ruleFunctions from './rules'; @@ -6,6 +5,7 @@ import format from './library/format'; import getConfiguration from './library/get-configuration'; import getMessages from './library/get-messages'; import getPreset from './library/get-preset'; +import parse from './library/parse'; export {format, getConfiguration, getMessages, getPreset}; @@ -21,10 +21,7 @@ export default async (message, options = {}) => { } = options; // parse the commit message - const parsed = merge( - {raw: message}, - parse(message, parserOptions) - ); + const parsed = parse(message); // wildcard matches skip the linting const bails = Object.entries(wildcards) diff --git a/source/library/parse.js b/source/library/parse.js new file mode 100644 index 0000000000..74935d4a7b --- /dev/null +++ b/source/library/parse.js @@ -0,0 +1,9 @@ +import {sync} from 'conventional-commits-parser'; + +export default parse; + +function parse(message, options) { + const parsed = sync(message, options); + parsed.raw = message; + return parsed; +} diff --git a/source/rules/footer-leading-blank.js b/source/rules/footer-leading-blank.js index 8d41a2428a..eaec80b41d 100644 --- a/source/rules/footer-leading-blank.js +++ b/source/rules/footer-leading-blank.js @@ -7,16 +7,14 @@ export default (parsed, when) => { const negated = when === 'never'; // get complete body split into lines - const lines = (parsed.raw || '').split('\n').slice(2); + const lines = (parsed.raw || '').split(/\r|\n/).slice(2); + const [leading] = lines; - // check if the first line of body (if any) is empty - const leadingBlank = - lines.length > 0 ? - lines[0].length === 0 : - true; + // check if the first line of body is empty + const succeeds = leading === ''; return [ - negated ? !leadingBlank : leadingBlank, + negated ? !succeeds : succeeds, [ 'footer', negated ? 'may not' : 'must', diff --git a/test/rules/footer-leading-blank.js b/test/rules/footer-leading-blank.js index 1f85fc7ab3..731517ff3c 100644 --- a/test/rules/footer-leading-blank.js +++ b/test/rules/footer-leading-blank.js @@ -1,5 +1,5 @@ import test from 'ava'; -import {sync as parse} from 'conventional-commits-parser'; +import parse from '../../source/library/parse'; import footerLeadingBlank from '../../source/rules/footer-leading-blank'; const messages = { @@ -72,19 +72,19 @@ test('footer-leading-blank with trailing message should succeed for "always"', t t.is(actual, expected); }); -test.failing('footer-leading-blank without blank line before footer should fail for empty keyword', t => { +test('footer-leading-blank without blank line before footer should fail for empty keyword', t => { const [actual] = footerLeadingBlank(parsed.without); const expected = false; t.is(actual, expected); }); -test.failing('footer-leading-blank without blank line before footer should succeed for "never"', t => { +test('footer-leading-blank without blank line before footer should succeed for "never"', t => { const [actual] = footerLeadingBlank(parsed.without, 'never'); const expected = true; t.is(actual, expected); }); -test.failing('footer-leading-blank without blank line before footer should fail for "always"', t => { +test('footer-leading-blank without blank line before footer should fail for "always"', t => { const [actual] = footerLeadingBlank(parsed.without, 'always'); const expected = false; t.is(actual, expected); diff --git a/test/rules/scope-empty.js b/test/rules/scope-empty.js index ba5983151a..3ac7a42041 100644 --- a/test/rules/scope-empty.js +++ b/test/rules/scope-empty.js @@ -1,5 +1,5 @@ import test from 'ava'; -import {sync as parse} from 'conventional-commits-parser'; +import parse from '../../source/library/parse'; import scopeEmpty from '../../source/rules/scope-empty'; const messages = { diff --git a/test/rules/scope-enum.js b/test/rules/scope-enum.js index b1a8f7c4a5..f4a2a26e44 100644 --- a/test/rules/scope-enum.js +++ b/test/rules/scope-enum.js @@ -1,5 +1,5 @@ import test from 'ava'; -import {sync as parse} from 'conventional-commits-parser'; +import parse from '../../source/library/parse'; import scopeEnum from '../../source/rules/scope-enum'; const messages = {