diff --git a/command.js b/command.js index 4ea6c1c3e..25b0a5abd 100755 --- a/command.js +++ b/command.js @@ -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]') @@ -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, @@ -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] diff --git a/lib/lifecycles/changelog.js b/lib/lifecycles/changelog.js index 43733225d..512d63a50 100644 --- a/lib/lifecycles/changelog.js +++ b/lib/lifecycles/changelog.js @@ -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$)| { @@ -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) diff --git a/package.json b/package.json index 7e64173aa..e4f9b2918 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/test.js b/test.js index 6a2dbacff..1ee100e3c 100644 --- a/test.js +++ b/test.js @@ -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 () { @@ -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 () {