Skip to content

Commit 1c51064

Browse files
authored
feat: allow a user to provide a custom changelog header (#335)
1 parent bd0fcdf commit 1c51064

File tree

4 files changed

+51
-12
lines changed

4 files changed

+51
-12
lines changed

command.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const { readFileSync } = require('fs')
55
const configPath = findUp.sync(['.versionrc', '.version.json'])
66
const config = configPath ? JSON.parse(readFileSync(configPath)) : {}
77
const spec = require('conventional-changelog-config-spec')
8+
const { START_OF_LAST_RELEASE_PATTERN } = require('./lib/lifecycles/changelog')
89

910
const yargs = require('yargs')
1011
.usage('Usage: $0 [options]')
@@ -87,6 +88,10 @@ const yargs = require('yargs')
8788
type: 'string',
8889
describe: 'Only populate commits made under this path'
8990
})
91+
.option('changelogHeader', {
92+
type: 'string',
93+
describe: 'Use a custom header when generating and updating changelog.'
94+
})
9095
.option('preset', {
9196
type: 'string',
9297
default: defaults.preset,
@@ -108,6 +113,13 @@ const yargs = require('yargs')
108113
.pkgConf('standard-version')
109114
.config(config)
110115
.wrap(97)
116+
.check((args) => {
117+
if (args.changelogHeader && args.changelogHeader.search(START_OF_LAST_RELEASE_PATTERN) !== -1) {
118+
throw Error(`custom changelog header must not match ${START_OF_LAST_RELEASE_PATTERN}`)
119+
} else {
120+
return true
121+
}
122+
})
111123

112124
Object.keys(spec.properties).forEach(propertyKey => {
113125
const property = spec.properties[propertyKey]

lib/lifecycles/changelog.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ const fs = require('fs')
66
const presetLoader = require('../preset-loader')
77
const runLifecycleScript = require('../run-lifecycle-script')
88
const writeFile = require('../write-file')
9-
const START_OF_LAST_RELEASE_PATTERN = /(^##? (?!Change Log$)|<a name=)/m
9+
const START_OF_LAST_RELEASE_PATTERN = /(^#+ \[?[0-9]+\.[0-9]+\.[0-9]+|<a name=)/m
1010

11-
module.exports = function (args, newVersion) {
11+
function Changelog (args, newVersion) {
1212
if (args.skip.changelog) return Promise.resolve()
1313
return runLifecycleScript(args, 'prechangelog')
1414
.then(() => {
@@ -19,12 +19,17 @@ module.exports = function (args, newVersion) {
1919
})
2020
}
2121

22+
Changelog.START_OF_LAST_RELEASE_PATTERN = START_OF_LAST_RELEASE_PATTERN
23+
24+
module.exports = Changelog
25+
2226
function outputChangelog (args, newVersion) {
2327
return new Promise((resolve, reject) => {
2428
createIfMissing(args)
25-
var header = '# Change Log\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n'
26-
var oldContent = args.dryRun ? '' : fs.readFileSync(args.infile, 'utf-8')
27-
var oldContentStart = oldContent.search(START_OF_LAST_RELEASE_PATTERN)
29+
const header = args.changelogHeader || '# Changelog\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n'
30+
31+
let oldContent = args.dryRun ? '' : fs.readFileSync(args.infile, 'utf-8')
32+
let oldContentStart = oldContent.search(START_OF_LAST_RELEASE_PATTERN)
2833
// find the position of the last release and remove header:
2934
if (oldContentStart !== -1) {
3035
oldContent = oldContent.substring(oldContentStart)

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@
3939
"homepage": "https://github.com/conventional-changelog/standard-version#readme",
4040
"dependencies": {
4141
"chalk": "2.4.2",
42-
"conventional-changelog": "3.1.7",
42+
"conventional-changelog": "3.1.8",
4343
"conventional-changelog-config-spec": "1.0.0",
44-
"conventional-recommended-bump": "4.1.1",
44+
"conventional-recommended-bump": "5.0.0",
4545
"detect-indent": "5.0.0",
4646
"detect-newline": "2.1.0",
4747
"dotgitignore": "2.1.0",

test.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,23 +165,31 @@ describe('cli', function () {
165165
content.should.not.match(/legacy header format/)
166166
})
167167

168+
// TODO: we should use snapshots which are easier to update than large
169+
// string assertions; we should also consider not using the CLI which
170+
// is slower than calling standard-version directly.
168171
it('appends the new release above the last release, removing the old header (new format)', function () {
172+
// we don't create a package.json, so no {{host}} and {{repo}} tag
173+
// will be populated, let's use a compareUrlFormat without these.
174+
const cliArgs = '--compareUrlFormat=/compare/{{previousTag}}...{{currentTag}}'
175+
169176
commit('feat: first commit')
170177
shell.exec('git tag -a v1.0.0 -m "my awesome first release"')
171178
commit('fix: patch release')
172179

173-
execCli().code.should.equal(0)
174-
var content = fs.readFileSync('CHANGELOG.md', 'utf-8')
180+
execCli(cliArgs).code.should.equal(0)
181+
let content = fs.readFileSync('CHANGELOG.md', 'utf-8')
175182

176183
// remove commit hashes and dates to make testing against a static string easier:
177184
content = content.replace(/patch release [0-9a-f]{6,8}/g, 'patch release ABCDEFXY').replace(/\([0-9]{4}-[0-9]{2}-[0-9]{2}\)/g, '(YYYY-MM-DD)')
178-
content.should.equal('# Change Log\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n\n## [1.0.1](/compare/v1.0.0...v1.0.1) (YYYY-MM-DD)\n\n\n### Bug Fixes\n\n* patch release ABCDEFXY\n')
185+
content.should.equal('# Changelog\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n\n### [1.0.1](/compare/v1.0.0...v1.0.1) (YYYY-MM-DD)\n\n\n### Bug Fixes\n\n* patch release ABCDEFXY\n')
179186

180187
commit('fix: another patch release')
181-
execCli().code.should.equal(0)
188+
// we've populated no package.json, so no {{host}} and
189+
execCli(cliArgs).code.should.equal(0)
182190
content = fs.readFileSync('CHANGELOG.md', 'utf-8')
183191
content = content.replace(/patch release [0-9a-f]{6,8}/g, 'patch release ABCDEFXY').replace(/\([0-9]{4}-[0-9]{2}-[0-9]{2}\)/g, '(YYYY-MM-DD)')
184-
content.should.equal('# Change Log\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n\n## [1.0.2](/compare/v1.0.1...v1.0.2) (YYYY-MM-DD)\n\n\n### Bug Fixes\n\n* another patch release ABCDEFXY\n\n\n\n## [1.0.1](/compare/v1.0.0...v1.0.1) (YYYY-MM-DD)\n\n\n### Bug Fixes\n\n* patch release ABCDEFXY\n')
192+
content.should.equal('# Changelog\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n\n### [1.0.2](/compare/v1.0.1...v1.0.2) (YYYY-MM-DD)\n\n\n### Bug Fixes\n\n* another patch release ABCDEFXY\n\n\n\n### [1.0.1](/compare/v1.0.0...v1.0.1) (YYYY-MM-DD)\n\n\n### Bug Fixes\n\n* patch release ABCDEFXY\n')
185193
})
186194

187195
it('commits all staged files', function () {
@@ -206,6 +214,20 @@ describe('cli', function () {
206214
content.should.match(/1\.0\.1/)
207215
content.should.not.match(/legacy header format/)
208216
})
217+
218+
it('allows for a custom changelog header', function () {
219+
fs.writeFileSync('CHANGELOG.md', '', 'utf-8')
220+
commit('feat: first commit')
221+
execCli('--changelogHeader="# Pork Chop Log"').code.should.equal(0)
222+
let content = fs.readFileSync('CHANGELOG.md', 'utf-8')
223+
content.should.match(/# Pork Chop Log/)
224+
})
225+
226+
it('exits with error if changelog header matches last version search regex', function () {
227+
fs.writeFileSync('CHANGELOG.md', '', 'utf-8')
228+
commit('feat: first commit')
229+
execCli('--changelogHeader="## 3.0.2"').code.should.equal(1)
230+
})
209231
})
210232

211233
describe('with mocked git', function () {

0 commit comments

Comments
 (0)