Skip to content
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

feat: add support for co-author commit messages #55

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Editor configuration, see http://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
14 changes: 13 additions & 1 deletion buildCommit.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = function buildCommit(answers, config) {
var wrapOptions = {
trim: true,
newline: '\n',
indent:'',
indent: '',
width: maxLineWidth
};

Expand Down Expand Up @@ -47,6 +47,14 @@ module.exports = function buildCommit(answers, config) {
var breaking = wrap(answers.breaking, wrapOptions);
var footer = wrap(answers.footer, wrapOptions);

var coAuthor = undefined;
if (config.hasOwnProperty('developers') && config.developers.length > 0 && answers.coAuthor.length > 0) {
coAuthor = wrap(answers.coAuthor.join('|'), wrapOptions);
coAuthor = coAuthor.split('|').map(function (e) {
return 'Co-authored-by: ' + e;
}).join('\n');
}

var result = head;
if (body) {
result += '\n\n' + body;
Expand All @@ -60,5 +68,9 @@ module.exports = function buildCommit(answers, config) {
result += '\n\n' + footerPrefix + ' ' + footer;
}

if (coAuthor) {
result += '\n\n' + coAuthor;
}

return escapeSpecialChars(result);
};
44 changes: 26 additions & 18 deletions questions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ var buildCommit = require('./buildCommit');
var log = require('winston');


var isNotWip = function(answers) {
var isNotWip = function (answers) {
return answers.type.toLowerCase() !== 'wip';
};

module.exports = {

getQuestions: function(config, cz) {
getQuestions: function (config, cz) {

// normalize config optional options
var scopeOverrides = config.scopeOverrides || {};
Expand All @@ -24,6 +24,7 @@ module.exports = {
messages.body = messages.body || 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n';
messages.breaking = messages.breaking || 'List any BREAKING CHANGES (optional):\n';
messages.footer = messages.footer || 'List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n';
messages.coAuthor = messages.coAuthor || 'List any pair programmers (optional):\n';
messages.confirmCommit = messages.confirmCommit || 'Are you sure you want to proceed with the commit above?';

var questions = [
Expand All @@ -37,7 +38,7 @@ module.exports = {
type: 'list',
name: 'scope',
message: messages.scope,
choices: function(answers) {
choices: function (answers) {
var scopes = [];
if (scopeOverrides[answers.type]) {
scopes = scopes.concat(scopeOverrides[answers.type]);
Expand All @@ -47,13 +48,13 @@ module.exports = {
if (config.allowCustomScopes || scopes.length === 0) {
scopes = scopes.concat([
new cz.Separator(),
{ name: 'empty', value: false },
{ name: 'custom', value: 'custom' }
{name: 'empty', value: false},
{name: 'custom', value: 'custom'}
]);
}
return scopes;
},
when: function(answers) {
when: function (answers) {
var hasScope = false;
if (scopeOverrides[answers.type]) {
hasScope = !!(scopeOverrides[answers.type].length > 0);
Expand All @@ -72,22 +73,22 @@ module.exports = {
type: 'input',
name: 'scope',
message: messages.customScope,
when: function(answers) {
when: function (answers) {
return answers.scope === 'custom';
}
},
{
type: 'input',
name: 'subject',
message: messages.subject,
validate: function(value) {
validate: function (value) {
var limit = config.subjectLimit || 100;
if (value.length > limit) {
return 'Exceed limit: ' + limit;
}
return true;
},
filter: function(value) {
filter: function (value) {
return value.charAt(0).toLowerCase() + value.slice(1);
}
},
Expand All @@ -100,11 +101,9 @@ module.exports = {
type: 'input',
name: 'breaking',
message: messages.breaking,
when: function(answers) {
if (config.allowBreakingChanges && config.allowBreakingChanges.indexOf(answers.type.toLowerCase()) >= 0) {
return true;
}
return false; // no breaking changes allowed unless specifed
when: function (answers) {
return !!(config.allowBreakingChanges && config.allowBreakingChanges.indexOf(answers.type.toLowerCase()) >= 0);
// no breaking changes allowed unless specifed
}
},
{
Expand All @@ -113,15 +112,24 @@ module.exports = {
message: messages.footer,
when: isNotWip
},
{
type: 'checkbox',
name: 'coAuthor',
message: messages.coAuthor,
choices: config.developers,
when: function () {
return config.hasOwnProperty('developers') && config.developers.length > 0;
}
},
{
type: 'expand',
name: 'confirmCommit',
choices: [
{ key: 'y', name: 'Yes', value: 'yes' },
{ key: 'n', name: 'Abort commit', value: 'no' },
{ key: 'e', name: 'Edit message', value: 'edit' }
{key: 'y', name: 'Yes', value: 'yes'},
{key: 'n', name: 'Abort commit', value: 'no'},
{key: 'e', name: 'Edit message', value: 'edit'}
],
message: function(answers) {
message: function (answers) {
var SEP = '###--------------------------------------------------------###';
log.info('\n' + SEP + '\n' + buildCommit(answers, config) + '\n' + SEP + '\n');
return messages.confirmCommit;
Expand Down
88 changes: 47 additions & 41 deletions spec/questionsSpec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

describe('cz-customizable', function() {

var questions, config;

beforeEach(function() {
Expand All @@ -19,10 +18,10 @@ describe('cz-customizable', function() {

it('should array of questions be returned', function() {
config = {
types: [{value: 'feat', name: 'feat: my feat'}],
scopes: [{name: 'myScope'}],
types: [{ value: 'feat', name: 'feat: my feat' }],
scopes: [{ name: 'myScope' }],
scopeOverrides: {
fix: [{name: 'fixOverride'}]
fix: [{ name: 'fixOverride' }]
},
allowCustomScopes: true,
allowBreakingChanges: ['feat'],
Expand All @@ -32,28 +31,35 @@ describe('cz-customizable', function() {
// question 1 - TYPE
expect(getQuestion(1).name).toEqual('type');
expect(getQuestion(1).type).toEqual('list');
expect(getQuestion(1).choices[0]).toEqual({value: 'feat', name: 'feat: my feat'});
expect(getQuestion(1).choices[0]).toEqual({
value: 'feat',
name: 'feat: my feat'
});

// question 2 - SCOPE
expect(getQuestion(2).name).toEqual('scope');
expect(getQuestion(2).choices({})[0]).toEqual({name: 'myScope'});
expect(getQuestion(2).choices({type: 'fix'})[0]).toEqual({name: 'fixOverride'}); //should override scope
expect(getQuestion(2).when({type: 'fix'})).toEqual(true);
expect(getQuestion(2).when({type: 'WIP'})).toEqual(false);
expect(getQuestion(2).when({type: 'wip'})).toEqual(false);
expect(getQuestion(2).choices({})[0]).toEqual({ name: 'myScope' });
expect(getQuestion(2).choices({ type: 'fix' })[0]).toEqual({
name: 'fixOverride'
}); //should override scope
expect(getQuestion(2).when({ type: 'fix' })).toEqual(true);
expect(getQuestion(2).when({ type: 'WIP' })).toEqual(false);
expect(getQuestion(2).when({ type: 'wip' })).toEqual(false);

// question 3 - SCOPE CUSTOM
expect(getQuestion(3).name).toEqual('scope');
expect(getQuestion(3).when({scope: 'custom'})).toEqual(true);
expect(getQuestion(3).when({scope: false})).toEqual(false);
expect(getQuestion(3).when({scope: 'scope'})).toEqual(false);
expect(getQuestion(3).when({ scope: 'custom' })).toEqual(true);
expect(getQuestion(3).when({ scope: false })).toEqual(false);
expect(getQuestion(3).when({ scope: 'scope' })).toEqual(false);

// question 4 - SUBJECT
expect(getQuestion(4).name).toEqual('subject');
expect(getQuestion(4).type).toEqual('input');
expect(getQuestion(4).message).toMatch(/IMPERATIVE tense description/);
expect(getQuestion(4).validate('good subject')).toEqual(true);
expect(getQuestion(4).validate('bad subject that exceed limit')).toEqual('Exceed limit: 20');
expect(getQuestion(4).validate('bad subject that exceed limit')).toEqual(
'Exceed limit: 20'
);
expect(getQuestion(4).filter('Subject')).toEqual('subject');

// question 5 - BODY
Expand All @@ -63,44 +69,47 @@ describe('cz-customizable', function() {
// question 6 - BREAKING CHANGE
expect(getQuestion(6).name).toEqual('breaking');
expect(getQuestion(6).type).toEqual('input');
expect(getQuestion(6).when({type: 'feat'})).toEqual(true);
expect(getQuestion(6).when({type: 'fix'})).toEqual(false);
expect(getQuestion(6).when({ type: 'feat' })).toEqual(true);
expect(getQuestion(6).when({ type: 'fix' })).toEqual(false);

// question 7 - FOOTER
expect(getQuestion(7).name).toEqual('footer');
expect(getQuestion(7).type).toEqual('input');
expect(getQuestion(7).when({type: 'fix'})).toEqual(true);
expect(getQuestion(7).when({type: 'WIP'})).toEqual(false);
expect(getQuestion(7).when({ type: 'fix' })).toEqual(true);
expect(getQuestion(7).when({ type: 'WIP' })).toEqual(false);

//question 8, last one, CONFIRM COMMIT OR NOT
expect(getQuestion(8).name).toEqual('confirmCommit');
expect(getQuestion(8).type).toEqual('expand');

expect(getQuestion(9).name).toEqual('confirmCommit');
expect(getQuestion(9).type).toEqual('expand');

var answers = {
confirmCommit: 'yes',
type: 'feat',
scope: 'myScope',
subject: 'create a new cool feature'
};
expect(getQuestion(8).message(answers)).toMatch('Are you sure you want to proceed with the commit above?');
expect(getQuestion(9).message(answers)).toMatch(
'Are you sure you want to proceed with the commit above?'
);
});

it('default length limit of subject should be 100', function() {
config = {
types: [{value: 'feat', name: 'feat: my feat'}]
types: [{ value: 'feat', name: 'feat: my feat' }]
};
expect(getQuestion(4).validate('good subject')).toEqual(true);
expect(getQuestion(4).validate('bad subject that exceed limit bad subject that exceed limitbad subject that exceed limit test test test')).toEqual('Exceed limit: 100');
expect(
getQuestion(4).validate(
'bad subject that exceed limit bad subject that exceed limitbad subject that exceed limit test test test'
)
).toEqual('Exceed limit: 100');
});


describe('optional fixOverride and allowBreakingChanges', function() {

it('should restrict BREAKING CHANGE question when config property "allowBreakingChanges" specifies array of types', function() {
config = {
types: [{value: 'feat', name: 'feat: my feat'}],
scopes: [{name: 'myScope'}],
types: [{ value: 'feat', name: 'feat: my feat' }],
scopes: [{ name: 'myScope' }],
allowBreakingChanges: ['fix']
};
expect(getQuestion(6).name).toEqual('breaking');
Expand All @@ -114,8 +123,8 @@ describe('cz-customizable', function() {

it('should allow BREAKING CHANGE question when config property "allowBreakingChanges" specifies array of types and answer is one of those', function() {
config = {
types: [{value: 'feat', name: 'feat: my feat'}],
scopes: [{name: 'myScope'}],
types: [{ value: 'feat', name: 'feat: my feat' }],
scopes: [{ name: 'myScope' }],
allowBreakingChanges: ['fix', 'feat']
};
expect(getQuestion(6).name).toEqual('breaking');
Expand All @@ -126,32 +135,29 @@ describe('cz-customizable', function() {

expect(getQuestion(6).when(answers)).toEqual(true); // allowed
});

});

describe('Optional scopes', function() {

it('should use scope override', function() {
config = {
types: [{value: 'feat', name: 'feat: my feat'}],
types: [{ value: 'feat', name: 'feat: my feat' }],
scopeOverrides: {
feat: [{name: 'myScope'}]
feat: [{ name: 'myScope' }]
}
};

// question 2 with
expect(getQuestion(2).name).toEqual('scope');
expect(getQuestion(2).choices({})[0]).toBeUndefined();
expect(getQuestion(2).choices({type: 'feat'})[0]).toEqual({name: 'myScope'}); //should override scope
expect(getQuestion(2).when({type: 'feat'})).toEqual(true);
(function () {
var answers = {type: 'fix'};
expect(getQuestion(2).choices({ type: 'feat' })[0]).toEqual({
name: 'myScope'
}); //should override scope
expect(getQuestion(2).when({ type: 'feat' })).toEqual(true);
(function() {
var answers = { type: 'fix' };
expect(getQuestion(2).when(answers)).toEqual(false);
expect(answers.scope).toEqual('custom');
})();

});
});


});
Loading