Skip to content

Commit

Permalink
feat: allow a user to provide a custom changelog header (#335)
Browse files Browse the repository at this point in the history
  • Loading branch information
bcoe committed May 5, 2019
1 parent bd0fcdf commit 1c51064
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 12 deletions.
12 changes: 12 additions & 0 deletions command.js
Expand Up @@ -5,6 +5,7 @@ const { readFileSync } = require('fs')
const configPath = findUp.sync(['.versionrc', '.version.json'])
const config = configPath ? JSON.parse(readFileSync(configPath)) : {}
const spec = require('conventional-changelog-config-spec')
const { START_OF_LAST_RELEASE_PATTERN } = require('./lib/lifecycles/changelog')

const yargs = require('yargs')
.usage('Usage: $0 [options]')
Expand Down Expand Up @@ -87,6 +88,10 @@ const yargs = require('yargs')
type: 'string',
describe: 'Only populate commits made under this path'
})
.option('changelogHeader', {
type: 'string',
describe: 'Use a custom header when generating and updating changelog.'
})
.option('preset', {
type: 'string',
default: defaults.preset,
Expand All @@ -108,6 +113,13 @@ const yargs = require('yargs')
.pkgConf('standard-version')
.config(config)
.wrap(97)
.check((args) => {
if (args.changelogHeader && args.changelogHeader.search(START_OF_LAST_RELEASE_PATTERN) !== -1) {
throw Error(`custom changelog header must not match ${START_OF_LAST_RELEASE_PATTERN}`)
} else {
return true
}
})

Object.keys(spec.properties).forEach(propertyKey => {
const property = spec.properties[propertyKey]
Expand Down
15 changes: 10 additions & 5 deletions lib/lifecycles/changelog.js
Expand Up @@ -6,9 +6,9 @@ const fs = require('fs')
const presetLoader = require('../preset-loader')
const runLifecycleScript = require('../run-lifecycle-script')
const writeFile = require('../write-file')
const START_OF_LAST_RELEASE_PATTERN = /(^##? (?!Change Log$)|<a name=)/m
const START_OF_LAST_RELEASE_PATTERN = /(^#+ \[?[0-9]+\.[0-9]+\.[0-9]+|<a name=)/m

module.exports = function (args, newVersion) {
function Changelog (args, newVersion) {
if (args.skip.changelog) return Promise.resolve()
return runLifecycleScript(args, 'prechangelog')
.then(() => {
Expand All @@ -19,12 +19,17 @@ module.exports = function (args, newVersion) {
})
}

Changelog.START_OF_LAST_RELEASE_PATTERN = START_OF_LAST_RELEASE_PATTERN

module.exports = Changelog

function outputChangelog (args, newVersion) {
return new Promise((resolve, reject) => {
createIfMissing(args)
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'
var oldContent = args.dryRun ? '' : fs.readFileSync(args.infile, 'utf-8')
var oldContentStart = oldContent.search(START_OF_LAST_RELEASE_PATTERN)
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'

let oldContent = args.dryRun ? '' : fs.readFileSync(args.infile, 'utf-8')
let oldContentStart = oldContent.search(START_OF_LAST_RELEASE_PATTERN)
// find the position of the last release and remove header:
if (oldContentStart !== -1) {
oldContent = oldContent.substring(oldContentStart)
Expand Down
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -39,9 +39,9 @@
"homepage": "https://github.com/conventional-changelog/standard-version#readme",
"dependencies": {
"chalk": "2.4.2",
"conventional-changelog": "3.1.7",
"conventional-changelog": "3.1.8",
"conventional-changelog-config-spec": "1.0.0",
"conventional-recommended-bump": "4.1.1",
"conventional-recommended-bump": "5.0.0",
"detect-indent": "5.0.0",
"detect-newline": "2.1.0",
"dotgitignore": "2.1.0",
Expand Down
32 changes: 27 additions & 5 deletions test.js
Expand Up @@ -165,23 +165,31 @@ describe('cli', function () {
content.should.not.match(/legacy header format/)
})

// TODO: we should use snapshots which are easier to update than large
// string assertions; we should also consider not using the CLI which
// is slower than calling standard-version directly.
it('appends the new release above the last release, removing the old header (new format)', function () {
// we don't create a package.json, so no {{host}} and {{repo}} tag
// will be populated, let's use a compareUrlFormat without these.
const cliArgs = '--compareUrlFormat=/compare/{{previousTag}}...{{currentTag}}'

commit('feat: first commit')
shell.exec('git tag -a v1.0.0 -m "my awesome first release"')
commit('fix: patch release')

execCli().code.should.equal(0)
var content = fs.readFileSync('CHANGELOG.md', 'utf-8')
execCli(cliArgs).code.should.equal(0)
let content = fs.readFileSync('CHANGELOG.md', 'utf-8')

// remove commit hashes and dates to make testing against a static string easier:
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)')
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')
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')

commit('fix: another patch release')
execCli().code.should.equal(0)
// we've populated no package.json, so no {{host}} and
execCli(cliArgs).code.should.equal(0)
content = fs.readFileSync('CHANGELOG.md', 'utf-8')
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)')
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')
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')
})

it('commits all staged files', function () {
Expand All @@ -206,6 +214,20 @@ describe('cli', function () {
content.should.match(/1\.0\.1/)
content.should.not.match(/legacy header format/)
})

it('allows for a custom changelog header', function () {
fs.writeFileSync('CHANGELOG.md', '', 'utf-8')
commit('feat: first commit')
execCli('--changelogHeader="# Pork Chop Log"').code.should.equal(0)
let content = fs.readFileSync('CHANGELOG.md', 'utf-8')
content.should.match(/# Pork Chop Log/)
})

it('exits with error if changelog header matches last version search regex', function () {
fs.writeFileSync('CHANGELOG.md', '', 'utf-8')
commit('feat: first commit')
execCli('--changelogHeader="## 3.0.2"').code.should.equal(1)
})
})

describe('with mocked git', function () {
Expand Down

0 comments on commit 1c51064

Please sign in to comment.