Skip to content

Commit 7fd87c1

Browse files
authored
Merge pull request #3 from uglow/fix/base-scopes-optional-if-override-scopes-exist
fix(rules): allow scopes to be empty so long as scope overrides exist feat(rules): add appendBranchNameToCommitMessage support (defaults to true)
2 parents dbac74d + d4e795a commit 7fd87c1

File tree

4 files changed

+144
-22
lines changed

4 files changed

+144
-22
lines changed

config/testUnit/istanbul.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ instrumentation:
22
root: lib/
33
check:
44
global:
5-
statements: 80
6-
functions: 80
5+
statements: 90
76
branches: 80
8-
lines: 80
7+
functions: 80
8+
lines: 90
99
each:
1010
statements: 72
1111
functions: 50

lib/index.js

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const PKG = require(path.join(APP_ROOT, '/package.json')); // Find the root pa
3232
const MAX_LENGTH = 100;
3333
// Make commit scope optional.
3434
const PATTERN = /^(?:fixup!\s*)?(\w*)(\(([\w\$\.\-\*/]+)\))*\: (.*)$/; //type(scope-min-3-chars): min-5-chars-starting-with-lowercase-letter
35-
const ISSUE_PATTERN = /(ibf-.*?)-/i;
35+
const ISSUE_PATTERN = /(ibf-.*?)-/i; // Todo: make this configurable or remove it entirely
3636
const IGNORED = /^Merge branch|WIP\:|Release v/;
3737
const BREAKING_CHANGE_PATTERN = /BREAKING CHANGE:/;
3838
const MIN_SUBJECT_LENGTH = 3;
@@ -44,6 +44,7 @@ let SCOPES;
4444
let SCOPE_OVERRIDES;
4545
let allowCustomScopes;
4646
let allowBreakingChangesForType;
47+
let appendBranchNameToCommitMessage = true; // Boolean
4748

4849
// publish for testing
4950
module.exports = {
@@ -106,13 +107,16 @@ function validateMessage(firstLine, fullMsg) {
106107
let type = match[1];
107108
let scope = match[3];
108109
let subject = match[4];
110+
let allowedScopesForType = SCOPE_OVERRIDES[type] ? SCOPE_OVERRIDES[type] : [];
111+
112+
allowedScopesForType = allowedScopesForType.map(item => item.name).concat(SCOPES);
109113

110114
if (!TYPES.length) {
111115
commitError(`No valid types defined! Check your package.json and cz-customisable rules file and define the "types" there.`);
112116
return false;
113117
}
114118

115-
if (!SCOPES.length && !allowCustomScopes) {
119+
if (!SCOPES.length && !allowCustomScopes && allowedScopesForType.indexOf(scope) === -1) {
116120
commitError(`No valid scopes defined! Check your package.json and cz-customisable rules file and define the "scopes" there (or set allowCustomScopes to true)`);
117121
return false;
118122
}
@@ -122,10 +126,6 @@ function validateMessage(firstLine, fullMsg) {
122126
return false;
123127
}
124128

125-
let allowedScopesForType = SCOPE_OVERRIDES[type] ? SCOPE_OVERRIDES[type] : [];
126-
127-
allowedScopesForType = allowedScopesForType.map(item => item.name).concat(SCOPES);
128-
129129
if (!allowCustomScopes && allowedScopesForType.indexOf(scope) === -1) {
130130
commitError(`"${scope}" is not allowed scope for a "${type}" commit!\nValid "${type}" scopes: ${allowedScopesForType.sort().join(', ')}`);
131131
return false;
@@ -205,6 +205,8 @@ function processCLI(commitMsgFileName, cb) {
205205
let incorrectLogFileName = commitMsgFileName.replace('COMMIT_EDITMSG', 'logs/incorrect-commit-msgs');
206206
let callback = cb || function() {}; // Used for testing
207207

208+
appendBranchNameToCommitMessage = czConfig && czConfig.appendBranchNameToCommitMessage != undefined ? czConfig.appendBranchNameToCommitMessage : appendBranchNameToCommitMessage;
209+
208210
fs.readFile(commitMsgFileName, function(err, buffer) {
209211
let lines = getLinesFromBuffer(buffer);
210212
let msg = lines.join('\n');
@@ -218,15 +220,21 @@ function processCLI(commitMsgFileName, cb) {
218220

219221
console.info(chalk.bold.white.bgGreen('Commit message is valid.'));
220222

221-
// If valid, add the issue/branch name to the last line
222-
exec('git rev-parse --abbrev-ref HEAD', function(err, stdout/*, stderr*/) {
223-
let lastline = appendIssueToCommit(lines, getIssueFromBranch(stdout));
224-
225-
fs.appendFile(commitMsgFileName, lastline, function() {
226-
process.exit(0);
227-
callback();
223+
// Make it optional to append the branch name to the commit message
224+
if (!appendBranchNameToCommitMessage) {
225+
process.exit(0);
226+
callback();
227+
} else {
228+
// If valid, add the issue/branch name to the last line
229+
exec('git rev-parse --abbrev-ref HEAD', function(err, stdout/*, stderr*/) {
230+
let lastline = appendIssueToCommit(lines, getIssueFromBranch(stdout));
231+
232+
fs.appendFile(commitMsgFileName, lastline, function() {
233+
process.exit(0);
234+
callback();
235+
});
228236
});
229-
});
237+
}
230238
}
231239
});
232240
}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"config": "config/release/commitMessageConfig.js"
4545
},
4646
"ghooks": {
47-
"commit-msg": "./node_modules/cz-customizable-ghooks/index.js $2",
47+
"commit-msg": "./node_modules/cz-customizable-ghooks/lib/index.js $2",
4848
"pre-push": "npm-run-all verify test:unit:once --silent"
4949
}
5050
},
@@ -55,7 +55,7 @@
5555
"devDependencies": {
5656
"chokidar-cli": "1.2.0",
5757
"cz-customizable": "4.0.0",
58-
"cz-customizable-ghooks": "1.1.2",
58+
"cz-customizable-ghooks": "1.2.0",
5959
"eslint": "1.10.3",
6060
"eslint-config-defaults": "8.0.2",
6161
"ghooks": "1.2.1",

test/ccg.spec.js

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ describe('cz-customizable-ghooks', () => {
8787
types: [
8888
{value: 'feat', name: 'feat: A new feature'},
8989
{value: 'fix', name: 'fix: A bug fix'},
90-
{value: 'docs', name: 'docs: Documentation only changes'},
90+
{value: 'docs', name: 'docs: Documentation only changes'}
9191
],
9292

9393
scopes: [
@@ -117,7 +117,7 @@ describe('cz-customizable-ghooks', () => {
117117
};
118118

119119
const testData = [
120-
{msg: 'feat(customScope): this ok', expectedResult: false},
120+
{msg: 'feat(customScope): this not ok', expectedResult: false},
121121
{msg: 'docs(custom): docs has an override scope', expectedResult: true},
122122
{msg: 'fix(merge): and so does fix', expectedResult: true},
123123
{msg: 'docs(invalidCustom): not a valid custom scope', expectedResult: false}
@@ -139,6 +139,66 @@ describe('cz-customizable-ghooks', () => {
139139
});
140140
});
141141

142+
143+
describe('with no scopes but with scope overridesForTypes', () => {
144+
let baseScopes = [
145+
{name: 'merge'},
146+
{name: 'style'},
147+
{name: 'e2eTest'},
148+
{name: 'unitTest'}
149+
];
150+
let config = {
151+
types: [
152+
{value: 'feat', name: 'feat: A new feature'},
153+
{value: 'fix', name: 'fix: A bug fix'},
154+
{value: 'docs', name: 'docs: Documentation only changes'}
155+
],
156+
157+
scopeOverrides: {
158+
fix: baseScopes,
159+
docs: baseScopes.concat({name: 'custom'})
160+
},
161+
allowCustomScopes: false,
162+
allowBreakingChanges: ['feat', 'fix'],
163+
process: {
164+
exit: () => {}
165+
}
166+
};
167+
168+
const testData = [
169+
{msg: 'fix(merge): this ok', expectedResult: true},
170+
{msg: 'docs(custom): this has an override scope', expectedResult: true},
171+
{msg: 'feat(merge): no scopes for feature', expectedResult: false},
172+
{msg: 'docs(invalidCustom): not a valid custom scope', expectedResult: false}
173+
];
174+
175+
let consoleData = '';
176+
177+
beforeEach(() => {
178+
module = rewire('../lib/index');
179+
module.__set__({
180+
czConfig: config,
181+
console: {
182+
log: (data) => consoleData += data,
183+
error: (data) => consoleData += data
184+
}
185+
});
186+
});
187+
188+
afterEach(() => {
189+
consoleData = '';
190+
});
191+
192+
it('should accept commit messages which match the rules in the config', () => {
193+
testData.forEach(test => {
194+
let lines = test.msg.split('\n');
195+
196+
assert.equal(module.validateMessage(lines[0], test.msg), test.expectedResult, test.msg);// + '\n' + consoleData);
197+
});
198+
});
199+
});
200+
201+
142202
describe('error conditions', () => {
143203
let consoleData = '';
144204

@@ -213,7 +273,7 @@ describe('cz-customizable-ghooks', () => {
213273
});
214274
});
215275

216-
it('should accept commit messages which match the rules in the config', () => {
276+
it('should reject commit messages which do not match the rules in the config', () => {
217277
testData.forEach(test => {
218278
module.__set__({czConfig: test.config});
219279

@@ -307,6 +367,7 @@ describe('cz-customizable-ghooks', () => {
307367
const commitMsgFileName = __dirname + '/COMMIT_MSG';
308368
let consoleData = '';
309369
let exitCode;
370+
let execCall = '';
310371
let revert1, revert2 = () => {};
311372

312373
beforeEach(() => {
@@ -341,6 +402,7 @@ describe('cz-customizable-ghooks', () => {
341402
revert1();
342403
revert2();
343404
deleteCommitMessageFile();
405+
execCall = '';
344406
});
345407

346408
function createCommitMessageFile(msg) {
@@ -399,5 +461,57 @@ describe('cz-customizable-ghooks', () => {
399461

400462
module.processCLI(commitMsgFileName, cb);
401463
});
464+
465+
466+
it('should try to execute a git command to append the branch name to the message by default', (done) => {
467+
createCommitMessageFile('feat(a): something');
468+
469+
revert2 = module.__set__({
470+
exec: (cliArg, cb) => {
471+
execCall = cliArg;
472+
cb(null, ''); //err, stdOut
473+
}
474+
});
475+
476+
function cb() {
477+
assert(execCall === 'git rev-parse --abbrev-ref HEAD', execCall + ' should be passed to exec()');
478+
assert.equal(exitCode, 0);
479+
done();
480+
}
481+
482+
module.processCLI(commitMsgFileName, cb);
483+
});
484+
485+
486+
it('should not try to execute a git command to append the branch name if the config file indicates not to', (done) => {
487+
createCommitMessageFile('feat(a): something');
488+
489+
revert2 = module.__set__({
490+
exec: (cliArg, cb) => {
491+
execCall = cliArg;
492+
cb(null, ''); //err, stdOut
493+
},
494+
czConfig: {
495+
types: [
496+
{value: 'feat', name: 'feat: A new feature'}
497+
],
498+
scopes: [
499+
{name: 'a'}
500+
],
501+
scopeOverrides: {},
502+
allowCustomScopes: true,
503+
allowBreakingChanges: ['feat', 'fix'],
504+
appendBranchNameToCommitMessage: false //<--- This has changed from true (default) to false
505+
}
506+
});
507+
508+
function cb() {
509+
assert(execCall === '', 'exec() should not be called with ' + execCall);
510+
assert.equal(exitCode, 0);
511+
done();
512+
}
513+
514+
module.processCLI(commitMsgFileName, cb);
515+
});
402516
});
403517
});

0 commit comments

Comments
 (0)