import program from 'commander'; import { join } from 'path'; import { existsSync } from 'fs'; import { command } from 'execa'; import * as tempy from 'tempy'; import { copy, emptyDir, readdir, remove, stat, writeFile } from 'fs-extra'; import { getTemplatesData, renderTemplate } from './utils/template'; import { commitAllToGit } from './utils/git'; export const logger = console; const REPROS_DIRECTORY = join(__dirname, '..', '..', 'repros'); interface PublishOptions { remote?: string; push?: boolean; next?: boolean; } const publish = async (options: PublishOptions & { tmpFolder: string }) => { const { next: useNextVersion, remote, push, tmpFolder } = options; const scriptPath = __dirname; const gitBranch = useNextVersion ? 'next' : 'main'; const templatesData = await getTemplatesData(); logger.log(`👯‍♂️ Cloning the repository ${remote} in branch ${gitBranch}`); await command(`git clone ${remote} .`, { cwd: tmpFolder }); await command(`git checkout ${gitBranch}`, { cwd: tmpFolder }); // otherwise old files will stick around and result inconsistent states logger.log(`🗑 Delete existing template dirs from clone`); const files = await Promise.all( ( await readdir(REPROS_DIRECTORY) ).map(async (f) => ({ path: f, stats: await stat(join(REPROS_DIRECTORY, f)) })) ); await Promise.all( files .filter(({ stats, path }) => stats.isDirectory && !path.startsWith('.')) .map(async ({ path }) => emptyDir(join(tmpFolder, path))) ); logger.log(`🚚 Moving template files into the repository`); const templatePath = join(scriptPath, 'templates', 'root.ejs'); const templateData = { data: templatesData, version: gitBranch }; const output = await renderTemplate(templatePath, templateData); await writeFile(join(tmpFolder, 'README.md'), output); logger.log(`🚛 Moving all the repros into the repository`); await copy(REPROS_DIRECTORY, tmpFolder); await commitAllToGit(tmpFolder); logger.info(` 🙌 All the examples were bootstrapped: - in ${tmpFolder} - using the '${gitBranch}' version of Storybook CLI - and committed on the '${gitBranch}' branch of a local Git repository Also all the files in the 'templates' folder were copied at the root of the Git repository. `); if (push) { await command(`git push --set-upstream origin ${gitBranch}`, { cwd: tmpFolder, }); const remoteRepoUrl = `${remote.replace('.git', '')}/tree/${gitBranch}`; logger.info(`🚀 Everything was pushed on ${remoteRepoUrl}`); } else { logger.info(` To publish these examples you just need to: - push the branch: 'git push --set-upstream origin ${gitBranch} `); } }; program .description('Create a reproduction from a set of possible templates') .option('--remote ', 'Choose the remote to push the contents to') .option('--next', 'Whether to use the next version of Storybook CLI', true) .option('--push', 'Whether to push the contents to the remote', false) .option('--force-push', 'Whether to force push the changes into the repros repository', false); program.parse(process.argv); if (!existsSync(REPROS_DIRECTORY)) { throw Error("Can't find repros directory. Did you forget to run generate-repros?"); } const tmpFolder = tempy.directory(); logger.log(`⏱ Created tmp folder: ${tmpFolder}`); const options = program.opts() as PublishOptions; publish({ ...options, tmpFolder }).catch(async (e) => { logger.error(e); if (existsSync(tmpFolder)) { logger.log('🚮 Removing the temporary folder..'); await remove(tmpFolder); } process.exit(1); });