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

95 lines
2.7 KiB
TypeScript

import { setOutput } from '@actions/core';
import { program } from 'commander';
// eslint-disable-next-line depend/ban-dependencies
import ora from 'ora';
import picocolors from 'picocolors';
import invariant from 'tiny-invariant';
import { esMain } from '../utils/esmain';
import { git } from './utils/git-client';
import { getUnpickedPRs } from './utils/github-client';
program.name('pick-patches').description('Cherry pick patch PRs back to main');
const logger = console;
const OWNER = 'storybookjs';
const REPO = 'storybook';
const SOURCE_BRANCH = 'next';
interface PR {
number: number;
id: string;
branch: string;
title: string;
mergeCommit: string;
}
function formatPR(pr: PR): string {
return `https://github.com/${OWNER}/${REPO}/pull/${pr.number} "${pr.title}" ${picocolors.yellow(
pr.mergeCommit
)}`;
}
export const run = async (_: unknown) => {
if (!process.env.GH_TOKEN) {
logger.error('GH_TOKEN environment variable must be set, exiting.');
process.exit(1);
}
const sourceBranch = SOURCE_BRANCH;
const spinner = ora('Searching for patch PRs to cherry-pick').start();
const patchPRs = await getUnpickedPRs(sourceBranch);
if (patchPRs.length > 0) {
spinner.succeed(`Found ${patchPRs.length} PRs to cherry-pick to main.`);
} else {
spinner.warn('No PRs found.');
}
const failedCherryPicks: string[] = [];
for (const pr of patchPRs) {
const prSpinner = ora(`Cherry picking #${pr.number}`).start();
try {
await git.raw(['cherry-pick', '-m', '1', '--keep-redundant-commits', '-x', pr.mergeCommit]);
prSpinner.succeed(`Picked: ${formatPR(pr)}`);
} catch (pickError) {
invariant(pickError instanceof Error);
prSpinner.fail(`Failed to automatically pick: ${formatPR(pr)}`);
logger.error(pickError.message);
const abort = ora(`Aborting cherry pick for merge commit: ${pr.mergeCommit}`).start();
try {
await git.raw(['cherry-pick', '--abort']);
abort.stop();
} catch (abortError) {
invariant(abortError instanceof Error);
abort.warn(`Failed to abort cherry pick (${pr.mergeCommit})`);
logger.error(abortError.message);
}
failedCherryPicks.push(pr.mergeCommit);
prSpinner.info(
`This PR can be picked manually with: ${picocolors.gray(
`git cherry-pick -m1 -x ${pr.mergeCommit}`
)}`
);
}
}
if (process.env.GITHUB_ACTIONS === 'true') {
setOutput('no-patch-prs', patchPRs.length === 0);
setOutput('failed-cherry-picks', JSON.stringify(failedCherryPicks));
}
};
if (esMain(import.meta.url)) {
const options = program.parse(process.argv);
run(options).catch((err) => {
console.error(err);
process.exit(1);
});
}