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

Add support for .auto-changelog default config file #66

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,19 @@ You can also set any option in `package.json` under the `auto-changelog` key, us
}
```

If you'd like to use a global installation of `auto-changelog` in a non-NodeJS project that wouldn't otherwise have a `package.json` file, you can include a `.auto-changelog` file in your project root with your defaults in order to avoid needing to specify command-line options for every run:

```js
{
"output": "HISTORY.md",
"template": "keepachangelog",
"unreleased": true,
"commitLimit": false
}
```

**Note:** You cannot use the `.auto-changelog` convention if you have already defined defaults in `package.json`.

### Requirements

`auto-changelog` is designed to be as flexible as possible, providing a clear changelog for any project. There are only two absolute requirements:
Expand Down
31 changes: 23 additions & 8 deletions src/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,30 @@ const DEFAULT_OPTIONS = {

const PACKAGE_OPTIONS_KEY = 'auto-changelog'

function getOptions (argv, pkg) {
async function getConfigOptions (pkg) {
if (!await fileExists('.auto-changelog')) {
return {}
}

if (pkg) {
console.warn('Ignoring detected `.auto-changelog` config file due to presence of "auto-changelog" settings in `package.json`')
return {}
}

return await readJson('.auto-changelog') || {}
}

async function getOptions (argv, pkg) {
const configOptions = await getConfigOptions(pkg)
const resolvedOptions = Object.assign(DEFAULT_OPTIONS, configOptions)
const options = new Command()
.option('-o, --output [file]', `output file, default: ${DEFAULT_OPTIONS.output}`)
.option('-t, --template [template]', `specify template to use [compact, keepachangelog, json], default: ${DEFAULT_OPTIONS.template}`)
.option('-r, --remote [remote]', `specify git remote to use for links, default: ${DEFAULT_OPTIONS.remote}`)
.option('-o, --output [file]', `output file, default: ${resolvedOptions.output}`)
.option('-t, --template [template]', `specify template to use [compact, keepachangelog, json], default: ${resolvedOptions.template}`)
.option('-r, --remote [remote]', `specify git remote to use for links, default: ${resolvedOptions.remote}`)
.option('-p, --package', 'use version from package.json as latest release')
.option('-v, --latest-version [version]', 'use specified version as latest release')
.option('-u, --unreleased', 'include section for unreleased changes')
.option('-l, --commit-limit [count]', `number of commits to display per release, default: ${DEFAULT_OPTIONS.commitLimit}`, parseLimit)
.option('-l, --commit-limit [count]', `number of commits to display per release, default: ${resolvedOptions.commitLimit}`, parseLimit)
.option('-i, --issue-url [url]', `override url for issues, use {id} for issue id`)
.option('--issue-pattern [regex]', `override regex pattern for issues in commit messages`)
.option('--breaking-pattern [regex]', `regex pattern for breaking change commits`)
Expand All @@ -42,12 +57,12 @@ function getOptions (argv, pkg) {
throw new Error('package.json could not be found')
}
return {
...DEFAULT_OPTIONS,
...resolvedOptions,
...options
}
}
return {
...DEFAULT_OPTIONS,
...resolvedOptions,
...pkg[PACKAGE_OPTIONS_KEY],
...options
}
Expand Down Expand Up @@ -83,7 +98,7 @@ async function getReleases (commits, remote, latestVersion, options) {

export default async function run (argv) {
const pkg = await fileExists('package.json') && await readJson('package.json')
const options = getOptions(argv, pkg)
const options = await getOptions(argv, pkg)
const remote = await fetchRemote(options.remote)
const commits = await fetchCommits(remote, options)
const latestVersion = getLatestVersion(options, pkg, commits)
Expand Down
52 changes: 48 additions & 4 deletions test/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import run, {
const getOptions = __get__('getOptions')

describe('getOptions', () => {
it('parses commit limit correctly', () => {
const options = getOptions(['', '', '--commit-limit', '10'])
it('parses commit limit correctly', async () => {
const options = await getOptions(['', '', '--commit-limit', '10'])
expect(options.commitLimit).to.equal(10)
})

it('parses false commit limit correctly', () => {
const options = getOptions(['', '', '--commit-limit', 'false'])
it('parses false commit limit correctly', async () => {
const options = await getOptions(['', '', '--commit-limit', 'false'])
expect(options.commitLimit).to.equal(false)
})
})
Expand Down Expand Up @@ -131,6 +131,50 @@ describe('run', () => {
return run(['', '', '--output', 'should-be-this.md'])
})

it('uses options from .auto-changelog', async () => {
const expected = await readFile(join(__dirname, 'data', 'template-keepachangelog.md'))
mock('fileExists', (fileName) => {
return fileName === '.auto-changelog'
})
mock('readJson', (fileName) => {
return fileName === '.auto-changelog' ? {template: 'keepachangelog'} : null
})
mock('writeFile', (output, log) => {
expect(output).to.equal('CHANGELOG.md')
expect(log).to.equal(expected)
})

return run(['', ''])
})

it('command line options override options from .auto-changelog', async () => {
mock('fileExists', (fileName) => {
return fileName === '.auto-changelog'
})
mock('readJson', (fileName) => {
return fileName === '.auto-changelog' ? {output: 'should-not-be-this.md'} : null
})
mock('writeFile', (output, log) => {
expect(output).to.equal('should-be-this.md')
})

return run(['', '', '--output', 'should-be-this.md'])
})

it('.auto-changelog is ignored if package.json options are set', async () => {
mock('fileExists', () => true)
mock('readJson', () => ({
'auto-changelog': {
output: 'should-be-this.md'
}
}))
mock('writeFile', (output, log) => {
expect(output).to.equal('should-be-this.md')
})

return run(['', ''])
})

it('supports unreleased option', () => {
mock('writeFile', (output, log) => {
expect(log).to.include('Unreleased')
Expand Down