1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

fix: Switch to using authenticated GitHub API to increase rate limit

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2023-05-23 10:56:27 -04:00
parent 8f4aa497cc
commit aa2cb21aa8
3 changed files with 3421 additions and 60 deletions

3332
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,11 +11,14 @@
}, },
"type": "module", "type": "module",
"devDependencies": { "devDependencies": {
"@octokit/core": "^4.2.1",
"@swc/cli": "^0.1.62", "@swc/cli": "^0.1.62",
"@swc/core": "^1.3.53", "@swc/core": "^1.3.53",
"@types/inquirer": "^9.0.3", "@types/inquirer": "^9.0.3",
"@types/node": "^16.18.25", "@types/node": "^16.18.25",
"@types/semver": "^7.3.13", "@types/semver": "^7.3.13",
"install": "^0.13.0",
"npm": "^9.6.7",
"rimraf": "^4.4.1" "rimraf": "^4.4.1"
}, },
"dependencies": { "dependencies": {

View File

@ -11,6 +11,8 @@ import inquirer from "inquirer";
import { createInterface, ReadLine } from "readline"; import { createInterface, ReadLine } from "readline";
import semver from "semver"; import semver from "semver";
import { promisify } from "util"; import { promisify } from "util";
import { Octokit } from "@octokit/core";
import type { components } from "@octokit/openapi-types";
type SemVer = semver.SemVer; type SemVer = semver.SemVer;
@ -53,26 +55,16 @@ async function pipeExecFile(file: string, args: string[], opts?: { stdin: string
await p; await p;
} }
const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN || (await execFile("gh", ["auth", "token"])).stdout.trim(),
});
interface GithubPrData { interface GithubPrData {
author: { authorLogin: string | undefined;
login: string; labels: components["schemas"]["label"][];
}; mergeCommitSha: string;
labels: {
id: string;
name: string;
description: string;
color: string;
}[];
mergeCommit: {
oid: string;
};
mergedAt: string; mergedAt: string;
milestone: { milestone: components["schemas"]["milestone"];
number: number;
title: string;
description: string;
dueOn: null | string;
};
number: number; number: number;
title: string; title: string;
} }
@ -173,23 +165,29 @@ function formatVersionForPickingPrs(version: SemVer): string {
} }
async function deleteAndClosePreviousReleaseBranch(prBase: string, prBranch: string) { async function deleteAndClosePreviousReleaseBranch(prBase: string, prBranch: string) {
try { const pullRequests = await octokit.request("GET /repos/{owner}/{repo}/pulls", {
await pipeExecFile("gh", [ owner: "lensapp",
"pr", repo: "lens",
"view", headers: {
prBranch, 'X-GitHub-Api-Version': '2022-11-28'
"--json", },
"number", });
]);
} catch { const previousReleasePR = pullRequests.data.find(pr => pr.base.ref === prBase && pr.head.ref === prBranch);
if (!previousReleasePR) {
return; return;
} }
await pipeExecFile("gh", [ await octokit.request("PATCH /repos/{owner}/{repo}/pulls/{pull_number}", {
"pr", owner: "lensapp",
"close", repo: "lens",
prBranch, pull_number: previousReleasePR.number,
]); state: "closed",
headers: {
'X-GitHub-Api-Version': '2022-11-28'
},
});
await pipeExecFile("git", [ await pipeExecFile("git", [
"push", "push",
@ -220,17 +218,36 @@ async function createReleaseBranchAndCommit(prBase: string, version: SemVer, prB
await pipeExecFile("git", ["push", "--set-upstream", "origin", prBranch]); await pipeExecFile("git", ["push", "--set-upstream", "origin", prBranch]);
await pipeExecFile("gh", [ const newReleasePR = await octokit.request("POST /repos/{owner}/{repo}/pulls", {
"pr", owner: "lensapp",
"create", repo: "lens",
"--base", prBase, title: `Release ${version.format()}`,
"--title", `Release ${version.format()}`, head: prBranch,
"--label", "skip-changelog", base: prBase,
"--label", "release", body: prBody,
"--milestone", formatSemverForMilestone(version), draft: false,
"--body-file", "-", maintainer_can_modify: true,
], { headers: {
stdin: prBody, 'X-GitHub-Api-Version': '2022-11-28'
},
});
await octokit.request("POST /repos/{owner}/{repo}/issues/{issue_number}/labels", {
owner: "lensapp",
repo: "lens",
issue_number: newReleasePR.data.number,
labels: ["release", "skip-changelog"],
headers: {
'X-GitHub-Api-Version': '2022-11-28'
},
});
await octokit.request("POST /repos/{owner}/{repo}/issues/{issue_number}/milestone", {
owner: "lensapp",
repo: "lens",
issue_number: newReleasePR.data.number,
milestone: formatSemverForMilestone(version),
headers: {
'X-GitHub-Api-Version': '2022-11-28'
},
}); });
} }
@ -253,22 +270,26 @@ async function getRelevantPRs(previousReleasedVersion: string, baseBranch: strin
console.log(`retrieving previous 200 PRs from ${baseBranch}...`); console.log(`retrieving previous 200 PRs from ${baseBranch}...`);
const milestone = formatVersionForPickingPrs(await getCurrentVersionOfSubPackage("core")); const milestone = formatVersionForPickingPrs(await getCurrentVersionOfSubPackage("core"));
const getMergedPrsArgs = [ const mergedPrsDataPromises = [1, 2, 3, 4, 5].map(page => octokit.request("GET /repos/{owner}/{repo}/pulls", {
"gh", owner: "lensapp",
"pr", repo: "lens",
"list", headers: {
"--limit=500", // Should be big enough, if not we need to release more often ;) 'X-GitHub-Api-Version': '2022-11-28'
"--state=merged", },
`--base=${baseBranch}`, state: "closed",
"--json mergeCommit,title,author,labels,number,milestone,mergedAt", base: baseBranch,
]; per_page: 100,
page,
}));
const milestoneRelevantPrs = (await Promise.all(mergedPrsDataPromises))
.flatMap(response => response.data)
.filter(pr => pr.milestone?.title === milestone)
.filter(pr => (pr.merged_at !== null && pr.merge_commit_sha !== null));
const mergedPrs = JSON.parse((await exec(getMergedPrsArgs.join(" "), { encoding: "utf-8" })).stdout) as GithubPrData[];
const milestoneRelevantPrs = mergedPrs.filter(pr => pr.milestone?.title === milestone);
const relevantPrsQuery = await Promise.all( const relevantPrsQuery = await Promise.all(
milestoneRelevantPrs.map(async pr => ({ milestoneRelevantPrs.map(async pr => ({
pr, pr,
stdout: (await exec(`git tag v${previousReleasedVersion} --no-contains ${pr.mergeCommit.oid}`)).stdout, stdout: (await exec(`git tag v${previousReleasedVersion} --no-contains ${pr.merge_commit_sha}`)).stdout,
})), })),
); );
@ -276,16 +297,21 @@ async function getRelevantPRs(previousReleasedVersion: string, baseBranch: strin
.filter(query => query.stdout) .filter(query => query.stdout)
.map(query => query.pr) .map(query => query.pr)
.filter(pr => pr.labels.every(label => label.name !== "skip-changelog")) .filter(pr => pr.labels.every(label => label.name !== "skip-changelog"))
.map(pr => ({ .map((pr): ExtendedGithubPrData => ({
...pr, authorLogin: pr.user?.login,
mergedAt: new Date(pr.mergedAt), labels: pr.labels,
mergeCommitSha: pr.merge_commit_sha as string,
number: pr.number,
title: pr.title,
milestone: pr.milestone as components["schemas"]["milestone"],
mergedAt: new Date(pr.merged_at as string),
shouldAttemptCherryPick: baseBranch === "master", shouldAttemptCherryPick: baseBranch === "master",
})) }))
.sort(sortExtendedGithubPrData); .sort(sortExtendedGithubPrData);
} }
function formatPrEntry(pr: ExtendedGithubPrData) { function formatPrEntry(pr: ExtendedGithubPrData) {
return `- ${pr.title} (**[#${pr.number}](https://github.com/lensapp/lens/pull/${pr.number})**) https://github.com/${pr.author.login}`; return `- ${pr.title} (**[#${pr.number}](https://github.com/lensapp/lens/pull/${pr.number})**) https://github.com/${pr.authorLogin}`;
} }
const isEnhancementPr = (pr: ExtendedGithubPrData) => pr.labels.some(label => label.name === "enhancement"); const isEnhancementPr = (pr: ExtendedGithubPrData) => pr.labels.some(label => label.name === "enhancement");
@ -364,7 +390,7 @@ async function cherryPickCommits(prs: ExtendedGithubPrData[]): Promise<void> {
for (const pr of prs) { for (const pr of prs) {
if (pr.shouldAttemptCherryPick) { if (pr.shouldAttemptCherryPick) {
await cherryPickCommit(pr.mergeCommit.oid); await cherryPickCommit(pr.mergeCommitSha);
} else { } else {
console.log(`Skipping cherry picking of #${pr.number} - ${pr.title}`); console.log(`Skipping cherry picking of #${pr.number} - ${pr.title}`);
} }