From 2cdf09eab897cfaa3c483d3337e5cfdb68bfd858 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Fri, 3 Dec 2021 17:38:34 +1100 Subject: [PATCH 1/3] feat!: switch to ESM, fix output colourising, dedupe more code w/ branch-diff * upgrade all deps, including ESM-only deps * --simple is now default output, including colourising, with --markdown being an opt-in output format. * move process + print logic to separate module for exporting for simplifying branch-diff * add --sha and --reverse options from branch-diff to dedupe some processing code Fixes: https://github.com/nodejs/changelog-maker/issues/120 Closes: https://github.com/nodejs/changelog-maker/pull/107 Closes: https://github.com/nodejs/changelog-maker/pull/119 --- README.md | 7 +- changelog-maker.js | 169 ++++++++++++--------------------------- collect-commit-labels.js | 80 +++++++++--------- commit-to-output.js | 29 +++---- format.mjs => format.js | 4 +- group-commits.js | 8 +- groups.js | 29 ++++--- package.json | 28 ++++--- process-commits.js | 75 +++++++++++++++++ reverts.js | 9 +-- test.js | 31 +++---- 11 files changed, 230 insertions(+), 239 deletions(-) rename format.mjs => format.js (85%) create mode 100644 process-commits.js diff --git a/README.md b/README.md index e004449..a129f36 100644 --- a/README.md +++ b/README.md @@ -44,12 +44,15 @@ npm i changelog-maker -g ## Usage -**`changelog-maker [--simple] [--group] [--commit-url=] [--start-ref=] [--end-ref=] [github-user[, github-project]]`** +**`changelog-maker [--plaintext|p] [--markdown|md] [--sha] [--group|-g] [--reverse] [--commit-url=] [--start-ref=] [--end-ref=] [github-user[, github-project]]`** `github-user` and `github-project` should point to the GitHub repository that can be used to find the `PR-URL` data if just an issue number is provided and will also impact how the PR-URL issue numbers are displayed -* `--simple`: print a simple form, without additional Markdown cruft +* `--plaintext`: print a very simple form, without commit details, implies `--group` +* `--markdown`: print a Markdown formatted from, with links and proper escaping +* `--sha`: print only the list of short-form commit hashes * `--group`: reorder commits so that they are listed in groups where the `xyz:` prefix of the commit message defines the group. Commits are listed in original order _within_ group. +* `--reverse`: reverse the order of commits when printed, does not work with `--reverse` * `--commit-url`: pass in a url template which will be used to generate commit URLs for a repository not hosted in Github. `{ref}` is the placeholder that will be replaced with the commit, i.e. `--commit-url=https://gitlab.com/myUser/myRepo/commit/{ref}` * `--start-ref=`: use the given git `` as a starting point rather than the _last tag_. The `` can be anything commit-ish including a commit sha, tag, branch name. If you specify a `--start-ref` argument the commit log will not be pruned so that version commits and `working on ` commits are left in the list. * `--end-ref=`: use the given git `` as a end-point rather than the _now_. The `` can be anything commit-ish including a commit sha, tag, branch name. diff --git a/changelog-maker.js b/changelog-maker.js index af6af73..f5336d6 100755 --- a/changelog-maker.js +++ b/changelog-maker.js @@ -1,42 +1,26 @@ #!/usr/bin/env node -'use strict' - -const fs = require('fs') -const path = require('path') -const split2 = require('split2') -const list = require('list-stream') -const stripAnsi = require('strip-ansi') -const pkgtoId = require('pkg-to-id') -const commitStream = require('commit-stream') -const gitexec = require('gitexec') -const { commitToOutput, formatType } = require('./commit-to-output') -const groupCommits = require('./group-commits') -const collectCommitLabels = require('./collect-commit-labels') -const { isReleaseCommit, toGroups } = require('./groups') -const pkg = require('./package.json') -const debug = require('debug')(pkg.name) -const argv = require('minimist')(process.argv.slice(2)) - -// Skip on formatting on Node.js 10. -const formatMarkdown = process.versions.node.startsWith('10.') ? false : import('./format.mjs') - -const quiet = argv.quiet || argv.q +import { existsSync, readFileSync } from 'fs' +import { join } from 'path' +import process from 'process' +import stream from 'stream' +import split2 from 'split2' +import pkgtoId from 'pkg-to-id' +import commitStream from 'commit-stream' +import gitexec from 'gitexec' +import _debug from 'debug' +import minimist from 'minimist' +import { processCommits } from './process-commits.js' +import { isReleaseCommit } from './groups.js' + +const { pipeline } = stream.promises +const debug = _debug('changelog-maker') +const argv = minimist(process.argv.slice(2)) const help = argv.h || argv.help -const commitUrl = argv['commit-url'] || 'https://github.com/{ghUser}/{ghRepo}/commit/{ref}' -const pkgFile = path.join(process.cwd(), 'package.json') -const pkgData = fs.existsSync(pkgFile) ? require(pkgFile) : {} +const pkgFile = join(process.cwd(), 'package.json') +const pkgData = existsSync(pkgFile) ? JSON.parse(readFileSync(pkgFile)) : {} const pkgId = pkgtoId(pkgData) -const getFormat = () => { - if (argv.simple || argv.s) { - return formatType.SIMPLE - } else if (argv.plaintext || argv.p) { - return formatType.PLAINTEXT - } - return formatType.MARKDOWN -} - const ghId = { user: argv._[0] || pkgId.user || 'nodejs', repo: argv._[1] || (pkgId.name && stripScope(pkgId.name)) || 'node' @@ -58,14 +42,11 @@ if (help) { } function showUsage () { - let usage = fs.readFileSync(path.join(__dirname, 'README.md'), 'utf8') + const usage = readFileSync(new URL('README.md', import.meta.url), 'utf8') .replace(/[\s\S]+(## Usage\n[\s\S]*)\n## [\s\S]+/m, '$1') - if (process.stdout.isTTY) { - usage = usage - .replace(/## Usage\n[\s]*/m, '') - .replace(/\*\*/g, '') - .replace(/`/g, '') - } + .replace(/## Usage\n[\s]*/m, 'Usage: ') + .replace(/\*\*/g, '') + .replace(/`/g, '') process.stdout.write(usage) } @@ -81,6 +62,18 @@ function replace (s, m) { return s } +const _startrefcmd = replace(refcmd, { ref: argv['start-ref'] || defaultRef }) +const _endrefcmd = argv['end-ref'] && replace(refcmd, { ref: argv['end-ref'] }) +const _sincecmd = replace(commitdatecmd, { refcmd: _startrefcmd }) +const _untilcmd = argv['end-ref'] ? replace(commitdatecmd, { refcmd: _endrefcmd }) : untilcmd +const _gitcmd = replace(gitcmd, { sincecmd: _sincecmd, untilcmd: _untilcmd }) + +debug('%s', _startrefcmd) +debug('%s', _endrefcmd) +debug('%s', _sincecmd) +debug('%s', _untilcmd) +debug('%s', _gitcmd) + function organiseCommits (list) { if (argv['start-ref'] || argv.a || argv.all) { if (argv['filter-release']) { @@ -105,86 +98,22 @@ function organiseCommits (list) { }) } -async function printCommits (list) { - for await (let commit of list) { - if (!process.stdout.isTTY) { - commit = stripAnsi(commit) - } - process.stdout.write(commit) - } -} - -function onCommitList (err, list) { - if (err) { - return fatal(err) - } - - list = organiseCommits(list) - - collectCommitLabels(list, (err) => { - if (err) { - return fatal(err) - } - - if (argv.group) { - list = groupCommits(list) - } - - const format = getFormat() - if (format === formatType.PLAINTEXT) { - const formatted = [] - - let currentGroup - for (const commit of list) { - const commitGroup = toGroups(commit.summary) - if (currentGroup !== commitGroup) { - formatted.push(`${commitGroup}:`) - currentGroup = commitGroup - } - formatted.push(commitToOutput(commit, formatType.PLAINTEXT, ghId, commitUrl)) +async function run () { + let commitList = [] + await pipeline( + gitexec.exec(process.cwd(), _gitcmd), + split2(), + commitStream(ghId.user, ghId.repo), + async function * (source) { + for await (const commit of source) { + commitList.push(commit) } - - list = formatted.map((line) => `${line}\n`) - } else { - list = list.map(async (commit) => { - let output = commitToOutput(commit, format, ghId, commitUrl) - if (format === formatType.MARKDOWN) { - if (!process.stdout.isTTY) { - output = stripAnsi(output) - } - if (process.versions.node.startsWith('10.')) { - return `${output}\n` - } - return formatMarkdown.then((module) => module.default(output)) - } - return `${output}\n` - }) - } - - if (!quiet) { - printCommits(list) - } - }) + }) + commitList = organiseCommits(commitList) + await processCommits(argv, ghId, commitList) } -function fatal (err) { - console.error(`Fatal error: ${err.message}`) +run().catch((err) => { + console.error(err) process.exit(1) -} - -const _startrefcmd = replace(refcmd, { ref: argv['start-ref'] || defaultRef }) -const _endrefcmd = argv['end-ref'] && replace(refcmd, { ref: argv['end-ref'] }) -const _sincecmd = replace(commitdatecmd, { refcmd: _startrefcmd }) -const _untilcmd = argv['end-ref'] ? replace(commitdatecmd, { refcmd: _endrefcmd }) : untilcmd -const _gitcmd = replace(gitcmd, { sincecmd: _sincecmd, untilcmd: _untilcmd }) - -debug('%s', _startrefcmd) -debug('%s', _endrefcmd) -debug('%s', _sincecmd) -debug('%s', _untilcmd) -debug('%s', _gitcmd) - -gitexec.exec(process.cwd(), _gitcmd) - .pipe(split2()) - .pipe(commitStream(ghId.user, ghId.repo)) - .pipe(list.obj(onCommitList)) +}) diff --git a/collect-commit-labels.js b/collect-commit-labels.js index 17e322a..4c6da41 100644 --- a/collect-commit-labels.js +++ b/collect-commit-labels.js @@ -1,8 +1,9 @@ 'use strict' -const ghauth = require('ghauth') -const ghissues = require('ghissues') -const async = require('async') +import { promisify } from 'util' +import ghauth from 'ghauth' +import ghissues from 'ghissues' +import async from 'async' const authOptions = { configName: 'changelog-maker', @@ -10,58 +11,53 @@ const authOptions = { noDeviceFlow: true } -function collectCommitLabels (list, callback) { +export async function collectCommitLabels (list) { const sublist = list.filter((commit) => { return typeof commit.ghIssue === 'number' && commit.ghUser && commit.ghProject }) if (!sublist.length) { - return setImmediate(callback) + return } - ghauth(authOptions, (err, authData) => { - if (err) { - return callback(err) - } - - const cache = {} - - const q = async.queue((commit, next) => { - function onFetch (err, issue) { - if (err) { - console.error('Error fetching issue #%s: %s', commit.ghIssue, err.message) - return next() - } + const authData = await promisify(ghauth)(authOptions) - if (issue.labels) { - commit.labels = issue.labels.map((label) => label.name) - } + const cache = {} - next() + const q = async.queue((commit, next) => { + function onFetch (err, issue) { + if (err) { + console.error('Error fetching issue #%s: %s', commit.ghIssue, err.message) + return next() } - if (commit.ghUser === 'iojs') { - commit.ghUser = 'nodejs' // forcibly rewrite as the GH API doesn't do it for us + if (issue.labels) { + commit.labels = issue.labels.map((label) => label.name) } - // To prevent multiple simultaneous requests for the same issue - // from hitting the network at the same time, immediately assign a Promise - // to the cache that all commits with the same ghIssue value will use. - const key = `${commit.ghUser}/${commit.ghProject}#${commit.ghIssue}` - cache[key] = cache[key] || new Promise((resolve, reject) => { - ghissues.get(authData, commit.ghUser, commit.ghProject, commit.ghIssue, (err, issue) => { - if (err) { - return reject(err) - } + next() + } - resolve(issue) - }) + if (commit.ghUser === 'iojs') { + commit.ghUser = 'nodejs' // forcibly rewrite as the GH API doesn't do it for us + } + + // To prevent multiple simultaneous requests for the same issue + // from hitting the network at the same time, immediately assign a Promise + // to the cache that all commits with the same ghIssue value will use. + const key = `${commit.ghUser}/${commit.ghProject}#${commit.ghIssue}` + cache[key] = cache[key] || new Promise((resolve, reject) => { + ghissues.get(authData, commit.ghUser, commit.ghProject, commit.ghIssue, (err, issue) => { + if (err) { + return reject(err) + } + + resolve(issue) }) - cache[key].then((val) => onFetch(null, val), (err) => onFetch(err)) - }, 15) - q.drain(callback) - q.push(sublist) - }) -} + }) + cache[key].then((val) => onFetch(null, val), (err) => onFetch(err)) + }, 15) -module.exports = collectCommitLabels + q.push(sublist) + await q.drain() +} diff --git a/commit-to-output.js b/commit-to-output.js index 9be9fd3..8acd536 100644 --- a/commit-to-output.js +++ b/commit-to-output.js @@ -1,13 +1,12 @@ -'use strict' - -const chalk = require('chalk') -const reverts = require('./reverts') -const groups = require('./groups') +import chalk from 'chalk' +import { isRevert, cleanSummary as cleanRevertSummary } from './reverts.js' +import { toGroups, cleanSummary as cleanGroupSummary } from './groups.js' function cleanUnsupportedMarkdown (txt) { // escape _~*\[]<>` return txt.replace(/([_~*\\[\]<>`])/g, '\\$1') } + function cleanMarkdown (txt) { // Escape backticks for edge case scenarii (no code span support). if (txt.includes('``') || txt.includes('\\`')) { @@ -30,7 +29,8 @@ function cleanMarkdown (txt) { return cleanMdString } -const formatType = { +export const formatType = { + SHA: 'sha', PLAINTEXT: 'plaintext', MARKDOWN: 'markdown', SIMPLE: 'simple' @@ -65,7 +65,7 @@ function toStringSimple (data) { s = s.trim() return (data.semver && data.semver.length) - ? chalk.green(chalk.bold(s)) + ? chalk.green.bold(s) : (data.group === 'doc' ? chalk.grey(s) : s) @@ -84,13 +84,13 @@ function toStringMarkdown (data) { s = s.trim() return (data.semver && data.semver.length) - ? chalk.green(chalk.bold(s)) + ? chalk.green.bold(s) : (data.group === 'doc' ? chalk.grey(s) : s) } -function commitToOutput (commit, format, ghId, commitUrl) { +export function commitToOutput (commit, format, ghId, commitUrl) { const data = {} const prUrlMatch = commit.prUrl && commit.prUrl.match(/^https?:\/\/.+\/([^/]+\/[^/]+)\/\w+\/\d+$/i) const urlHash = `#${commit.ghIssue}` || commit.prUrl @@ -99,9 +99,9 @@ function commitToOutput (commit, format, ghId, commitUrl) { data.sha = commit.sha data.shaUrl = commitUrl.replace(/\{ghUser\}/g, ghId.user).replace(/\{ghRepo\}/g, ghId.repo).replace(/\{ref\}/g, ref) data.semver = commit.labels && commit.labels.filter((l) => l.includes('semver')) - data.revert = reverts.isRevert(commit.summary) - data.group = groups.toGroups(commit.summary) - data.summary = groups.cleanSummary(reverts.cleanSummary(commit.summary)) + data.revert = isRevert(commit.summary) + data.group = toGroups(commit.summary) + data.summary = cleanGroupSummary(cleanRevertSummary(commit.summary)) data.author = (commit.author && commit.author.name) || '' data.pr = prUrlMatch && ((prUrlMatch[1] !== `${ghId.user}/${ghId.repo}` ? prUrlMatch[1] : '') + urlHash) data.prUrl = prUrlMatch && commit.prUrl @@ -114,8 +114,3 @@ function commitToOutput (commit, format, ghId, commitUrl) { return toStringMarkdown(data) } - -module.exports = { - commitToOutput, - formatType -} diff --git a/format.mjs b/format.js similarity index 85% rename from format.mjs rename to format.js index f9f83a1..056d253 100644 --- a/format.mjs +++ b/format.js @@ -8,9 +8,7 @@ const formatter = remark() .use(presetLintNode) .use(remarkStringify) -const format = async (markdown) => { +export async function formatMarkdown (markdown) { const result = await formatter.process(markdown) return result.toString() } - -export default format diff --git a/group-commits.js b/group-commits.js index 6e6f86b..1066654 100644 --- a/group-commits.js +++ b/group-commits.js @@ -1,8 +1,6 @@ -'use strict' +import { toGroups } from './groups.js' -const { toGroups } = require('./groups') - -function groupCommits (list) { +export function groupCommits (list) { const groupList = list.reduce((groupList, commit) => { const group = toGroups(commit.summary) || '*' @@ -18,5 +16,3 @@ function groupCommits (list) { return p.concat(groupList[group]) }, []) } - -module.exports = groupCommits diff --git a/groups.js b/groups.js index 9797114..794dbde 100644 --- a/groups.js +++ b/groups.js @@ -1,45 +1,44 @@ +import { fileURLToPath } from 'url' +import process from 'process' +import { readFileSync } from 'fs' +import { cleanSummary as cleanRevertsSummary } from './reverts.js' + const groupRe = /^((:?\w|-|,|, )+):\s*/i -const reverts = require('./reverts') -function toGroups (summary) { - summary = reverts.cleanSummary(summary) +export function toGroups (summary) { + summary = cleanRevertsSummary(summary) const m = summary.match(groupRe) return (m && m[1]) || '' } -function cleanSummary (summary) { +export function cleanSummary (summary) { return (summary || '').replace(groupRe, '') } /* - -to test this, run on the commandline: +To test this, run on the command line in a nodejs/node clone: for br in v4.x v5.x v6.x v7.x; do git log $br --format='%s' | grep -E '^\d+.*elease$' >> /tmp/release-commits-all.txt; done sort /tmp/release-commits-all.txt | uniq > /tmp/release-commits.txt rm /tmp/release-commits-all.txt -then in this directory: +Then in this directory: node groups.js /tmp/release-commits.txt -doesn't cover false positives though +It doesn't cover false positives though. */ -function isReleaseCommit (summary) { +export function isReleaseCommit (summary) { return /^Working on v?\d{1,2}\.\d{1,3}\.\d{1,3}$/.test(summary) || /^\d{4}-\d{2}-\d{2},? (Node\.js|Version) v?\d{1,2}\.\d{1,3}\.\d{1,3} (["'][A-Za-z ]+["'] )?\((Current|Stable|LTS|Maintenance)\)/.test(summary) || /^\d{4}-\d{2}-\d{2},? io.js v\d{1,2}\.\d{1,3}\.\d{1,3} Release/.test(summary) || /^\d+\.\d+\.\d+$/.test(summary) // `npm version X` style commit } -module.exports.toGroups = toGroups -module.exports.cleanSummary = cleanSummary -module.exports.isReleaseCommit = isReleaseCommit - -if (require.main === module) { +if (process.argv[1] === fileURLToPath(import.meta.url)) { console.log(`Running tests on lines in ${process.argv[2]}...`) - const failures = require('fs').readFileSync(process.argv[2], 'utf8').split('\n').filter(Boolean).filter((summary) => { + const failures = readFileSync(process.argv[2], 'utf8').split('\n').filter(Boolean).filter((summary) => { return !isReleaseCommit(summary) }) if (!failures.length) { diff --git a/package.json b/package.json index 27c1fc4..f7f53b5 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,14 @@ "version": "2.8.0", "description": "A git log to CHANGELOG.md tool", "main": "changelog-maker.js", + "type": "module", "bin": { "changelog-maker": "./changelog-maker.js" }, + "exports": { + "./groups": "./groups.js", + "./process-commits": "./process-commits.js" + }, "author": "Rod (https://r.va.gg/)", "license": "MIT", "repository": { @@ -19,26 +24,25 @@ "keywords": [], "preferGlobal": true, "dependencies": { - "async": "^3.2.0", - "chalk": "^4.1.0", + "async": "^3.2.2", + "chalk": "^5.0.0", "commit-stream": "^1.1.0", - "debug": "^4.3.1", + "debug": "^4.3.3", "ghauth": "^5.0.1", "ghissues": "^1.1.4", "gitexec": "^2.0.1", - "list-stream": "^2.0.0", "minimist": "^1.2.5", - "pkg-to-id": "0.0.3", - "remark": "^14.0.1", - "remark-parse": "^10.0.0", - "remark-preset-lint-node": "^3.2.0", - "remark-stringify": "^10.0.0", - "split2": "^4.0.0", - "strip-ansi": "^6.0.0" + "pkg-to-id": "^0.0.3", + "remark": "^14.0.2", + "remark-parse": "^10.0.1", + "remark-preset-lint-node": "^3.3.0", + "remark-stringify": "^10.0.2", + "split2": "^4.1.0", + "strip-ansi": "^7.0.1" }, "devDependencies": { "standard": "^16.0.4", - "tap": "^15.0.1" + "tap": "^15.1.5" }, "scripts": { "lint": "standard", diff --git a/process-commits.js b/process-commits.js new file mode 100644 index 0000000..0ee0312 --- /dev/null +++ b/process-commits.js @@ -0,0 +1,75 @@ +import stripAnsi from 'strip-ansi' +import { commitToOutput, formatType } from './commit-to-output.js' +import { groupCommits } from './group-commits.js' +import { toGroups } from './groups.js' +import { formatMarkdown } from './format.js' +import { supportsColor } from 'chalk' +import { collectCommitLabels } from './collect-commit-labels.js' + +function getFormat (argv) { + if (argv.sha) { + return formatType.SHA + } else if (argv.plaintext || argv.p) { + return formatType.PLAINTEXT + } else if (argv.markdown || argv.md) { + return formatType.MARKDOWN + } + return formatType.SIMPLE +} + +async function printCommits (list) { + for (let commit of list) { + if (!supportsColor) { + commit = stripAnsi(commit) + } + process.stdout.write(`${commit}\n`) + } +} + +export async function processCommits (argv, ghId, list) { + const quiet = argv.quiet || argv.q + const reverse = argv.reverse + const commitUrl = argv['commit-url'] || 'https://github.com/{ghUser}/{ghRepo}/commit/{ref}' + + await collectCommitLabels(list) + + const format = getFormat(argv) + + if (argv.group || argv.g || format === formatType.PLAINTEXT) { + list = groupCommits(list) + } + + if (format === formatType.SHA) { + list = list.map((commit) => `${commit.sha.substr(0, 10)}`) + } else if (format === formatType.PLAINTEXT) { + const formatted = [] + + let currentGroup + for (const commit of list) { + const commitGroup = toGroups(commit.summary) + if (currentGroup !== commitGroup) { + formatted.push(`${commitGroup}:`) + currentGroup = commitGroup + } + formatted.push(commitToOutput(commit, formatType.PLAINTEXT, ghId, commitUrl)) + } + list = formatted + } else { + list = await Promise.all(list.map(async (commit) => { + let output = commitToOutput(commit, format, ghId, commitUrl) + if (format === formatType.MARKDOWN) { + output = stripAnsi(output) + return (await formatMarkdown(output)).replace(/\n$/, '') + } + return output + })) + } + + if (format !== formatType.PLAINTEXT && reverse) { + list = list.reverse() + } + + if (!quiet) { + printCommits(list) + } +} diff --git a/reverts.js b/reverts.js index 6ce99e3..069c987 100644 --- a/reverts.js +++ b/reverts.js @@ -1,18 +1,13 @@ -'use strict' - const revertRe = /^revert\s+"?/i -function isRevert (summary) { +export function isRevert (summary) { return summary && revertRe.test(summary) } -function cleanSummary (summary = '') { +export function cleanSummary (summary = '') { if (!isRevert(summary)) { return summary } return summary.replace(revertRe, '').replace(/"$/, '') } - -module.exports.isRevert = isRevert -module.exports.cleanSummary = cleanSummary diff --git a/test.js b/test.js index 0aa1e18..2053aaf 100644 --- a/test.js +++ b/test.js @@ -1,20 +1,21 @@ // NOTE: to run this you will probably need to be authorized with GitHub. // Run `./changelog-maker.js` by itself to set this up. -'use strict' +import { dirname, join } from 'path' +import { execSync } from 'child_process' +import { test } from 'tap' +import chalk from 'chalk' -const path = require('path') -const { execSync } = require('child_process') -const { test } = require('tap') +const __dirname = dirname(new URL(import.meta.url).pathname) function exec (args) { - const stdout = execSync(`"${process.execPath}" ${path.join(__dirname, 'changelog-maker.js')} ${args}`).toString() + const stdout = execSync(`"${process.execPath}" ${join(__dirname, 'changelog-maker.js')} ${args}`).toString() return stdout } test('test basic commit block', (t) => { - t.equal(exec('--start-ref=v1.3.9 --end-ref=v1.3.10'), + t.equal(exec('--md --start-ref=v1.3.9 --end-ref=v1.3.10'), `* \\[[\`e28b3f2813\`](https://github.com/nodejs/changelog-maker/commit/e28b3f2813)] - 1.3.10 (Rod Vagg) * \\[[\`ace3af943e\`](https://github.com/nodejs/changelog-maker/commit/ace3af943e)] - Merge pull request #13 from jamsyoung/private-repo-support (Rod Vagg) * \\[[\`25ec5428bc\`](https://github.com/nodejs/changelog-maker/commit/25ec5428bc)] - default to repo scope always - revert previous changes (James Young) @@ -25,7 +26,7 @@ test('test basic commit block', (t) => { }) test('test filter-release', (t) => { - t.equal(exec('--start-ref=v1.3.9 --end-ref=v1.3.10 --filter-release'), + t.equal(exec('--md --start-ref=v1.3.9 --end-ref=v1.3.10 --filter-release'), `* \\[[\`ace3af943e\`](https://github.com/nodejs/changelog-maker/commit/ace3af943e)] - Merge pull request #13 from jamsyoung/private-repo-support (Rod Vagg) * \\[[\`25ec5428bc\`](https://github.com/nodejs/changelog-maker/commit/25ec5428bc)] - default to repo scope always - revert previous changes (James Young) * \\[[\`424d6c22c1\`](https://github.com/nodejs/changelog-maker/commit/424d6c22c1)] - add --private arg to set repo scope, update readme (James Young) @@ -34,7 +35,7 @@ test('test filter-release', (t) => { }) test('test simple', (t) => { - t.equal(exec('--start-ref=v1.3.9 --end-ref=v1.3.10 --simple'), + t.equal(exec('--start-ref=v1.3.9 --end-ref=v1.3.10'), `* [e28b3f2813] - 1.3.10 (Rod Vagg) * [ace3af943e] - Merge pull request #13 from jamsyoung/private-repo-support (Rod Vagg) * [25ec5428bc] - default to repo scope always - revert previous changes (James Young) @@ -55,8 +56,8 @@ test: }) test('test group, semver labels, PR-URL', (t) => { - t.equal(exec('--start-ref=v2.2.7 --end-ref=9c700d29 --group --filter-release --simple'), - `* [cc442b6534] - (SEMVER-MINOR) minor nit (Rod Vagg) https://github.com/nodejs/node/pull/23715 + t.equal(exec('--start-ref=v2.2.7 --end-ref=9c700d29 --group --filter-release'), + `${chalk.green.bold('* [cc442b6534] - (SEMVER-MINOR) minor nit (Rod Vagg) https://github.com/nodejs/node/pull/23715')} * [4f2b7f8136] - deps: use strip-ansi instead of chalk.stripColor (Rod Vagg) * [6898501e18] - deps: update deps, introduce test & lint deps (Rod Vagg) * [9c700d2910] - feature: refactor and improve --commit-url (Rod Vagg) @@ -68,7 +69,7 @@ test('test group, semver labels, PR-URL', (t) => { }) test('test simple group, semver labels, PR-URL', (t) => { - t.equal(exec('--start-ref=v2.2.7 --end-ref=9c700d29 --group --filter-release'), + t.equal(exec('--md --start-ref=v2.2.7 --end-ref=9c700d29 --group --filter-release'), `* \\[[\`cc442b6534\`](https://github.com/nodejs/changelog-maker/commit/cc442b6534)] - **(SEMVER-MINOR)** minor nit (Rod Vagg) [nodejs/node#23715](https://github.com/nodejs/node/pull/23715) * \\[[\`4f2b7f8136\`](https://github.com/nodejs/changelog-maker/commit/4f2b7f8136)] - **deps**: use strip-ansi instead of chalk.stripColor (Rod Vagg) * \\[[\`6898501e18\`](https://github.com/nodejs/changelog-maker/commit/6898501e18)] - **deps**: update deps, introduce test & lint deps (Rod Vagg) @@ -81,7 +82,7 @@ test('test simple group, semver labels, PR-URL', (t) => { }) test('test blank commit-url', (t) => { - let actual = exec('--start-ref=v2.2.7 --end-ref=9c700d29 --filter-release --commit-url=http://foo.bar/').split('\n') + let actual = exec('--md --start-ref=v2.2.7 --end-ref=9c700d29 --filter-release --commit-url=http://foo.bar/').split('\n') actual.splice(0, actual.length - 3) actual = actual.join('\n') t.equal(actual, @@ -92,7 +93,7 @@ test('test blank commit-url', (t) => { }) test('test blank commit-url', (t) => { - let actual = exec('--start-ref=v2.2.7 --end-ref=9c700d29 --filter-release --commit-url=https://yeehaw.com/{ref}/{ref}/{ghUser}/{ghRepo}/').split('\n') + let actual = exec('--md --start-ref=v2.2.7 --end-ref=9c700d29 --filter-release --commit-url=https://yeehaw.com/{ref}/{ref}/{ghUser}/{ghRepo}/').split('\n') actual.splice(0, actual.length - 3) actual = actual.join('\n') t.equal(actual, @@ -104,7 +105,7 @@ test('test blank commit-url', (t) => { test('test backtick strings in commit messages', (t) => { t.equal( - exec('--start-ref=ce886b5130 --end-ref=0717fdc946 --filter-release --commit-url=https://yeehaw.com/{ref}/{ref}/{ghUser}/{ghRepo}/'), + exec('--md --start-ref=ce886b5130 --end-ref=0717fdc946 --filter-release --commit-url=https://yeehaw.com/{ref}/{ref}/{ghUser}/{ghRepo}/'), `* \\[[\`0717fdc946\`](https://yeehaw.com/0717fdc946/0717fdc946/nodejs/changelog-maker/)] - **test**: \\\`commit\\_msg\\\` with an unescaped \\\` backtick char (Antoine du Hamel) * \\[[\`9f1d897c88\`](https://yeehaw.com/9f1d897c88/9f1d897c88/nodejs/changelog-maker/)] - **test**: \\\`commit\\_msg\\\` with an escaped \\\\\\\` backtick char (Antoine du Hamel) * \\[[\`4a3154bde0\`](https://yeehaw.com/4a3154bde0/4a3154bde0/nodejs/changelog-maker/)] - **test**: \`commit_msg\` starting with a backtick string (Antoine du Hamel) @@ -118,7 +119,7 @@ test('test backtick strings in commit messages', (t) => { test('test markdown punctuation chars in commit message and author name', (t) => { t.equal( - exec('--start-ref=f12fe589c4 --end-ref=f12fe589c4 --filter-release --commit-url=https://yeehaw.com/{ref}/{ref}/{ghUser}/{ghRepo}/'), + exec('--md --start-ref=f12fe589c4 --end-ref=f12fe589c4 --filter-release --commit-url=https://yeehaw.com/{ref}/{ref}/{ghUser}/{ghRepo}/'), `* \\[[\`f12fe589c4\`](https://yeehaw.com/f12fe589c4/f12fe589c4/nodejs/changelog-maker/)] - **group\\_with\\_underscore**: test commit message (Author\\_name\\_with\\_underscore) `) t.end() From 3eba26695819a012200eddf211f68a20fb2e7a49 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Fri, 3 Dec 2021 18:49:35 +1100 Subject: [PATCH 2/3] chore: remove Node.js v12 support --- .github/workflows/test-and-release.yml | 2 +- changelog-maker.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-release.yml b/.github/workflows/test-and-release.yml index 4e2baba..ba99aaf 100644 --- a/.github/workflows/test-and-release.yml +++ b/.github/workflows/test-and-release.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - node: [12, 14, 16] + node: [14, 16] # windows support not quite ready: os: [ubuntu-latest, windows-latest] os: [ubuntu-latest] diff --git a/changelog-maker.js b/changelog-maker.js index f5336d6..ad1f1f3 100755 --- a/changelog-maker.js +++ b/changelog-maker.js @@ -3,7 +3,8 @@ import { existsSync, readFileSync } from 'fs' import { join } from 'path' import process from 'process' -import stream from 'stream' +import { pipeline as _pipeline } from 'stream' +import { promisify } from 'util' import split2 from 'split2' import pkgtoId from 'pkg-to-id' import commitStream from 'commit-stream' @@ -13,7 +14,7 @@ import minimist from 'minimist' import { processCommits } from './process-commits.js' import { isReleaseCommit } from './groups.js' -const { pipeline } = stream.promises +const pipeline = promisify(_pipeline) const debug = _debug('changelog-maker') const argv = minimist(process.argv.slice(2)) const help = argv.h || argv.help From 61d2293823feee3ea9e1bcd85b939ec8e78e2439 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Fri, 3 Dec 2021 18:58:55 +1100 Subject: [PATCH 3/3] fix: add back --format=x arg option --- README.md | 11 ++++++++--- process-commits.js | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a129f36..ae013bc 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,14 @@ npm i changelog-maker -g `github-user` and `github-project` should point to the GitHub repository that can be used to find the `PR-URL` data if just an issue number is provided and will also impact how the PR-URL issue numbers are displayed -* `--plaintext`: print a very simple form, without commit details, implies `--group` -* `--markdown`: print a Markdown formatted from, with links and proper escaping -* `--sha`: print only the list of short-form commit hashes +* `--format`: dictates what formatting the output will have. Possible options are: `simple`, `markdown`, `plaintext`, and `sha`. The default is to print a `simple` output suitable for stdout. + - `simple`: don't print full markdown output, good for console printing without the additional fluff. + - `sha`: print only the 10-character truncated commit hashes. + - `plaintext`: a very simple form, without commit details, implies `--group`. + - `markdown`: a Markdown formatted from, with links and proper escaping. +* `--sha`: same as `--format=sha`. +* `--plaintext`: same as `--format=plaintext`. +* `--markdown`: same as `--format=markdown`. * `--group`: reorder commits so that they are listed in groups where the `xyz:` prefix of the commit message defines the group. Commits are listed in original order _within_ group. * `--reverse`: reverse the order of commits when printed, does not work with `--reverse` * `--commit-url`: pass in a url template which will be used to generate commit URLs for a repository not hosted in Github. `{ref}` is the placeholder that will be replaced with the commit, i.e. `--commit-url=https://gitlab.com/myUser/myRepo/commit/{ref}` diff --git a/process-commits.js b/process-commits.js index 0ee0312..0e405e1 100644 --- a/process-commits.js +++ b/process-commits.js @@ -7,7 +7,9 @@ import { supportsColor } from 'chalk' import { collectCommitLabels } from './collect-commit-labels.js' function getFormat (argv) { - if (argv.sha) { + if (argv.format && Object.values(formatType).includes(argv.format)) { + return argv.format + } else if (argv.sha) { return formatType.SHA } else if (argv.plaintext || argv.p) { return formatType.PLAINTEXT