Skip to content

Commit df17633

Browse files
committed
feat!: switch to ESM, dedupe more code w/ changelog-maker
Also remove Node.js v12 support Ref: nodejs/changelog-maker#121
1 parent 95db90c commit df17633

File tree

4 files changed

+74
-154
lines changed

4 files changed

+74
-154
lines changed

.github/workflows/test-and-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
strategy:
99
fail-fast: false
1010
matrix:
11-
node: [12, 14, 16]
11+
node: [14, 16]
1212
# windows support not quite ready: os: [ubuntu-latest, windows-latest]
1313
os: [ubuntu-latest]
1414

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
## Usage
99

10-
**`$ branch-diff [--simple] [--group] [--patch-only] base-branch comparison-branch`**
10+
**`$ branch-diff [--sha] [--plaintext] [--markdown] [--group] [--reverse] [--patch-only] base-branch comparison-branch`**
1111

1212
A commit is considered to be in the comparison-branch but not in the base-branch if:
1313

@@ -29,12 +29,16 @@ But the comparison isn't quite as strict, generally leading to a shorter list of
2929
* `--exclude-label`: Exclude any commits from the list that come from a GitHub pull request with the given label. Multiple `--exclude-label` options may be provided, they will also be split by `,`. e.g. `--exclude-label=semver-major,meta`.
3030
* `--require-label`: Only include commits in the list that come from a GitHub pull request with the given label. Multiple `--require-label` options may be provided, they will also be split by `,`. e.g. `--require-label=test,doc`.
3131
* `--patch-only`: An alias for `--exclude-label=semver-major,semver-minor`.
32-
* `--format`: Dictates what formatting the output will have. Possible options are: `simple`, `plaintext`, and `sha`. The default is to print markdown-formatted output; `plaintext` also implies that commits will be grouped.
32+
* `--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.
3333
- `simple`: Don't print full markdown output, good for console printing without the additional fluff.
34-
- `sha`: Print only the 10-character truncated commit shasums. Good for piping though additional tooling, such as `xargs git cherry-pick` for applying commits.
35-
* `--simple` or `-s`: An alias for `--format=simple`.
34+
- `sha`: Print only the 10-character truncated commit hashes. Good for piping though additional tooling, such as `xargs git cherry-pick` for applying commits.
35+
- `plaintext`: A very simple form, without commit details, implies `--group`.
36+
- `markdown`: A Markdown formatted from, with links and proper escaping.
37+
* `--sha`: Same as `--format=sha`.
38+
* `--plaintext`: Same as `--format=plaintext`.
39+
* `--markdown`: Same as `--format=markdown`.
3640
* `--filter-release`: Exclude Node-style release commits from the list. e.g. `Working on v1.0.0` or `2015-10-21 Version 2.0.0`.
37-
* `--reverse`: Reverse the results, this is especially useful when piping output to `xargs`
41+
* `--reverse`: Reverse the results, this is especially useful when piping output to `xargs`.
3842
* `--commit-url`: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}`. `{ghUser}` and `{ghRepo}` are available if they can be derived from package.json (Gitlab and Bitbucket URLs should be understood in package.json).
3943

4044
## License

branch-diff.js

Lines changed: 59 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
#!/usr/bin/env node
22

3-
'use strict'
4-
5-
const fs = require('fs')
6-
const path = require('path')
7-
const commitStream = require('commit-stream')
8-
const split2 = require('split2')
9-
const listStream = require('list-stream')
10-
const pkgtoId = require('pkg-to-id')
11-
const stripAnsi = require('strip-ansi')
12-
const map = require('map-async')
13-
const { commitToOutput } = require('changelog-maker/commit-to-output')
14-
const collectCommitLabels = require('changelog-maker/collect-commit-labels')
15-
const groupCommits = require('changelog-maker/group-commits')
16-
const { isReleaseCommit, toGroups } = require('changelog-maker/groups')
17-
const gitexec = require('gitexec')
18-
3+
import fs from 'fs'
4+
import path from 'path'
5+
import process from 'process'
6+
import { pipeline as _pipeline } from 'stream'
7+
import { promisify } from 'util'
8+
import commitStream from 'commit-stream'
9+
import split2 from 'split2'
10+
import pkgtoId from 'pkg-to-id'
11+
import minimist from 'minimist'
12+
import { isReleaseCommit } from 'changelog-maker/groups'
13+
import { processCommits } from 'changelog-maker/process-commits'
14+
import gitexec from 'gitexec'
15+
16+
const pipeline = promisify(_pipeline)
1917
const pkgFile = path.join(process.cwd(), 'package.json')
2018
const pkgData = fs.existsSync(pkgFile) ? require(pkgFile) : {}
2119
const pkgId = pkgtoId(pkgData)
@@ -26,23 +24,6 @@ const ghId = {
2624
user: pkgId.user || 'nodejs',
2725
repo: pkgId.name || 'node'
2826
}
29-
const defaultCommitUrl = 'https://github.com/{ghUser}/{ghRepo}/commit/{ref}'
30-
31-
const formatType = {
32-
PLAINTEXT: 'plaintext',
33-
MARKDOWN: 'markdown',
34-
SIMPLE: 'simple',
35-
SHA: 'sha'
36-
}
37-
38-
const getFormat = (argv) => {
39-
if (argv.format && Object.values(formatType).includes(argv.format)) {
40-
return argv.format
41-
} else if (argv.simple || argv.s) {
42-
return formatType.SIMPLE
43-
}
44-
return formatType.MARKDOWN
45-
}
4627

4728
function replace (s, m) {
4829
Object.keys(m).forEach(function (k) {
@@ -51,37 +32,26 @@ function replace (s, m) {
5132
return s
5233
}
5334

54-
function branchDiff (branch1, branch2, options, callback) {
35+
export async function branchDiff (branch1, branch2, options) {
5536
if (!branch1 || !branch2) {
56-
return callback(new Error('Must supply two branch names to compare'))
37+
throw new Error('Must supply two branch names to compare')
5738
}
5839

5940
const repoPath = options.repoPath || process.cwd()
60-
61-
findMergeBase(repoPath, branch1, branch2, (err, commit) => {
62-
if (err) { return callback(err) }
63-
map(
64-
[branch1, branch2], (branch, callback) => {
65-
collect(repoPath, branch, commit, branch === branch2 && options.endRef).pipe(listStream.obj(callback))
66-
}
67-
, (err, branchCommits) => err ? callback(err) : diffCollected(options, branchCommits, callback)
68-
)
69-
})
41+
const commit = await findMergeBase(repoPath, branch1, branch2)
42+
const branchCommits = await Promise.all([branch1, branch2].map(async (branch) => {
43+
return collect(repoPath, branch, commit, branch === branch2 && options.endRef)
44+
}))
45+
return await diffCollected(options, branchCommits)
7046
}
7147

72-
function findMergeBase (repoPath, branch1, branch2, callback) {
48+
async function findMergeBase (repoPath, branch1, branch2) {
7349
const gitcmd = `git merge-base ${branch1} ${branch2}`
74-
75-
gitexec.execCollect(repoPath, gitcmd, (err, data) => {
76-
if (err) {
77-
return callback(err)
78-
}
79-
80-
callback(null, data.substr(0, 10))
81-
})
50+
const data = await promisify(gitexec.execCollect)(repoPath, gitcmd)
51+
return data.substr(0, 10)
8252
}
8353

84-
function diffCollected (options, branchCommits, callback) {
54+
async function diffCollected (options, branchCommits) {
8555
function isInList (commit) {
8656
return branchCommits[0].some((c) => {
8757
if (commit.sha === c.sha) { return true }
@@ -102,102 +72,55 @@ function diffCollected (options, branchCommits, callback) {
10272

10373
let list = branchCommits[1].filter((commit) => !isInList(commit))
10474

105-
collectCommitLabels(list, (err) => {
106-
if (err) {
107-
return callback(err)
108-
}
109-
110-
if (options.excludeLabels.length > 0) {
111-
list = list.filter((commit) => {
112-
return !commit.labels || !commit.labels.some((label) => {
113-
return options.excludeLabels.indexOf(label) >= 0
114-
})
115-
})
116-
}
117-
118-
if (options.requireLabels.length > 0) {
119-
list = list.filter((commit) => {
120-
return commit.labels && commit.labels.some((label) => {
121-
return options.requireLabels.indexOf(label) >= 0
122-
})
75+
if (options.excludeLabels.length > 0) {
76+
list = list.filter((commit) => {
77+
return !commit.labels || !commit.labels.some((label) => {
78+
return options.excludeLabels.indexOf(label) >= 0
12379
})
124-
}
125-
126-
if (options.group) {
127-
list = groupCommits(list)
128-
}
129-
130-
callback(null, list)
131-
})
132-
}
133-
134-
function printCommits (list, format, reverse, commitUrl) {
135-
if (format === formatType.SHA) {
136-
list = list.map((commit) => `${commit.sha.substr(0, 10)}`)
137-
} else if (format === formatType.SIMPLE) {
138-
list = list.map((commit) => commitToOutput(commit, formatType.SIMPLE, ghId, commitUrl))
139-
} else if (format === formatType.PLAINTEXT) {
140-
// Plaintext format implies grouping.
141-
list = groupCommits(list)
142-
143-
const formatted = []
144-
let currentGroup
145-
for (const commit of list) {
146-
const commitGroup = toGroups(commit.summary)
147-
if (currentGroup !== commitGroup) {
148-
formatted.push(`${commitGroup}:`)
149-
currentGroup = commitGroup
150-
}
151-
formatted.push(commitToOutput(commit, formatType.PLAINTEXT, ghId, commitUrl))
152-
}
153-
list = formatted
154-
} else {
155-
list = list.map((commit) => {
156-
return commitToOutput(commit, formatType.MARKDOWN, ghId, commitUrl)
15780
})
15881
}
15982

160-
if (reverse) {
161-
list = list.reverse()
162-
}
163-
164-
let out = list.join('\n') + '\n'
165-
166-
if (!process.stdout.isTTY) {
167-
out = stripAnsi(out)
83+
if (options.requireLabels.length > 0) {
84+
list = list.filter((commit) => {
85+
return commit.labels && commit.labels.some((label) => {
86+
return options.requireLabels.indexOf(label) >= 0
87+
})
88+
})
16889
}
16990

170-
process.stdout.write(out)
91+
return list
17192
}
17293

173-
function collect (repoPath, branch, startCommit, endRef) {
94+
async function collect (repoPath, branch, startCommit, endRef) {
17495
const endrefcmd = endRef && replace(refcmd, { ref: endRef })
17596
const untilcmd = endRef ? replace(commitdatecmd, { refcmd: endrefcmd }) : ''
17697
const _gitcmd = replace(gitcmd, { branch, startCommit, untilcmd })
17798

178-
return gitexec.exec(repoPath, _gitcmd)
179-
.pipe(split2())
180-
.pipe(commitStream(ghId.user, ghId.repo))
99+
const commitList = []
100+
await pipeline(
101+
gitexec.exec(repoPath, _gitcmd),
102+
split2(),
103+
commitStream(ghId.user, ghId.repo),
104+
async function * (source) {
105+
for await (const commit of source) {
106+
commitList.push(commit)
107+
}
108+
})
109+
return commitList
181110
}
182111

183-
module.exports = branchDiff
184-
185-
function main () {
112+
async function main () {
186113
const minimistConfig = {
187114
boolean: ['version', 'group', 'patch-only', 'simple', 'filter-release', 'reverse']
188115
}
189-
const argv = require('minimist')(process.argv.slice(2), minimistConfig)
116+
const argv = minimist(process.argv.slice(2), minimistConfig)
190117
const branch1 = argv._[0]
191118
const branch2 = argv._[1]
192-
const reverse = argv.reverse
193119
const group = argv.group || argv.g
194120
const endRef = argv['end-ref']
195-
const commitUrl = argv['commit-url'] || defaultCommitUrl
196121
let excludeLabels = []
197122
let requireLabels = []
198123

199-
const format = getFormat(argv)
200-
201124
if (argv.version || argv.v) {
202125
return console.log(`v ${require('./package.json').version}`)
203126
}
@@ -227,17 +150,15 @@ function main () {
227150
endRef
228151
}
229152

230-
branchDiff(branch1, branch2, options, (err, list) => {
231-
if (err) { throw err }
232-
233-
if (argv['filter-release']) {
234-
list = list.filter((commit) => !isReleaseCommit(commit.summary))
235-
}
153+
let list = await branchDiff(branch1, branch2, options)
154+
if (argv['filter-release']) {
155+
list = list.filter((commit) => !isReleaseCommit(commit.summary))
156+
}
236157

237-
printCommits(list, format, reverse, commitUrl)
238-
})
158+
await processCommits(argv, ghId, list)
239159
}
240160

241-
if (require.main === module) {
242-
main()
243-
}
161+
main().catch((err) => {
162+
console.error(err)
163+
process.exit(1)
164+
})

package.json

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"version": "1.10.5",
44
"description": "A tool to list print the commits on one git branch that are not on another using loose comparison",
55
"main": "branch-diff.js",
6+
"type": "module",
67
"bin": {
78
"branch-diff": "./branch-diff.js"
89
},
@@ -14,26 +15,20 @@
1415
"author": "Rod <[email protected]> (http://r.va.gg/)",
1516
"license": "MIT",
1617
"dependencies": {
17-
"bl": "^5.0.0",
18-
"changelog-maker": "^2.5.0",
18+
"changelog-maker": "^3.0.0",
1919
"commit-stream": "^1.1.0",
20-
"deep-equal": "^2.0.5",
2120
"gitexec": "^2.0.1",
22-
"list-stream": "^2.0.0",
23-
"map-async": "^0.1.1",
2421
"minimist": "^1.2.5",
25-
"pkg-to-id": "0.0.3",
26-
"split2": "^4.0.0",
27-
"strip-ansi": "^6.0.0",
28-
"through2": "^4.0.2"
22+
"pkg-to-id": "^0.0.3",
23+
"split2": "^4.1.0"
2924
},
3025
"repository": {
3126
"type": "git",
3227
"url": "https://github.com/rvagg/branch-diff.git"
3328
},
3429
"preferGlobal": true,
3530
"devDependencies": {
36-
"standard": "^16.0.3"
31+
"standard": "^16.0.4"
3732
},
3833
"release": {
3934
"branches": [

0 commit comments

Comments
 (0)