Skip to content

Commit 8c921c7

Browse files
committed
gen-changelog: add support for rebased PRs
1 parent bf210fb commit 8c921c7

File tree

1 file changed

+77
-43
lines changed

1 file changed

+77
-43
lines changed

resources/gen-changelog.js

Lines changed: 77 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -73,22 +73,35 @@ function getChangeLog() {
7373
}
7474

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

81-
function genChangeLog(tag, date, commitsInfo) {
82-
const allPRs = commitsInfoToPRs(commitsInfo);
81+
function genChangeLog(tag, date, allPRs) {
8382
const byLabel = {};
8483
const commitersByLogin = {};
8584

8685
for (const pr of allPRs) {
87-
if (!labelsConfig[pr.label]) {
88-
throw new Error('Unknown label: ' + pr.label + pr.number);
86+
const labels = pr.labels.nodes
87+
.map(label => label.name)
88+
.filter(label => label.startsWith('PR: '));
89+
90+
if (labels.length === 0) {
91+
throw new Error(`PR #${pr.number} missing label`);
8992
}
90-
byLabel[pr.label] = byLabel[pr.label] || [];
91-
byLabel[pr.label].push(pr);
93+
if (labels.length > 1) {
94+
throw new Error(
95+
`PR #${pr.number} has conflicting labels: ` + labels.join('\n'),
96+
);
97+
}
98+
99+
const label = labels[0];
100+
if (!labelsConfig[label]) {
101+
throw new Error('Unknown label: ' + label + pr.number);
102+
}
103+
byLabel[label] = byLabel[label] || [];
104+
byLabel[label].push(pr);
92105
commitersByLogin[pr.author.login] = pr.author;
93106
}
94107

@@ -188,23 +201,9 @@ async function batchCommitInfo(commits) {
188201
associatedPullRequests(first: 10) {
189202
nodes {
190203
number
191-
title
192-
url
193-
author {
194-
login
195-
url
196-
... on User {
197-
name
198-
}
199-
}
200204
repository {
201205
nameWithOwner
202206
}
203-
labels(first: 10) {
204-
nodes {
205-
name
206-
}
207-
}
208207
}
209208
}
210209
}
@@ -227,13 +226,57 @@ async function batchCommitInfo(commits) {
227226
return commitsInfo;
228227
}
229228

229+
async function batchPRInfo(prs) {
230+
let prsSubQuery = '';
231+
for (const number of prs) {
232+
prsSubQuery += `
233+
pr_${number}: pullRequest(number: ${number}) {
234+
number
235+
title
236+
url
237+
author {
238+
login
239+
url
240+
... on User {
241+
name
242+
}
243+
}
244+
labels(first: 10) {
245+
nodes {
246+
name
247+
}
248+
}
249+
}
250+
`;
251+
}
252+
253+
const response = await graphqlRequest(`
254+
{
255+
repository(owner: "${githubOrg}", name: "${githubRepo}") {
256+
${prsSubQuery}
257+
}
258+
}
259+
`);
260+
261+
const prsInfo = [];
262+
for (const number of prs) {
263+
prsInfo.push(response.repository['pr_' + number]);
264+
}
265+
return prsInfo;
266+
}
267+
230268
function commitsInfoToPRs(commits) {
231269
const prs = {};
232270
for (const commit of commits) {
233271
const associatedPRs = commit.associatedPullRequests.nodes.filter(
234272
pr => pr.repository.nameWithOwner === `${githubOrg}/${githubRepo}`,
235273
);
236274
if (associatedPRs.length === 0) {
275+
const match = / \(#([0-9]+)\)$/m.exec(commit.message);
276+
if (match) {
277+
prs[parseInt(match[1])] = true;
278+
continue;
279+
}
237280
throw new Error(
238281
`Commit ${commit.oid} has no associated PR: ${commit.message}`,
239282
);
@@ -244,30 +287,21 @@ function commitsInfoToPRs(commits) {
244287
);
245288
}
246289

247-
const pr = associatedPRs[0];
248-
const labels = pr.labels.nodes
249-
.map(label => label.name)
250-
.filter(label => label.startsWith('PR: '));
290+
prs[associatedPRs[0].number] = true;
291+
}
251292

252-
if (labels.length === 0) {
253-
throw new Error(`PR #${pr.number} missing label`);
254-
}
255-
if (labels.length > 1) {
256-
throw new Error(
257-
`PR #${pr.number} has conflicting labels: ` + labels.join('\n'),
258-
);
259-
}
293+
return Object.keys(prs);
294+
}
260295

261-
prs[pr.number] = {
262-
number: pr.number,
263-
title: pr.title,
264-
url: pr.url,
265-
author: pr.author,
266-
label: labels[0],
267-
};
296+
async function getPRsInfo(commits) {
297+
// Split pr into batches of 50 to prevent timeouts
298+
const prInfoPromises = [];
299+
for (let i = 0; i < commits.length; i += 50) {
300+
const batch = commits.slice(i, i + 50);
301+
prInfoPromises.push(batchPRInfo(batch));
268302
}
269303

270-
return Object.values(prs);
304+
return (await Promise.all(prInfoPromises)).flat();
271305
}
272306

273307
async function getCommitsInfo(commits) {

0 commit comments

Comments
 (0)