Skip to content
This repository was archived by the owner on Feb 21, 2020. It is now read-only.

Commit 91d3b48

Browse files
author
Charlike Mike Reagent
committed
feat: allow empty footer too (git commit defaults)
Signed-off-by: Charlike Mike Reagent <[email protected]>
1 parent a885376 commit 91d3b48

13 files changed

+54
-25
lines changed

src/commit.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,11 @@ export function checkCommit(commit) {
158158

159159
const isValid =
160160
'footer' in commit && commit.footer !== null
161-
? isValidString(commit.footer)
161+
? typeof commit.footer === 'string'
162162
: true;
163163

164164
if (!isValid) {
165-
throw new TypeError('commit.footer should be non empty string when given');
165+
throw new TypeError('commit.footer should be string when given');
166166
}
167167

168168
return Object.assign({ body: null, footer: null }, commit, { header });

test/commit/check.test.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,7 @@ test('.checkCommit throw if commit.body is not a string when given', (t) => {
3838
});
3939
test('.checkCommit throw if commit.footer is not a string when given', (t) => {
4040
const commit = { header: { type: 'fix', subject: 'qux zaz' }, footer: 123 };
41-
t.throws(
42-
() => checkCommit(commit),
43-
/footer should be non empty string when given/,
44-
);
41+
t.throws(() => checkCommit(commit), /footer should be string when given/);
4542
});
4643

4744
test('.checkCommit should commit.body be `null` when explicitly null given', (t) => {
@@ -96,10 +93,18 @@ test('.checkCommit object with scope, body and footer', (t) => {
9693
t.deepStrictEqual(checkCommit(commit), commit);
9794
});
9895

99-
test('should checkCommit allow empty string body', (t) => {
96+
test('should checkCommit allow empty string body (git commit deafults)', (t) => {
10097
const header = { type: 'feat', scope: 'zazzy', subject: 'okey dude' };
10198
const commit = { header, body: '' };
10299
const result = checkCommit(commit);
103100

104101
t.strictEqual(result.body, '');
105102
});
103+
104+
test('should checkCommit allow empty string footer (git commit deafults)', (t) => {
105+
const header = { type: 'feat', scope: 'zazzy', subject: 'okey dude' };
106+
const commit = { header, footer: '' };
107+
const result = checkCommit(commit);
108+
109+
t.strictEqual(result.footer, '');
110+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{".checkCommit throw if not object given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":1,"str":"(t) => {\n t.throws(() => checkCommit({}), TypeError);\n t.throws(() => checkCommit([]), TypeError);\n t.throws(() => checkCommit(null), TypeError);\n t.throws(() => checkCommit(123), /expect `commit` to be an object/);\n}","title":".checkCommit throw if not object given"},".checkCommit throw if commit.header.type is not a string":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":2,"str":"(t) => {\n const fixture = () => checkCommit({ header: { foo: 'bar' } });\n t.throws(fixture, /type should be non empty string/);\n}","title":".checkCommit throw if commit.header.type is not a string"},".checkCommit throw if commit.header.subject is not a string":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":3,"str":"(t) => {\n t.throws(\n () => checkCommit({ header: { type: 'fix' } }),\n /subject should be non empty string/,\n );\n t.throws(\n () => checkCommit({ header: { type: 'fix', subject: '' } }),\n /subject should be non empty string/,\n );\n}","title":".checkCommit throw if commit.header.subject is not a string"},".checkCommit throw if commit.header.scope is not a string when given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":4,"str":"(t) => {\n const commit = { header: { type: 'fix', subject: 'qux zaz', scope: 123 } };\n t.throws(\n () => checkCommit(commit),\n /scope should be non empty string when given/,\n );\n}","title":".checkCommit throw if commit.header.scope is not a string when given"},".checkCommit throw if commit.body is not a string when given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":5,"str":"(t) => {\n const commit = { header: { type: 'fix', subject: 'qux zaz' }, body: 123 };\n t.throws(() => checkCommit(commit), /body should be string when given/);\n}","title":".checkCommit throw if commit.body is not a string when given"},".checkCommit throw if commit.footer is not a string when given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":6,"str":"(t) => {\n const commit = { header: { type: 'fix', subject: 'qux zaz' }, footer: 123 };\n t.throws(() => checkCommit(commit), /footer should be string when given/);\n}","title":".checkCommit throw if commit.footer is not a string when given"},".checkCommit should commit.body be `null` when explicitly null given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":7,"str":"(t) => {\n const header = { type: 'fix', scope: 'cli', subject: 'zzz' };\n const commit = { header, body: null, footer: 'xyz' };\n const result = checkCommit(commit);\n\n t.deepStrictEqual(result, {\n header: { type: 'fix', scope: 'cli', subject: 'zzz' },\n body: null,\n footer: 'xyz',\n });\n}","title":".checkCommit should commit.body be `null` when explicitly null given"},".checkCommit should commit.body be null when not given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":8,"str":"(t) => {\n const header = { type: 'feat', scope: 'zazzy', subject: 'okey dude' };\n const commit = { header, footer: 'ok ok' };\n const result = checkCommit(commit);\n\n t.deepStrictEqual(result, { header, body: null, footer: 'ok ok' });\n}","title":".checkCommit should commit.body be null when not given"},".checkCommit should commit.footer be `null` when explicitly null given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":9,"str":"(t) => {\n const header = { type: 'fix', scope: 'cli', subject: 'zzz' };\n const commit = { header, footer: null, body: 'BREAKING CHANGE: whoa!' };\n const result = checkCommit(commit);\n\n t.deepStrictEqual(result, {\n header: { type: 'fix', scope: 'cli', subject: 'zzz' },\n body: 'BREAKING CHANGE: whoa!',\n footer: null,\n });\n}","title":".checkCommit should commit.footer be `null` when explicitly null given"},".checkCommit should commit.footer be null when not given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":10,"str":"(t) => {\n const header = { type: 'feat', scope: 'zazzy', subject: 'okey dude' };\n const commit = { header };\n const result = checkCommit(commit);\n t.deepStrictEqual(result, { header, body: null, footer: null });\n}","title":".checkCommit should commit.footer be null when not given"},".checkCommit object with scope, body and footer":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":11,"str":"(t) => {\n const commit = {\n header: {\n type: 'feat',\n scope: 'quxie',\n subject: 'woo hoo',\n },\n body: 'qux zaz faz',\n footer: 'Breaking yeah',\n };\n t.deepStrictEqual(checkCommit(commit), commit);\n}","title":".checkCommit object with scope, body and footer"},"should checkCommit allow empty string body (git commit deafults)":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":12,"str":"(t) => {\n const header = { type: 'feat', scope: 'zazzy', subject: 'okey dude' };\n const commit = { header, body: '' };\n const result = checkCommit(commit);\n\n t.strictEqual(result.body, '');\n}","title":"should checkCommit allow empty string body (git commit deafults)"},"should checkCommit allow empty string footer (git commit deafults)":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":13,"str":"(t) => {\n const header = { type: 'feat', scope: 'zazzy', subject: 'okey dude' };\n const commit = { header, footer: '' };\n const result = checkCommit(commit);\n\n t.strictEqual(result.footer, '');\n}","title":"should checkCommit allow empty string footer (git commit deafults)"}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{".stringifyCommit throw if invalid header is given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":1,"str":"(t) => {\n t.throws(() => stringifyCommit(1234), TypeError);\n t.throws(() => stringifyCommit({ header: { type: 'foo' } }), TypeError);\n t.throws(() => stringifyCommit(), /expect `commit` to be an object/);\n}","title":".stringifyCommit throw if invalid header is given"},".stringifyCommit object":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":2,"str":"(t) => {\n const header = { type: 'fix', scope: 'huh', subject: 'yeah yeah' };\n const result = stringifyCommit({ header });\n\n t.strictEqual(result, 'fix(huh): yeah yeah');\n\n const cmt = {\n header,\n body: 'resolves #1\\nfixes #3',\n footer: 'BREAKING CHANGE: yeah!',\n };\n const commitMessage = dedent`${result}\n\n resolves #1\n fixes #3\n\n BREAKING CHANGE: yeah!`;\n\n t.strictEqual(stringifyCommit(cmt), commitMessage);\n}","title":".stringifyCommit object"},".stringifyCommit object without scope":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":3,"str":"(t) => {\n const header = {\n header: { type: 'fix', subject: 'yeah yeah' },\n body: 'woo hoo',\n };\n const result = stringifyCommit(header);\n\n t.strictEqual(result, 'fix: yeah yeah\\n\\nwoo hoo');\n}","title":".stringifyCommit object without scope"}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{".validateCommit should return boolean when second param `ret` is not given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":1,"str":"(t) => {\n const header = { type: 'fix', subject: 'bar qux' };\n const boolTrue = validateCommit({\n header,\n body: 'foo',\n });\n const boolFalse = validateCommit({ header, body: 111, footer: 'sasa' });\n\n t.strictEqual(boolTrue, true);\n t.strictEqual(boolFalse, false);\n}","title":".validateCommit should return boolean when second param `ret` is not given"},".validateCommit should return { error, value } object when `ret` is true":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":2,"str":"(t) => {\n const header = { type: 'major', scope: 'qux', subject: 'some awful change' };\n const result = validateCommit({ header, body: 'okkk' }, true);\n\n t.deepStrictEqual(result, {\n value: { header, body: 'okkk', footer: null },\n });\n\n const res2 = validateCommit({ header: { foo: 1 }, body: 'a' }, true);\n t.ok(res2.error);\n t.ok(res2.error instanceof Error);\n t.ok(!res2.value);\n}","title":".validateCommit should return { error, value } object when `ret` is true"}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{".checkHeader throw if not object given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":1,"str":"(t) => {\n t.throws(() => checkHeader({}), TypeError);\n t.throws(() => checkHeader([]), TypeError);\n t.throws(() => checkHeader(null), TypeError);\n t.throws(() => checkHeader(123), /expect `header` to be an object/);\n}","title":".checkHeader throw if not object given"},".checkHeader throw if header.type is not a string":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":2,"str":"(t) => {\n const fixture = () => checkHeader({ foo: 'bar' });\n t.throws(fixture, /type should be non empty string/);\n}","title":".checkHeader throw if header.type is not a string"},".checkHeader throw if header.subject is not a string":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":3,"str":"(t) => {\n t.throws(\n () => checkHeader({ type: 'fix' }),\n /subject should be non empty string/,\n );\n t.throws(\n () => checkHeader({ type: 'fix', subject: '' }),\n /subject should be non empty string/,\n );\n}","title":".checkHeader throw if header.subject is not a string"},".checkHeader throw if header.scope is not a string when given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":4,"str":"(t) => {\n t.throws(\n () => checkHeader({ type: 'fix', subject: 'qux zaz', scope: 123 }),\n /scope should be non empty string when given/,\n );\n}","title":".checkHeader throw if header.scope is not a string when given"},".checkHeader should header.scope be `null` when explicitly null given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":5,"str":"(t) => {\n const result = checkHeader({ type: 'fix', subject: 'ss', scope: null });\n t.deepStrictEqual(result, { type: 'fix', subject: 'ss', scope: null });\n}","title":".checkHeader should header.scope be `null` when explicitly null given"},".checkHeader should header.scope be null when not given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":6,"str":"(t) => {\n const res = checkHeader({ type: 'aaa', subject: 'quxie bar' });\n t.deepStrictEqual(res, { type: 'aaa', subject: 'quxie bar', scope: null });\n}","title":".checkHeader should header.scope be null when not given"},".checkHeader correctly header object without scope":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":7,"str":"(t) => {\n const result = checkHeader({\n type: 'fix',\n subject: 'bar qux',\n });\n\n t.deepStrictEqual(result, { type: 'fix', scope: null, subject: 'bar qux' });\n}","title":".checkHeader correctly header object without scope"},".checkHeader object with scope":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":8,"str":"(t) => {\n const header = {\n type: 'feat',\n scope: 'quxie',\n subject: 'woo hoo',\n };\n\n t.deepStrictEqual(checkHeader(header), header);\n}","title":".checkHeader object with scope"}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{".parseHeader throw if not a string given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":1,"str":"(t) => {\n t.throws(() => parseHeader(123), TypeError);\n t.throws(() => parseHeader(123), /expect `header` to be non empty string/);\n t.throws(() => parseHeader(''), /expect `header` to be non empty string/);\n}","title":".parseHeader throw if not a string given"},".parseHeader throw when invalid conventional commits":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":2,"str":"(t) => {\n function fixture() {\n parseHeader('fix bar qux');\n }\n t.throws(fixture, Error);\n t.throws(fixture, /<type>\\[optional scope\\]: <description>/);\n}","title":".parseHeader throw when invalid conventional commits"},".parseHeader NOT throw when header is valid by conventional commits":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":3,"str":"(t) => {\n const one = parseHeader('fix: zzz qux');\n const two = parseHeader('fix(cli): aaaa qux');\n const res = parseHeader('fix(cli): qqqqq qux\\n\\nSome awesome body');\n\n t.ok(isObject(one));\n t.ok(isObject(two));\n t.ok(isObject(res));\n}","title":".parseHeader NOT throw when header is valid by conventional commits"},".parseHeader correctly header string without scope":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":4,"str":"(t) => {\n const result = parseHeader('fix: bar qux');\n\n t.deepStrictEqual(result, { type: 'fix', scope: null, subject: 'bar qux' });\n}","title":".parseHeader correctly header string without scope"},".parseHeader header string with scope":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":5,"str":"(t) => {\n t.deepStrictEqual(parseHeader('fix(cli): bar qux'), {\n type: 'fix',\n scope: 'cli',\n subject: 'bar qux',\n });\n}","title":".parseHeader header string with scope"}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{".validateHeader should return boolean when second param `ret` is not given":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":1,"str":"(t) => {\n const boolTrue = validateHeader({ type: 'fix', subject: 'bar qux' });\n const boolFalse = validateHeader({ type: 'fix' });\n\n t.strictEqual(boolTrue, true);\n t.strictEqual(boolFalse, false);\n}","title":".validateHeader should return boolean when second param `ret` is not given"},".validateHeader should return { error, value } object when `ret` is true":{"skip":false,"todo":false,"run":false,"isPending":false,"isRejected":false,"isFulfilled":true,"id":2,"str":"(t) => {\n const result = validateHeader({ type: 'fix', subject: 'bar qux' }, true);\n\n t.deepStrictEqual(result, {\n value: { type: 'fix', scope: null, subject: 'bar qux' },\n });\n\n const res2 = validateHeader({ type: 'fix' }, true);\n t.ok(res2.error);\n t.ok(res2.error instanceof Error);\n t.ok(!res2.value);\n}","title":".validateHeader should return { error, value } object when `ret` is true"}}

test/index.js

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -112,24 +112,39 @@ test('should result.increment be false if no bump needed', (t) => {
112112

113113
test('ensure most common usage', (t) => {
114114
const commitMsg = 'fix: bar qux';
115-
const res1 = applyPlugins(plugins, check(parse(commitMsg)));
116-
const res2 = applyPlugins(plugins, check(parse(commitMsg + EOL)));
117-
const res3 = applyPlugins(plugins, check(parse(commitMsg + EOL + EOL)));
115+
const [res1] = applyPlugins(plugins, check(parse(commitMsg)));
116+
const [res2] = applyPlugins(plugins, check(parse(commitMsg + EOL)));
117+
const [res3] = applyPlugins(plugins, check(parse(commitMsg + EOL + EOL)));
118118

119119
t.deepStrictEqual(res1, res2);
120120

121-
t.strictEqual(res2[0].body, null);
122-
t.strictEqual(res2[0].header.type, 'fix');
123-
t.strictEqual(res2[0].header.scope, null);
124-
t.strictEqual(res2[0].header.subject, 'bar qux');
125-
t.strictEqual(res2[0].isBreaking, false);
126-
t.strictEqual(res2[0].increment, 'patch');
127-
128-
const [cmt] = res3;
129-
t.strictEqual(cmt.header.type, 'fix');
130-
t.strictEqual(cmt.header.scope, null);
131-
t.strictEqual(cmt.header.subject, 'bar qux');
132-
t.strictEqual(cmt.body.trim(), '');
133-
t.strictEqual(cmt.isBreaking, false);
134-
t.strictEqual(cmt.increment, 'patch');
121+
t.strictEqual(res2.body, null);
122+
t.strictEqual(res2.header.type, 'fix');
123+
t.strictEqual(res2.header.scope, null);
124+
t.strictEqual(res2.header.subject, 'bar qux');
125+
t.strictEqual(res2.isBreaking, false);
126+
t.strictEqual(res2.increment, 'patch');
127+
128+
t.strictEqual(res3.body.trim(), '');
129+
t.strictEqual(res3.header.type, 'fix');
130+
t.strictEqual(res3.header.scope, null);
131+
t.strictEqual(res3.header.subject, 'bar qux');
132+
t.strictEqual(res3.isBreaking, false);
133+
t.strictEqual(res3.increment, 'patch');
134+
});
135+
136+
test('ensure empty footer is allowed (git commit defaults)', (t) => {
137+
const commitMsg = 'fix: bar qux\n\nBar qux';
138+
const [res1] = applyPlugins(plugins, check(parse(commitMsg)));
139+
const [res2] = applyPlugins(plugins, check(parse(commitMsg + EOL)));
140+
const [res3] = applyPlugins(plugins, check(parse(commitMsg + EOL + EOL)));
141+
142+
t.strictEqual(res1.body, 'Bar qux');
143+
t.strictEqual(res1.footer, null);
144+
145+
t.strictEqual(res2.body, `Bar qux${EOL}`);
146+
t.strictEqual(res2.footer, null);
147+
148+
t.strictEqual(res3.body, 'Bar qux');
149+
t.strictEqual(res3.footer, '');
135150
});

0 commit comments

Comments
 (0)