forked from cookpete/auto-changelog
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.js
132 lines (124 loc) · 5.78 KB
/
run.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
const { Command } = require('commander')
const { version } = require('../package.json')
const { fetchRemote } = require('./remote')
const { fetchTags } = require('./tags')
const { parseReleases } = require('./releases')
const { compileTemplate } = require('./template')
const { parseLimit, readFile, readJson, writeFile, fileExists, updateLog, formatBytes } = require('./utils')
const DEFAULT_OPTIONS = {
output: 'CHANGELOG.md',
template: 'compact',
remote: 'origin',
commitLimit: 3,
backfillLimit: 3,
tagPrefix: '',
sortTags: 'semver',
sortCommits: 'relevance',
appendGitLog: '',
appendGitTag: '',
config: '.auto-changelog'
}
const PACKAGE_FILE = 'package.json'
const PACKAGE_OPTIONS_KEY = 'auto-changelog'
const PREPEND_TOKEN = '<!-- auto-changelog-above -->'
const getOptions = async argv => {
const commandOptions = new Command()
.option('-o, --output <file>', `output file, default: ${DEFAULT_OPTIONS.output}`)
.option('-c, --config <file>', `config file location, default: ${DEFAULT_OPTIONS.config}`)
.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('-p, --package [file]', 'use version from file as latest release, default: package.json')
.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('-b, --backfill-limit <count>', `number of commits to backfill empty releases with, default: ${DEFAULT_OPTIONS.backfillLimit}`, parseLimit)
.option('--commit-url <url>', 'override url for commits, use {id} for commit id')
.option('-i, --issue-url <url>', 'override url for issues, use {id} for issue id') // -i kept for back compatibility
.option('--merge-url <url>', 'override url for merges, use {id} for merge id')
.option('--compare-url <url>', 'override url for compares, use {from} and {to} for tags')
.option('--issue-pattern <regex>', 'override regex pattern for issues in commit messages')
.option('--breaking-pattern <regex>', 'regex pattern for breaking change commits')
.option('--merge-pattern <regex>', 'add custom regex pattern for merge commits')
.option('--ignore-commit-pattern <regex>', 'pattern to ignore when parsing commits')
.option('--tag-pattern <regex>', 'override regex pattern for version tags')
.option('--tag-prefix <prefix>', 'prefix used in version tags')
.option('--sort-tags <property>', `sort commits by semantic versioning or git fields, default: ${DEFAULT_OPTIONS.sortTags}`)
.option('--starting-version <tag>', 'specify earliest version to include in changelog')
.option('--starting-date <yyyy-mm-dd>', 'specify earliest date to include in changelog')
.option('--sort-commits <property>', `sort commits by property [relevance, date, date-desc], default: ${DEFAULT_OPTIONS.sortCommits}`)
.option('--release-summary', 'use tagged commit message body as release summary')
.option('--unreleased-only', 'only output unreleased changes')
.option('--hide-empty-releases', 'hide empty releases')
.option('--hide-credit', 'hide auto-changelog credit')
.option('--handlebars-setup <file>', 'handlebars setup file')
.option('--append-git-log <string>', 'string to append to git log command')
.option('--append-git-tag <string>', 'string to append to git tag command')
.option('--prepend', 'prepend changelog to output file')
.option('--stdout', 'output changelog to stdout')
.version(version)
.parse(argv)
.opts()
const pkg = await readJson(PACKAGE_FILE)
const packageOptions = pkg ? pkg[PACKAGE_OPTIONS_KEY] : null
const dotOptions = await readJson(commandOptions.config || DEFAULT_OPTIONS.config)
const options = {
...DEFAULT_OPTIONS,
...dotOptions,
...packageOptions,
...commandOptions
}
const remote = await fetchRemote(options)
const latestVersion = await getLatestVersion(options)
return {
...options,
...remote,
latestVersion
}
}
const getLatestVersion = async options => {
if (options.latestVersion) {
return options.latestVersion
}
if (options.package) {
const file = options.package === true ? PACKAGE_FILE : options.package
if (await fileExists(file) === false) {
throw new Error(`File ${file} does not exist`)
}
const { version } = await readJson(file)
return version
}
return null
}
const run = async argv => {
const options = await getOptions(argv)
const log = string => options.stdout ? null : updateLog(string)
log('Fetching tags…')
const tags = await fetchTags(options)
log(`${tags.length} version tags found…`)
const onParsed = ({ title }) => log(`Fetched ${title}…`)
const releases = await parseReleases(tags, options, onParsed)
const changelog = await compileTemplate(releases, options)
await write(changelog, options, log)
}
const write = async (changelog, options, log) => {
if (options.stdout) {
process.stdout.write(changelog)
return
}
const bytes = formatBytes(Buffer.byteLength(changelog, 'utf8'))
const existing = await fileExists(options.output) && await readFile(options.output, 'utf8')
if (existing) {
const index = options.prepend ? 0 : existing.indexOf(PREPEND_TOKEN)
if (index !== -1) {
const prepended = `${changelog}\n${existing.slice(index)}`
await writeFile(options.output, prepended)
log(`${bytes} prepended to ${options.output}\n`)
return
}
}
await writeFile(options.output, changelog)
log(`${bytes} written to ${options.output}\n`)
}
module.exports = {
run
}