Skip to content

Commit

Permalink
gen-changelog: add support for rebased PRs (#2220)
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanGoncharov authored Oct 15, 2019
1 parent bf210fb commit 2ffa10a
Showing 1 changed file with 80 additions and 46 deletions.
126 changes: 80 additions & 46 deletions resources/gen-changelog.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ if (!packageJSON.repository || typeof packageJSON.repository.url !== 'string') {
process.exit(1);
}

const match = /https:\/\/github.com\/([^/]+)\/([^/]+).git/.exec(
const repoURLMatch = /https:\/\/github.com\/([^/]+)\/([^/]+).git/.exec(
packageJSON.repository.url,
);
if (match == null) {
if (repoURLMatch == null) {
console.error('Cannot extract organisation and repo name from repo URL!');
process.exit(1);
}
const [, githubOrg, githubRepo] = match;
const [, githubOrg, githubRepo] = repoURLMatch;

getChangeLog()
.then(changelog => process.stdout.write(changelog))
Expand All @@ -73,22 +73,35 @@ function getChangeLog() {
}

const date = exec('git log -1 --format=%cd --date=short');
return getCommitsInfo(commitsList.split('\n')).then(commitsInfo =>
genChangeLog(tag, date, commitsInfo),
);
return getCommitsInfo(commitsList.split('\n'))
.then(commitsInfo => getPRsInfo(commitsInfoToPRs(commitsInfo)))
.then(prsInfo => genChangeLog(tag, date, prsInfo));
}

function genChangeLog(tag, date, commitsInfo) {
const allPRs = commitsInfoToPRs(commitsInfo);
function genChangeLog(tag, date, allPRs) {
const byLabel = {};
const commitersByLogin = {};

for (const pr of allPRs) {
if (!labelsConfig[pr.label]) {
throw new Error('Unknown label: ' + pr.label + pr.number);
const labels = pr.labels.nodes
.map(label => label.name)
.filter(label => label.startsWith('PR: '));

if (labels.length === 0) {
throw new Error(`PR #${pr.number} missing label`);
}
byLabel[pr.label] = byLabel[pr.label] || [];
byLabel[pr.label].push(pr);
if (labels.length > 1) {
throw new Error(
`PR #${pr.number} has conflicting labels: ` + labels.join('\n'),
);
}

const label = labels[0];
if (!labelsConfig[label]) {
throw new Error('Unknown label: ' + label + pr.number);
}
byLabel[label] = byLabel[label] || [];
byLabel[label].push(pr);
commitersByLogin[pr.author.login] = pr.author;
}

Expand Down Expand Up @@ -188,23 +201,9 @@ async function batchCommitInfo(commits) {
associatedPullRequests(first: 10) {
nodes {
number
title
url
author {
login
url
... on User {
name
}
}
repository {
nameWithOwner
}
labels(first: 10) {
nodes {
name
}
}
}
}
}
Expand All @@ -227,13 +226,57 @@ async function batchCommitInfo(commits) {
return commitsInfo;
}

async function batchPRInfo(prs) {
let prsSubQuery = '';
for (const number of prs) {
prsSubQuery += `
pr_${number}: pullRequest(number: ${number}) {
number
title
url
author {
login
url
... on User {
name
}
}
labels(first: 10) {
nodes {
name
}
}
}
`;
}

const response = await graphqlRequest(`
{
repository(owner: "${githubOrg}", name: "${githubRepo}") {
${prsSubQuery}
}
}
`);

const prsInfo = [];
for (const number of prs) {
prsInfo.push(response.repository['pr_' + number]);
}
return prsInfo;
}

function commitsInfoToPRs(commits) {
const prs = {};
for (const commit of commits) {
const associatedPRs = commit.associatedPullRequests.nodes.filter(
pr => pr.repository.nameWithOwner === `${githubOrg}/${githubRepo}`,
);
if (associatedPRs.length === 0) {
const match = / \(#([0-9]+)\)$/m.exec(commit.message);
if (match) {
prs[parseInt(match[1], 10)] = true;
continue;
}
throw new Error(
`Commit ${commit.oid} has no associated PR: ${commit.message}`,
);
Expand All @@ -244,30 +287,21 @@ function commitsInfoToPRs(commits) {
);
}

const pr = associatedPRs[0];
const labels = pr.labels.nodes
.map(label => label.name)
.filter(label => label.startsWith('PR: '));
prs[associatedPRs[0].number] = true;
}

if (labels.length === 0) {
throw new Error(`PR #${pr.number} missing label`);
}
if (labels.length > 1) {
throw new Error(
`PR #${pr.number} has conflicting labels: ` + labels.join('\n'),
);
}
return Object.keys(prs);
}

prs[pr.number] = {
number: pr.number,
title: pr.title,
url: pr.url,
author: pr.author,
label: labels[0],
};
async function getPRsInfo(commits) {
// Split pr into batches of 50 to prevent timeouts
const prInfoPromises = [];
for (let i = 0; i < commits.length; i += 50) {
const batch = commits.slice(i, i + 50);
prInfoPromises.push(batchPRInfo(batch));
}

return Object.values(prs);
return (await Promise.all(prInfoPromises)).flat();
}

async function getCommitsInfo(commits) {
Expand Down

0 comments on commit 2ffa10a

Please sign in to comment.