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

feat: --find-matching-prs for commits without PR-URL #130

Merged
merged 1 commit into from
Jun 16, 2022
Merged
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ npm i changelog-maker -g

## Usage

**`changelog-maker [--plaintext|p] [--markdown|md] [--sha] [--group|-g] [--reverse] [--commit-url=<url/with/{ref}>] [--start-ref=<ref>] [--end-ref=<ref>] [github-user[, github-project]]`**
**`changelog-maker [--plaintext|p] [--markdown|md] [--sha] [--group|-g] [--reverse] [--find-matching-prs] [--commit-url=<url/with/{ref}>] [--start-ref=<ref>] [--end-ref=<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

Expand All @@ -62,6 +62,7 @@ npm i changelog-maker -g
* `--start-ref=<ref>`: use the given git `<ref>` as a starting point rather than the _last tag_. The `<ref>` 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 <version>` commits are left in the list.
* `--end-ref=<ref>`: use the given git `<ref>` as a end-point rather than the _now_. The `<ref>` can be anything commit-ish including a commit sha, tag, branch name.
* `--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" and also "npm version X" style commits containing _only_ an `x.y.z` semver designator.
* `--find-matching-prs`: use the GitHub API to find the pull requests that match commits that don't have the `PR-URL` metadata in their message text. Without metadata, it may be necessary to also pass the org/user and repo name on the commandline (as the `github-user` and `github-project` arguments as demonstrated above, it may also be necessary to use `--find-matching-prs=true` in this case).
* `--quiet` or `-q`: do not print to `process.stdout`
* `--all` or `-a`: process all commits since beginning, instead of last tag.
* `--help` or `-h`: show usage and help.
Expand Down
12 changes: 12 additions & 0 deletions auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { promisify } from 'util'
import ghauth from 'ghauth'

const authOptions = {
configName: 'changelog-maker',
scopes: ['repo'],
noDeviceFlow: true
}

export async function auth () {
return await promisify(ghauth)(authOptions)
}
11 changes: 2 additions & 9 deletions collect-commit-labels.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
'use strict'

import { promisify } from 'util'
import ghauth from 'ghauth'
import { auth } from './auth.js'
import ghissues from 'ghissues'
import async from 'async'

const authOptions = {
configName: 'changelog-maker',
scopes: ['repo'],
noDeviceFlow: true
}

export async function collectCommitLabels (list) {
const sublist = list.filter((commit) => {
return typeof commit.ghIssue === 'number' && commit.ghUser && commit.ghProject
Expand All @@ -20,7 +13,7 @@ export async function collectCommitLabels (list) {
return
}

const authData = await promisify(ghauth)(authOptions)
const authData = await auth()

const cache = {}

Expand Down
72 changes: 72 additions & 0 deletions find-matching-prs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
'use strict'

import { auth } from './auth.js'
import { graphql } from '@octokit/graphql'
import async from 'async'

// Query to find the first 4 pull requests that include the commit that we're
// concerned about. We'll filter them and take the first one that was MERGED
// as our prUrl.
const query = `
query ($owner: String!, $name: String!, $commit: GitObjectID!) {
repository(owner: $owner, name: $name) {
object(oid: $commit) {
... on Commit {
associatedPullRequests(first: 4) {
... on PullRequestConnection {
edges {
node {
... on PullRequest {
number
url
title
state
}
}
}
}
}
}
}
}
}
`

export async function findMatchingPrs (ghId, list) {
// only look up commits that don't have a prUrl from metadata
const sublist = list.filter((commit) => typeof commit.prUrl !== 'string')
if (!sublist.length) {
return
}

const authData = await auth()
const headers = { authorization: `token ${authData.token}` }
const cache = {}

const q = async.queue(async (commit, next) => {
if (commit.ghUser === 'iojs') {
commit.ghUser = 'nodejs' // forcibly rewrite as the GH API doesn't do it for us
}

// cache on commit, so we don't run the same commit twice (is this possible?)
cache[commit.sha] = cache[commit.sha] || (async () => {
try {
const res = await graphql(query, { owner: ghId.user, name: ghId.repo, commit: commit.sha, headers })
if (res.repository?.object?.associatedPullRequests?.edges?.length) {
const pr = res.repository.object.associatedPullRequests.edges.filter((e) => e.node?.state === 'MERGED')[0]
if (pr) {
commit.ghIssue = pr.node.number
commit.prUrl = pr.node.url
}
}
} catch (err) {
console.error(`Error querying GitHub to find pull request for commit: ${err}`)
}
})()
await cache[commit.sha]
next()
}, 15)

q.push(sublist)
await q.drain()
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"keywords": [],
"preferGlobal": true,
"dependencies": {
"@octokit/graphql": "^4.8.0",
"async": "^3.2.2",
"chalk": "^5.0.0",
"commit-stream": "^1.1.0",
Expand Down
5 changes: 5 additions & 0 deletions process-commits.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { toGroups } from './groups.js'
import { formatMarkdown } from './format.js'
import { supportsColor } from 'chalk'
import { collectCommitLabels } from './collect-commit-labels.js'
import { findMatchingPrs } from './find-matching-prs.js'

function getFormat (argv) {
if (argv.format && Object.values(formatType).includes(argv.format)) {
Expand Down Expand Up @@ -33,6 +34,10 @@ export async function processCommits (argv, ghId, list) {
const reverse = argv.reverse
const commitUrl = argv['commit-url'] || 'https://github.com/{ghUser}/{ghRepo}/commit/{ref}'

if (argv['find-matching-prs']) {
await findMatchingPrs(ghId, list)
}

await collectCommitLabels(list)

const format = getFormat(argv)
Expand Down
8 changes: 8 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,11 @@ test('test markdown punctuation chars in commit message and author name', (t) =>
`)
t.end()
})

test('test find-matching-prs', (t) => {
t.equal(
exec('--start-ref=a059bc7ca9 --end-ref=a059bc7ca9 --find-matching-prs=true nodejs changelog-maker'),
`* [a059bc7ca9] - chore(deps): remove package-lock.json (#118) (Rod Vagg) https://github.com/nodejs/changelog-maker/pull/118
`)
t.end()
})