storybook/scripts/release/label-patches.ts
2024-10-02 17:07:43 +02:00

106 lines
3.3 KiB
TypeScript

import { program } from 'commander';
// eslint-disable-next-line depend/ban-dependencies
import ora from 'ora';
import { v4 as uuidv4 } from 'uuid';
import { esMain } from '../utils/esmain';
import { getPullInfoFromCommits, getRepo } from './utils/get-changes';
import { getLatestTag, git } from './utils/git-client';
import { getLabelIds, getUnpickedPRs, githubGraphQlClient } from './utils/github-client';
program
.name('label-patches')
.description('Label all patches applied in current branch up to the latest release tag.')
.option(
'-A, --all',
'Label all pull requests pending patches, iregardless if they are in the git log or not',
false
);
async function labelPR(id: string, labelId: string) {
await githubGraphQlClient(
`
mutation ($input: AddLabelsToLabelableInput!) {
addLabelsToLabelable(input: $input) {
clientMutationId
}
}
`,
{ input: { labelIds: [labelId], labelableId: id, clientMutationId: uuidv4() } }
);
}
async function getPullRequestsFromLog({ repo }: { repo: string }) {
const spinner = ora('Looking for latest tag').start();
const latestTag = await getLatestTag();
spinner.succeed(`Found latest tag: ${latestTag}`);
const spinner2 = ora(`Looking at cherry pick commits since ${latestTag}`).start();
const commitsSinceLatest = await git.log({ from: latestTag });
console.log(commitsSinceLatest);
const cherryPicked = commitsSinceLatest.all.flatMap((it) => {
const result = it.body.match(/\(cherry picked from commit (\b[0-9a-f]{7,40}\b)\)/);
return result ? [result?.[1]] : [];
});
if (cherryPicked.length === 0) {
spinner2.fail('No cherry pick commits found to label.');
return [];
}
const pullRequests = (
await getPullInfoFromCommits({
repo,
commits: cherryPicked.map((hash) => ({ hash })),
})
).filter((it) => it.id != null);
if (pullRequests.length === 0) {
spinner2.fail(
`Found picks: ${cherryPicked.join(', ')}, but no associated pull request found to label.`
);
return pullRequests;
}
const commitWithPr = pullRequests.map((pr) => `Commit: ${pr.commit}\n PR: ${pr.links.pull}`);
spinner2.succeed(`Found the following picks 🍒:\n ${commitWithPr.join('\n')}`);
return pullRequests;
}
export const run = async (options: unknown) => {
if (!process.env.GH_TOKEN) {
throw new Error('GH_TOKEN environment variable must be set, exiting.');
}
const repo = await getRepo();
const labelAll = typeof options === 'object' && 'all' in options && Boolean(options.all);
const pullRequestsToLabel = labelAll
? await getUnpickedPRs('next')
: await getPullRequestsFromLog({ repo });
if (pullRequestsToLabel.length === 0) {
return;
}
const spinner3 = ora(
`Labeling ${pullRequestsToLabel.length} PRs with the patch:done label...`
).start();
try {
const labelToId = await getLabelIds({ repo, labelNames: ['patch:done'] });
await Promise.all(pullRequestsToLabel.map((pr) => labelPR(pr.id, labelToId['patch:done'])));
spinner3.succeed(`Successfully labeled all PRs with the patch:done label.`);
} catch (e) {
spinner3.fail(`Something went wrong when labelling the PRs.`);
console.error(e);
}
};
if (esMain(import.meta.url)) {
const options = program.parse().opts();
run(options).catch((err) => {
console.error(err);
process.exit(1);
});
}