mirror of
https://github.com/storybookjs/storybook.git
synced 2025-03-26 05:02:32 +08:00
119 lines
3.2 KiB
TypeScript
119 lines
3.2 KiB
TypeScript
/* eslint-disable no-restricted-syntax, no-await-in-loop */
|
|
import { Command } from 'commander';
|
|
import execa from 'execa';
|
|
|
|
import {
|
|
getOptions,
|
|
getCommand,
|
|
getOptionsOrPrompt,
|
|
createOptions,
|
|
OptionValues,
|
|
} from './utils/options';
|
|
import type { OptionSpecifier } from './utils/options';
|
|
import { filterDataForCurrentCircleCINode } from './utils/concurrency';
|
|
|
|
import TEMPLATES from '../code/lib/cli/src/repro-templates';
|
|
|
|
export type Cadence = 'ci' | 'daily' | 'weekly';
|
|
export type Template = {
|
|
name: string;
|
|
script: string;
|
|
cadence?: readonly Cadence[];
|
|
skipScripts?: string[];
|
|
// there are other fields but we don't use them here
|
|
};
|
|
export type TemplateKey = string;
|
|
export type Templates = Record<TemplateKey, Template>;
|
|
|
|
export async function parseCommand(commandline: string) {
|
|
const argv = commandline.split(' ');
|
|
|
|
const [yarn, scriptName] = argv;
|
|
if (yarn !== 'yarn') throw new Error('only works with scripts at this point');
|
|
|
|
const { options } = await import(`./${scriptName}`);
|
|
|
|
const command = new Command(scriptName);
|
|
const values = getOptions(command, options as OptionSpecifier, ['yarn', ...argv]);
|
|
|
|
return {
|
|
scriptName,
|
|
command: `yarn ${scriptName}`,
|
|
options,
|
|
values,
|
|
};
|
|
}
|
|
|
|
export const options = createOptions({
|
|
cadence: {
|
|
type: 'string',
|
|
description: 'What cadence are we running on (i.e. which templates should we use)?',
|
|
values: ['ci', 'daily', 'weekly'] as const,
|
|
required: true,
|
|
},
|
|
script: {
|
|
type: 'string',
|
|
description: 'What command are we running?',
|
|
},
|
|
parallel: {
|
|
type: 'boolean',
|
|
description: 'Run commands in parallel?',
|
|
},
|
|
});
|
|
|
|
export function filterTemplates(templates: Templates, cadence: Cadence, scriptName: string) {
|
|
const allTemplates = Object.entries(templates);
|
|
const cadenceTemplates = allTemplates.filter(([, template]) =>
|
|
template.cadence.includes(cadence)
|
|
);
|
|
const jobTemplates = cadenceTemplates.filter(([, t]) => !t.skipScripts?.includes(scriptName));
|
|
return Object.fromEntries(filterDataForCurrentCircleCINode(jobTemplates));
|
|
}
|
|
|
|
const logger = console;
|
|
export async function oncePerTemplate({
|
|
cadence,
|
|
script: commandline,
|
|
parallel,
|
|
}: OptionValues<typeof options>) {
|
|
const command = await parseCommand(commandline);
|
|
const templates = filterTemplates(TEMPLATES, cadence, command.scriptName);
|
|
|
|
const toAwait = [];
|
|
for (const template of Object.keys(templates)) {
|
|
const toRun = getCommand(command.command, command.options, {
|
|
...command.values,
|
|
template,
|
|
});
|
|
|
|
logger.log(`🏃 Running ${toRun}`);
|
|
|
|
if (parallel) {
|
|
// Don't pipe stdio as it'll get interleaved
|
|
toAwait.push(
|
|
(async () => {
|
|
await execa.command(toRun);
|
|
logger.log(`✅ Done with ${toRun}`);
|
|
})()
|
|
);
|
|
} else {
|
|
await execa.command(toRun, { stdio: 'inherit' });
|
|
}
|
|
}
|
|
|
|
await Promise.all(toAwait);
|
|
}
|
|
|
|
async function run() {
|
|
const optionValues = await getOptionsOrPrompt('yarn once-per-template', options);
|
|
return oncePerTemplate(optionValues);
|
|
}
|
|
|
|
if (require.main === module) {
|
|
run().catch((err) => {
|
|
logger.error('🚨 An error occurred when executing "once-per-template":');
|
|
logger.error(err);
|
|
process.exit(1);
|
|
});
|
|
}
|