Skip to content

Commit 3398c02

Browse files
yinzarajimthedev
authored andcommitted
feat: implement configuration through package.json (#75)
cz-conventional-changelog can now have its values (specifically all the defaults and maxLineWidth) through the config.commitizen key in the package.json file. The scope now automatically becomes lowercase (as is required for conventional changelogs) and is prompted on the same line (as it is always short and doesn't need an additional line). The subject question now indicates the total number of characters that are allowed based upon the maxLineWidth configuration (or 100 as it is now by default), the length of the type, and scope. Validation prevents entering more than the allowed number of characters with feedback of the number of characters entered. Subject will always have a lowercase first letter and strip any trailing dots (as is required by the conventional changelog standard). 'commitizen' and 'semantic-release' have been updated to the most recent versions (because of current vunderabilites) and the .travisci file has been updated to reflect newer node versions.
1 parent 65d6a9f commit 3398c02

9 files changed

+12806
-62
lines changed

.editorconfig

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[*]
2+
end_of_line = lf
3+
charset = utf-8
4+
indent_size = 2
5+
indent_style = space
6+
insert_final_newline = true
7+
max_line_length = 80
8+
trim_trailing_whitespace = true

.prettierrc

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"printWidth": 80,
3+
"endOfLine": "lf",
4+
"singleQuote": true
5+
}

.travis.yml

+16-13
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1-
sudo: false
21
language: node_js
3-
cache:
4-
directories:
5-
- node_modules
6-
notifications:
7-
email: false
2+
83
node_js:
9-
- '4'
10-
before_install:
11-
- npm i -g npm@^2.0.0
12-
before_script:
13-
- npm prune
14-
after_success:
15-
- npm run semantic-release
4+
- 10
5+
- 8
6+
- 6
7+
- 4
8+
9+
jobs:
10+
include:
11+
- stage: release
12+
node_js: lts/*
13+
deploy:
14+
provider: script
15+
skip_cleanup: true
16+
script:
17+
- npm semantic-release
18+
1619
branches:
1720
only:
1821
- master

README.md

+40
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,43 @@ Status:
66
[![Build Status](https://img.shields.io/travis/commitizen/cz-conventional-changelog.svg?style=flat-square)](https://travis-ci.org/commitizen/cz-conventional-changelog)
77

88
Part of the [commitizen](https://github.com/commitizen/cz-cli) family. Prompts for [conventional changelog](https://github.com/conventional-changelog/conventional-changelog) standard.
9+
10+
## Configuration
11+
12+
### package.json
13+
14+
Like commitizen, you specify the configuration of cz-conventional-changelog through the package.json's `config.commitizen` key.
15+
16+
```json5
17+
{
18+
// ... default values
19+
"config": {
20+
"commitizen": {
21+
"path": "./node_modules/cz-conventional-changelog",
22+
"maxHeaderWidth": 100,
23+
"maxLineWidth": 100,
24+
"defaultType": "",
25+
"defaultScope": "",
26+
"defaultSubject": "",
27+
"defaultBody": "",
28+
"defaultIssues": ""
29+
}
30+
}
31+
// ...
32+
}
33+
```
34+
### Environment variables
35+
36+
The following environment varibles can be used to override any default configuration or package.json based configuration.
37+
38+
* CZ_TYPE = defaultType
39+
* CZ_SCOPE = defaultScope
40+
* CZ_SUBJECT = defaultSubject
41+
* CZ_BODY = defaultBody
42+
* CZ_MAX_HEADER_WIDTH = maxHeaderWidth
43+
* CZ_MAX_LINE_WIDTH = maxLineWidth
44+
45+
### Commitlint
46+
47+
If using the [commitlint](https://github.com/conventional-changelog/commitlint) js library, the "maxHeaderWidth" configuration property will default to the configuration of the "header-max-length" rule instead of the hard coded value of 100. This can be ovewritten by setting the 'maxHeaderWidth' configuration in package.json or the CZ_MAX_HEADER_WIDTH environment variable.
48+

engine.js

+123-36
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,47 @@
1-
"format cjs";
1+
'format cjs';
22

33
var wrap = require('word-wrap');
44
var map = require('lodash.map');
55
var longest = require('longest');
66
var rightPad = require('right-pad');
7+
var chalk = require('chalk');
78

89
var filter = function(array) {
910
return array.filter(function(x) {
1011
return x;
1112
});
1213
};
1314

15+
var headerLength = function(answers) {
16+
return (
17+
answers.type.length + 2 + (answers.scope ? answers.scope.length + 2 : 0)
18+
);
19+
};
20+
21+
var maxSummaryLength = function(options, answers) {
22+
return options.maxHeaderWidth - headerLength(answers);
23+
};
24+
25+
var filterSubject = function(subject) {
26+
subject = subject.trim();
27+
if (subject.charAt(0).toLowerCase() !== subject.charAt(0)) {
28+
subject =
29+
subject.charAt(0).toLowerCase() + subject.slice(1, subject.length);
30+
}
31+
while (subject.endsWith('.')) {
32+
subject = subject.slice(0, subject.length - 1);
33+
}
34+
return subject;
35+
};
36+
1437
// This can be any kind of SystemJS compatible module.
1538
// We use Commonjs here, but ES6 or AMD would do just
1639
// fine.
17-
module.exports = function (options) {
18-
40+
module.exports = function(options) {
1941
var types = options.types;
2042

2143
var length = longest(Object.keys(types)).length + 1;
22-
var choices = map(types, function (type, key) {
44+
var choices = map(types, function(type, key) {
2345
return {
2446
name: rightPad(key + ':', length) + ' ' + type.description,
2547
value: key
@@ -39,8 +61,6 @@ module.exports = function (options) {
3961
// By default, we'll de-indent your commit
4062
// template and will keep empty lines.
4163
prompter: function(cz, commit) {
42-
console.log('\nLine 1 will be cropped at 100 characters. All other lines will be wrapped after 100 characters.\n');
43-
4464
// Let's ask some questions of the user
4565
// so that we can populate our commit
4666
// template.
@@ -52,42 +72,112 @@ module.exports = function (options) {
5272
{
5373
type: 'list',
5474
name: 'type',
55-
message: 'Select the type of change that you\'re committing:',
75+
message: "Select the type of change that you're committing:",
5676
choices: choices,
5777
default: options.defaultType
58-
}, {
78+
},
79+
{
5980
type: 'input',
6081
name: 'scope',
61-
message: 'What is the scope of this change (e.g. component or file name)? (press enter to skip)\n',
62-
default: options.defaultScope
63-
}, {
82+
message:
83+
'What is the scope of this change (e.g. component or file name): (press enter to skip)',
84+
default: options.defaultScope,
85+
filter: function(value) {
86+
return value.trim().toLowerCase();
87+
}
88+
},
89+
{
6490
type: 'input',
6591
name: 'subject',
66-
message: 'Write a short, imperative tense description of the change:\n',
67-
default: options.defaultSubject
68-
}, {
92+
message: function(answers) {
93+
return (
94+
'Write a short, imperative tense description of the change (max ' +
95+
maxSummaryLength(options, answers) +
96+
' chars):\n'
97+
);
98+
},
99+
default: options.defaultSubject,
100+
validate: function(subject, answers) {
101+
var filteredSubject = filterSubject(subject);
102+
return filteredSubject.length == 0
103+
? 'subject is required'
104+
: filteredSubject.length <= maxSummaryLength(options, answers)
105+
? true
106+
: 'Subject length must be less than or equal to ' +
107+
maxSummaryLength(options, answers) +
108+
' characters. Current length is ' +
109+
filteredSubject.length +
110+
' characters.';
111+
},
112+
transformer: function(subject, answers) {
113+
var filteredSubject = filterSubject(subject);
114+
var color =
115+
filteredSubject.length <= maxSummaryLength(options, answers)
116+
? chalk.green
117+
: chalk.red;
118+
return color('(' + filteredSubject.length + ') ' + subject);
119+
},
120+
filter: function(subject) {
121+
return filterSubject(subject);
122+
}
123+
},
124+
{
69125
type: 'input',
70126
name: 'body',
71-
message: 'Provide a longer description of the change: (press enter to skip)\n',
127+
message:
128+
'Provide a longer description of the change: (press enter to skip)\n',
72129
default: options.defaultBody
73-
}, {
130+
},
131+
{
74132
type: 'confirm',
75133
name: 'isBreaking',
76134
message: 'Are there any breaking changes?',
77135
default: false
78-
}, {
136+
},
137+
{
138+
type: 'input',
139+
name: 'breakingBody',
140+
default: '-',
141+
message:
142+
'A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself:\n',
143+
when: function(answers) {
144+
return answers.isBreaking && !answers.body;
145+
},
146+
validate: function(breakingBody, answers) {
147+
return (
148+
breakingBody.trim().length > 0 ||
149+
'Body is required for BREAKING CHANGE'
150+
);
151+
}
152+
},
153+
{
79154
type: 'input',
80155
name: 'breaking',
81156
message: 'Describe the breaking changes:\n',
82157
when: function(answers) {
83158
return answers.isBreaking;
84159
}
85-
}, {
160+
},
161+
162+
{
86163
type: 'confirm',
87164
name: 'isIssueAffected',
88165
message: 'Does this change affect any open issues?',
89166
default: options.defaultIssues ? true : false
90-
}, {
167+
},
168+
{
169+
type: 'input',
170+
name: 'issuesBody',
171+
default: '-',
172+
message:
173+
'If issues are closed, the commit requires a body. Please enter a longer description of the commit itself:\n',
174+
when: function(answers) {
175+
return (
176+
answers.isIssueAffected && !answers.body && !answers.breakingBody
177+
);
178+
}
179+
},
180+
{
91181
type: 'input',
92182
name: 'issues',
93183
message: 'Add issue references (e.g. "fix #123", "re #123".):\n',
@@ -97,36 +187,33 @@ module.exports = function (options) {
97187
default: options.defaultIssues ? options.defaultIssues : undefined
98188
}
99189
]).then(function(answers) {
100-
101-
var maxLineWidth = 100;
102-
103190
var wrapOptions = {
104191
trim: true,
192+
cut: false,
105193
newline: '\n',
106-
indent:'',
107-
width: maxLineWidth
194+
indent: '',
195+
width: options.maxLineWidth
108196
};
109197

110198
// parentheses are only needed when a scope is present
111-
var scope = answers.scope.trim();
112-
scope = scope ? '(' + answers.scope.trim() + ')' : '';
199+
var scope = answers.scope ? '(' + answers.scope + ')' : '';
113200

114-
// Hard limit this line
115-
var head = (answers.type + scope + ': ' + answers.subject.trim()).slice(0, maxLineWidth);
201+
// Hard limit this line in the validate
202+
var head = answers.type + scope + ': ' + answers.subject;
116203

117-
// Wrap these lines at 100 characters
118-
var body = wrap(answers.body, wrapOptions);
204+
// Wrap these lines at options.maxLineWidth characters
205+
var body = answers.body ? wrap(answers.body, wrapOptions) : false;
119206

120207
// Apply breaking change prefix, removing it if already present
121208
var breaking = answers.breaking ? answers.breaking.trim() : '';
122-
breaking = breaking ? 'BREAKING CHANGE: ' + breaking.replace(/^BREAKING CHANGE: /, '') : '';
123-
breaking = wrap(breaking, wrapOptions);
124-
125-
var issues = answers.issues ? wrap(answers.issues, wrapOptions) : '';
209+
breaking = breaking
210+
? 'BREAKING CHANGE: ' + breaking.replace(/^BREAKING CHANGE: /, '')
211+
: '';
212+
breaking = breaking ? wrap(breaking, wrapOptions) : false;
126213

127-
var footer = filter([ breaking, issues ]).join('\n\n');
214+
var issues = answers.issues ? wrap(answers.issues, wrapOptions) : false;
128215

129-
commit(head + '\n\n' + body + '\n\n' + footer);
216+
commit(filter([head, body, breaking, issues]).join('\n\n'));
130217
});
131218
}
132219
};

0 commit comments

Comments
 (0)