Skip to content

Commit

Permalink
feat!: switch to ESM, dedupe more code w/ changelog-maker
Browse files Browse the repository at this point in the history
Also remove Node.js v12 support

Ref: nodejs/changelog-maker#121
  • Loading branch information
rvagg committed Jan 18, 2022
1 parent 95db90c commit df17633
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 154 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-and-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

## Usage

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

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

Expand All @@ -29,12 +29,16 @@ But the comparison isn't quite as strict, generally leading to a shorter list of
* `--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`.
* `--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`.
* `--patch-only`: An alias for `--exclude-label=semver-major,semver-minor`.
* `--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.
* `--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 shasums. Good for piping though additional tooling, such as `xargs git cherry-pick` for applying commits.
* `--simple` or `-s`: An alias for `--format=simple`.
- `sha`: Print only the 10-character truncated commit hashes. Good for piping though additional tooling, such as `xargs git cherry-pick` for applying commits.
- `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`.
* `--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`.
* `--reverse`: Reverse the results, this is especially useful when piping output to `xargs`
* `--reverse`: Reverse the results, this is especially useful when piping output to `xargs`.
* `--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).

## License
Expand Down
197 changes: 59 additions & 138 deletions branch-diff.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
#!/usr/bin/env node

'use strict'

const fs = require('fs')
const path = require('path')
const commitStream = require('commit-stream')
const split2 = require('split2')
const listStream = require('list-stream')
const pkgtoId = require('pkg-to-id')
const stripAnsi = require('strip-ansi')
const map = require('map-async')
const { commitToOutput } = require('changelog-maker/commit-to-output')
const collectCommitLabels = require('changelog-maker/collect-commit-labels')
const groupCommits = require('changelog-maker/group-commits')
const { isReleaseCommit, toGroups } = require('changelog-maker/groups')
const gitexec = require('gitexec')

import fs from 'fs'
import path from 'path'
import process from 'process'
import { pipeline as _pipeline } from 'stream'
import { promisify } from 'util'
import commitStream from 'commit-stream'
import split2 from 'split2'
import pkgtoId from 'pkg-to-id'
import minimist from 'minimist'
import { isReleaseCommit } from 'changelog-maker/groups'
import { processCommits } from 'changelog-maker/process-commits'
import gitexec from 'gitexec'

const pipeline = promisify(_pipeline)
const pkgFile = path.join(process.cwd(), 'package.json')
const pkgData = fs.existsSync(pkgFile) ? require(pkgFile) : {}
const pkgId = pkgtoId(pkgData)
Expand All @@ -26,23 +24,6 @@ const ghId = {
user: pkgId.user || 'nodejs',
repo: pkgId.name || 'node'
}
const defaultCommitUrl = 'https://github.com/{ghUser}/{ghRepo}/commit/{ref}'

const formatType = {
PLAINTEXT: 'plaintext',
MARKDOWN: 'markdown',
SIMPLE: 'simple',
SHA: 'sha'
}

const getFormat = (argv) => {
if (argv.format && Object.values(formatType).includes(argv.format)) {
return argv.format
} else if (argv.simple || argv.s) {
return formatType.SIMPLE
}
return formatType.MARKDOWN
}

function replace (s, m) {
Object.keys(m).forEach(function (k) {
Expand All @@ -51,37 +32,26 @@ function replace (s, m) {
return s
}

function branchDiff (branch1, branch2, options, callback) {
export async function branchDiff (branch1, branch2, options) {
if (!branch1 || !branch2) {
return callback(new Error('Must supply two branch names to compare'))
throw new Error('Must supply two branch names to compare')
}

const repoPath = options.repoPath || process.cwd()

findMergeBase(repoPath, branch1, branch2, (err, commit) => {
if (err) { return callback(err) }
map(
[branch1, branch2], (branch, callback) => {
collect(repoPath, branch, commit, branch === branch2 && options.endRef).pipe(listStream.obj(callback))
}
, (err, branchCommits) => err ? callback(err) : diffCollected(options, branchCommits, callback)
)
})
const commit = await findMergeBase(repoPath, branch1, branch2)
const branchCommits = await Promise.all([branch1, branch2].map(async (branch) => {
return collect(repoPath, branch, commit, branch === branch2 && options.endRef)
}))
return await diffCollected(options, branchCommits)
}

function findMergeBase (repoPath, branch1, branch2, callback) {
async function findMergeBase (repoPath, branch1, branch2) {
const gitcmd = `git merge-base ${branch1} ${branch2}`

gitexec.execCollect(repoPath, gitcmd, (err, data) => {
if (err) {
return callback(err)
}

callback(null, data.substr(0, 10))
})
const data = await promisify(gitexec.execCollect)(repoPath, gitcmd)
return data.substr(0, 10)
}

function diffCollected (options, branchCommits, callback) {
async function diffCollected (options, branchCommits) {
function isInList (commit) {
return branchCommits[0].some((c) => {
if (commit.sha === c.sha) { return true }
Expand All @@ -102,102 +72,55 @@ function diffCollected (options, branchCommits, callback) {

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

collectCommitLabels(list, (err) => {
if (err) {
return callback(err)
}

if (options.excludeLabels.length > 0) {
list = list.filter((commit) => {
return !commit.labels || !commit.labels.some((label) => {
return options.excludeLabels.indexOf(label) >= 0
})
})
}

if (options.requireLabels.length > 0) {
list = list.filter((commit) => {
return commit.labels && commit.labels.some((label) => {
return options.requireLabels.indexOf(label) >= 0
})
if (options.excludeLabels.length > 0) {
list = list.filter((commit) => {
return !commit.labels || !commit.labels.some((label) => {
return options.excludeLabels.indexOf(label) >= 0
})
}

if (options.group) {
list = groupCommits(list)
}

callback(null, list)
})
}

function printCommits (list, format, reverse, commitUrl) {
if (format === formatType.SHA) {
list = list.map((commit) => `${commit.sha.substr(0, 10)}`)
} else if (format === formatType.SIMPLE) {
list = list.map((commit) => commitToOutput(commit, formatType.SIMPLE, ghId, commitUrl))
} else if (format === formatType.PLAINTEXT) {
// Plaintext format implies grouping.
list = groupCommits(list)

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 = list.map((commit) => {
return commitToOutput(commit, formatType.MARKDOWN, ghId, commitUrl)
})
}

if (reverse) {
list = list.reverse()
}

let out = list.join('\n') + '\n'

if (!process.stdout.isTTY) {
out = stripAnsi(out)
if (options.requireLabels.length > 0) {
list = list.filter((commit) => {
return commit.labels && commit.labels.some((label) => {
return options.requireLabels.indexOf(label) >= 0
})
})
}

process.stdout.write(out)
return list
}

function collect (repoPath, branch, startCommit, endRef) {
async function collect (repoPath, branch, startCommit, endRef) {
const endrefcmd = endRef && replace(refcmd, { ref: endRef })
const untilcmd = endRef ? replace(commitdatecmd, { refcmd: endrefcmd }) : ''
const _gitcmd = replace(gitcmd, { branch, startCommit, untilcmd })

return gitexec.exec(repoPath, _gitcmd)
.pipe(split2())
.pipe(commitStream(ghId.user, ghId.repo))
const commitList = []
await pipeline(
gitexec.exec(repoPath, _gitcmd),
split2(),
commitStream(ghId.user, ghId.repo),
async function * (source) {
for await (const commit of source) {
commitList.push(commit)
}
})
return commitList
}

module.exports = branchDiff

function main () {
async function main () {
const minimistConfig = {
boolean: ['version', 'group', 'patch-only', 'simple', 'filter-release', 'reverse']
}
const argv = require('minimist')(process.argv.slice(2), minimistConfig)
const argv = minimist(process.argv.slice(2), minimistConfig)
const branch1 = argv._[0]
const branch2 = argv._[1]
const reverse = argv.reverse
const group = argv.group || argv.g
const endRef = argv['end-ref']
const commitUrl = argv['commit-url'] || defaultCommitUrl
let excludeLabels = []
let requireLabels = []

const format = getFormat(argv)

if (argv.version || argv.v) {
return console.log(`v ${require('./package.json').version}`)
}
Expand Down Expand Up @@ -227,17 +150,15 @@ function main () {
endRef
}

branchDiff(branch1, branch2, options, (err, list) => {
if (err) { throw err }

if (argv['filter-release']) {
list = list.filter((commit) => !isReleaseCommit(commit.summary))
}
let list = await branchDiff(branch1, branch2, options)
if (argv['filter-release']) {
list = list.filter((commit) => !isReleaseCommit(commit.summary))
}

printCommits(list, format, reverse, commitUrl)
})
await processCommits(argv, ghId, list)
}

if (require.main === module) {
main()
}
main().catch((err) => {
console.error(err)
process.exit(1)
})
15 changes: 5 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "1.10.5",
"description": "A tool to list print the commits on one git branch that are not on another using loose comparison",
"main": "branch-diff.js",
"type": "module",
"bin": {
"branch-diff": "./branch-diff.js"
},
Expand All @@ -14,26 +15,20 @@
"author": "Rod <rod@vagg.org> (http://r.va.gg/)",
"license": "MIT",
"dependencies": {
"bl": "^5.0.0",
"changelog-maker": "^2.5.0",
"changelog-maker": "^3.0.0",
"commit-stream": "^1.1.0",
"deep-equal": "^2.0.5",
"gitexec": "^2.0.1",
"list-stream": "^2.0.0",
"map-async": "^0.1.1",
"minimist": "^1.2.5",
"pkg-to-id": "0.0.3",
"split2": "^4.0.0",
"strip-ansi": "^6.0.0",
"through2": "^4.0.2"
"pkg-to-id": "^0.0.3",
"split2": "^4.1.0"
},
"repository": {
"type": "git",
"url": "https://github.com/rvagg/branch-diff.git"
},
"preferGlobal": true,
"devDependencies": {
"standard": "^16.0.3"
"standard": "^16.0.4"
},
"release": {
"branches": [
Expand Down

0 comments on commit df17633

Please sign in to comment.