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: allow a user to provide a custom changelog header #335

Merged
merged 8 commits into from May 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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