Skip to content

fix: prevent false positives for footer-leading-blank #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions source/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {sync as parse} from 'conventional-commits-parser';
import {merge} from 'lodash';

import ruleFunctions from './rules';
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};

Expand All @@ -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)
Expand Down
9 changes: 9 additions & 0 deletions source/library/parse.js
Original file line number Diff line number Diff line change
@@ -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;
}
20 changes: 13 additions & 7 deletions source/rules/footer-leading-blank.js
Original file line number Diff line number Diff line change
@@ -1,14 +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;
const lines = (parsed.raw || '').split(/\r|\n/).slice(2);
const [leading] = lines;

// check if the first line of body is empty
const succeeds = leading === '';

return [
negated ? !leadingBlank : leadingBlank,
negated ? !succeeds : succeeds,
[
'footer',
negated ? 'may not' : 'must',
Expand Down
109 changes: 109 additions & 0 deletions test/rules/footer-leading-blank.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import test from 'ava';
import parse from '../../source/library/parse';
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('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('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('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('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('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('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);
});
2 changes: 1 addition & 1 deletion test/rules/scope-empty.js
Original file line number Diff line number Diff line change
@@ -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 = {
Expand Down
2 changes: 1 addition & 1 deletion test/rules/scope-enum.js
Original file line number Diff line number Diff line change
@@ -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 = {
Expand Down