rename repro -> sandbox

This commit is contained in:
Yann Braga 2023-01-12 09:33:55 +01:00
parent ac5c1d22a7
commit fca8f01de9
21 changed files with 97 additions and 51 deletions

View File

@ -19,7 +19,7 @@ body:
attributes:
label: To Reproduce
description: >-
Please create a reproduction by running `npx sb@next repro` and
Please create a reproduction by running `npx sb@next sandbox` and
following the instructions. Read our
[documentation](https://storybook.js.org/docs/react/contribute/how-to-reproduce)
to learn more about creating reproductions.

View File

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
env:
YARN_ENABLE_IMMUTABLE_INSTALLS: false
CLEANUP_REPRO_NODE_MODULES: true
CLEANUP_SANDBOX_NODE_MODULES: true
steps:
- uses: actions/setup-node@v3
with:
@ -35,8 +35,8 @@ jobs:
run: yarn wait-on http://localhost:6001
working-directory: ./code
- name: Generate repros
run: yarn generate-repros --local-registry
run: yarn generate-sandboxes --local-registry
working-directory: ./code
- name: Publish repros to GitHub
run: yarn publish-repros --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT}}@github.com/storybookjs/repro-sandboxes.git --push
- name: Publish sandboxes to GitHub
run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT}}@github.com/storybookjs/sandboxes.git --push
working-directory: ./code

View File

@ -13,7 +13,7 @@ import { add } from './add';
import { migrate } from './migrate';
import { extract } from './extract';
import { upgrade, type UpgradeOptions } from './upgrade';
import { repro } from './repro';
import { sandbox } from './sandbox';
import { link } from './link';
import { automigrate } from './automigrate';
import { generateStorybookBabelConfigInCWD } from './babel-config';
@ -141,13 +141,14 @@ program
);
program
.command('repro [filterValue]')
.description('Create a reproduction from a set of possible templates')
.command('sandbox [filterValue]')
.alias('repro') // for retrocompatibility purposes
.description('Create a sandbox from a set of possible templates')
.option('-o --output <outDir>', 'Define an output directory')
.option('-b --branch <branch>', 'Define the branch to download from', 'next')
.option('--no-init', 'Whether to download a template without an initialized Storybook', false)
.action((filterValue, options) =>
repro({ filterValue, ...options }).catch((e) => {
sandbox({ filterValue, ...options }).catch((e) => {
logger.error(e);
process.exit(1);
})

View File

@ -2,7 +2,9 @@ import fse from 'fs-extra';
import path from 'path';
import { sync as spawnSync } from 'cross-spawn';
import { logger } from '@storybook/node-logger';
import { exec } from './repro-generators/scripts';
import shell from 'shelljs';
import chalk from 'chalk';
import type { ExecOptions } from 'shelljs';
interface LinkOptions {
target: string;
@ -10,6 +12,49 @@ interface LinkOptions {
start: boolean;
}
// TODO: Extract this to somewhere else, or use `exec` from a different file that might already have it
export const exec = async (
command: string,
options: ExecOptions = {},
{
startMessage,
errorMessage,
dryRun,
}: { startMessage?: string; errorMessage?: string; dryRun?: boolean } = {}
) => {
if (startMessage) logger.info(startMessage);
if (dryRun) {
logger.info(`\n> ${command}\n`);
return undefined;
}
logger.info(command);
return new Promise((resolve, reject) => {
const defaultOptions: ExecOptions = {
silent: false,
};
const child = shell.exec(command, {
...defaultOptions,
...options,
async: true,
silent: false,
});
child.stderr.pipe(process.stderr);
child.on('exit', (code) => {
if (code === 0) {
resolve(undefined);
} else {
logger.error(chalk.red(`An error occurred while executing: \`${command}\``));
logger.info(errorMessage);
reject(new Error(`command exited with code: ${code}: `));
}
});
});
};
export const link = async ({ target, local, start }: LinkOptions) => {
const storybookDir = process.cwd();
try {
@ -58,12 +103,12 @@ export const link = async ({ target, local, start }: LinkOptions) => {
logger.info(`Installing ${reproName}`);
await exec(`yarn install`, { cwd: reproDir });
// ⚠️ TODO: Fix peer deps in `@storybook/preset-create-react-app`
logger.info(
`Magic stuff related to @storybook/preset-create-react-app, we need to fix peerDependencies`
);
if (!reproPackageJson.devDependencies?.vite) {
// ⚠️ TODO: Fix peer deps in `@storybook/preset-create-react-app`
logger.info(
`Magic stuff related to @storybook/preset-create-react-app, we need to fix peerDependencies`
);
await exec(`yarn add -D webpack-hot-middleware`, { cwd: reproDir });
}

View File

@ -12,7 +12,7 @@ export type Template = {
/**
* Script used to generate the base project of a template.
* The Storybook CLI will then initialize Storybook on top of that template.
* This is used to generate projects which are pushed to https://github.com/storybookjs/repro-sandboxes
* This is used to generate projects which are pushed to https://github.com/storybookjs/sandboxes
*/
script: string;
/**

View File

@ -11,7 +11,7 @@ import { allTemplates as TEMPLATES } from './sandbox-templates';
const logger = console;
interface ReproOptions {
interface SandboxOptions {
filterValue?: string;
output?: string;
branch?: string;
@ -21,12 +21,12 @@ type Choice = keyof typeof TEMPLATES;
const toChoices = (c: Choice): prompts.Choice => ({ title: TEMPLATES[c].name, value: c });
export const repro = async ({
export const sandbox = async ({
output: outputDirectory,
filterValue,
branch,
init,
}: ReproOptions) => {
}: SandboxOptions) => {
// Either get a direct match when users pass a template id, or filter through all templates
let selectedConfig: Template | undefined = TEMPLATES[filterValue as TemplateKey];
let selectedTemplate: Choice | null = selectedConfig ? (filterValue as TemplateKey) : null;
@ -83,7 +83,7 @@ export const repro = async ({
logger.info(
boxen(
dedent`
🤗 Welcome to ${chalk.yellow('sb repro NEXT')}! 🤗
🤗 Welcome to ${chalk.yellow('sb sandbox')}! 🤗
Create a ${chalk.green('new project')} to minimally reproduce Storybook issues.
@ -108,7 +108,7 @@ export const repro = async ({
selectedConfig = TEMPLATES[selectedTemplate];
if (!selectedConfig) {
throw new Error('🚨 Repro: please specify a valid template type');
throw new Error('🚨 Sandbox: please specify a valid template type');
}
}
@ -147,11 +147,11 @@ export const repro = async ({
logger.info(`🏃 Adding ${selectedConfig.name} into ${templateDestination}`);
logger.log('📦 Downloading repro template...');
logger.log('📦 Downloading sandbox template...');
try {
const templateType = init ? 'after-storybook' : 'before-storybook';
// Download the repro based on subfolder "after-storybook" and selected branch
const gitPath = `github:storybookjs/repro-templates-temp/${selectedTemplate}/${templateType}#${branch}`;
// Download the sandbox based on subfolder "after-storybook" and selected branch
const gitPath = `github:storybookjs/sandboxes/${selectedTemplate}/${templateType}#${branch}`;
await downloadTemplate(gitPath, {
force: true,
dir: templateDestination,
@ -166,7 +166,7 @@ export const repro = async ({
);
}
} catch (err) {
logger.error(`🚨 Failed to download repro template: ${err.message}`);
logger.error(`🚨 Failed to download sandbox template: ${err.message}`);
throw err;
}
@ -194,7 +194,7 @@ export const repro = async ({
)
);
} catch (error) {
logger.error('🚨 Failed to create repro');
logger.error('🚨 Failed to create sandbox');
throw error;
}
};

View File

@ -30,7 +30,7 @@
"ci-tests": "yarn task --task check --no-link --start-from=install && yarn lint && yarn test && cd ../scripts && yarn test",
"coverage": "codecov",
"danger": "danger",
"generate-repros": "ts-node --swc ../scripts/next-repro-generators/generate-repros.ts",
"generate-sandboxes": "ts-node --swc ../scripts/sandbox-generators/generate-repros.ts",
"github-release": "github-release-from-changelog",
"linear-export": "ts-node --swc --project=../scripts/tsconfig.json ../scripts/linear-export.ts",
"lint": "yarn lint:js && yarn lint:md",
@ -41,7 +41,7 @@
"lint:other": "prettier --write '**/*.{css,html,json,md,yml}'",
"lint:package": "sort-package-json",
"local-registry": "ts-node --swc --project=../scripts/tsconfig.json ../scripts/run-registry.ts",
"publish-repros": "ts-node --swc ../scripts/next-repro-generators/publish.ts",
"publish-sandboxes": "ts-node --swc ../scripts/sandbox-generators/publish.ts",
"publish:debug": "npm run publish:latest -- --npm-tag=debug --no-push",
"publish:latest": "lerna publish --exact --concurrency 1 --force-publish",
"publish:next": "npm run publish:latest -- --npm-tag=next",

View File

@ -188,13 +188,13 @@ npx storybook@next link --local /path/to/local-repro-directory
<div class="aside">
💡 The `storybook link` command relies on [Yarn 2 linking](https://yarnpkg.com/cli/link/) under the hood. It requires your local reproduction to be using [Yarn 2](https://yarnpkg.com/) as well, which is the case if you're already enabled it with the [`storybook repro`](./how-to-reproduce.md) command per our contribution guidelines. The process will fail if you're trying to link a non-Yarn 2 project.
💡 The `storybook link` command relies on [Yarn 2 linking](https://yarnpkg.com/cli/link/) under the hood. It requires your local reproduction to be using [Yarn 2](https://yarnpkg.com/) as well, which is the case if you're already enabled it with the [`storybook sandbox`](./how-to-reproduce.md) command per our contribution guidelines. The process will fail if you're trying to link a non-Yarn 2 project.
</div>
## Developing a template
The first step is to add an entry to `code/lib/cli/src/repro-templates.ts`, which is the master list of all repro templates:
The first step is to add an entry to `code/lib/cli/src/sandbox-templates.ts`, which is the master list of all repro templates:
```ts
'cra/default-js': {
@ -209,7 +209,7 @@ The first step is to add an entry to `code/lib/cli/src/repro-templates.ts`, whic
},
```
Add the `isDevelopment` flag until the PR is merged (you can fast-follow it with a second PR to remove the flag), as it'll make the development process much easier.
Add the `inDevelopment` flag until the PR is merged (you can fast-follow it with a second PR to remove the flag), as it'll make the development process much easier.
The **`key`** `cra/default-js` consists of two parts:

View File

@ -21,11 +21,11 @@ Make sure you have:
First, open a terminal and run the following command:
```shell
npx storybook@next repro
npx storybook@next sandbox
```
<div class="aside">
💡 You can append a template name in the command to get filtered results e.g. <code>npx storybook@next repro react</code>
💡 You can append a template name in the command to get filtered results e.g. <code>npx storybook@next sandbox react</code>
</div>
Next, choose the template you want to work with:

View File

@ -1,3 +0,0 @@
#!/usr/bin/env bash
./scripts/node_modules/.bin/ts-node ./scripts/next-repro-generators/generate-repros.ts

3
generate-sandboxes.sh Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
./scripts/node_modules/.bin/ts-node ./scripts/sandbox-generators/generate-sandboxes.ts

View File

@ -10,7 +10,7 @@ import { execaCommand } from '../utils/exec';
import type { OptionValues } from '../utils/options';
import { createOptions } from '../utils/options';
import { allTemplates as reproTemplates } from '../../code/lib/cli/src/sandbox-templates';
import { allTemplates as sandboxTemplates } from '../../code/lib/cli/src/sandbox-templates';
import storybookVersions from '../../code/lib/cli/src/versions';
import { JsPackageManagerFactory } from '../../code/lib/cli/src/js-package-manager/JsPackageManagerFactory';
@ -30,7 +30,7 @@ const SCRIPT_TIMEOUT = 5 * 60 * 1000;
const sbInit = async (cwd: string, flags?: string[], debug?: boolean) => {
const sbCliBinaryPath = join(__dirname, `../../code/lib/cli/bin/index.js`);
console.log(`🎁 Installing storybook`);
const env = { STORYBOOK_DISABLE_TELEMETRY: 'true', STORYBOOK_REPRO_GENERATOR: 'true' };
const env = { STORYBOOK_DISABLE_TELEMETRY: 'true' };
const fullFlags = ['--yes', ...(flags || [])];
await runCommand(`${sbCliBinaryPath} init ${fullFlags.join(' ')}`, { cwd, env }, debug);
};
@ -124,7 +124,7 @@ const runGenerators = async (
localRegistry = true,
debug = false
) => {
console.log(`🤹‍♂️ Generating repros with a concurrency of ${maxConcurrentTasks}`);
console.log(`🤹‍♂️ Generating sandboxes with a concurrency of ${maxConcurrentTasks}`);
const limit = pLimit(maxConcurrentTasks);
@ -177,8 +177,8 @@ const runGenerators = async (
await addDocumentation(baseDir, { name, dirName });
// Remove node_modules to save space and avoid GH actions failing
// They're not uploaded to the git repros repo anyway
if (process.env.CLEANUP_REPRO_NODE_MODULES) {
// They're not uploaded to the git sandboxes repo anyway
if (process.env.CLEANUP_SANDBOX_NODE_MODULES) {
console.log(`🗑️ Removing ${join(beforeDir, 'node_modules')}`);
await remove(join(beforeDir, 'node_modules'));
console.log(`🗑️ Removing ${join(baseDir, AFTER_DIR_NAME, 'node_modules')}`);
@ -200,7 +200,7 @@ export const options = createOptions({
template: {
type: 'string',
description: 'Which template would you like to create?',
values: Object.keys(reproTemplates),
values: Object.keys(sandboxTemplates),
},
localRegistry: {
type: 'boolean',
@ -219,7 +219,7 @@ export const generate = async ({
localRegistry,
debug,
}: OptionValues<typeof options>) => {
const generatorConfigs = Object.entries(reproTemplates)
const generatorConfigs = Object.entries(sandboxTemplates)
.map(([dirName, configuration]) => ({
dirName,
...configuration,

View File

@ -91,7 +91,7 @@ program
program.parse(process.argv);
if (!existsSync(REPROS_DIRECTORY)) {
throw Error("Can't find repros directory. Did you forget to run generate-repros?");
throw Error("Can't find repros directory. Did you forget to run generate-sandboxes?");
}
const tmpFolder = tempy.directory();

View File

@ -2,7 +2,7 @@ import { render } from 'ejs';
import { readFile } from 'fs-extra';
import { format } from 'prettier';
import type { GeneratorConfig } from './types';
import { allTemplates as reproTemplates } from '../../../code/lib/cli/src/sandbox-templates';
import { allTemplates as sandboxTemplates } from '../../../code/lib/cli/src/sandbox-templates';
export async function renderTemplate(templatePath: string, templateData: Record<string, any>) {
const template = await readFile(templatePath, 'utf8');
@ -14,7 +14,7 @@ export async function renderTemplate(templatePath: string, templateData: Record<
}
export const getStackblitzUrl = (path: string, branch = 'next') => {
return `https://stackblitz.com/github/storybookjs/repro-sandboxes/tree/${branch}/${path}/after-storybook?preset=node`;
return `https://stackblitz.com/github/storybookjs/sandboxes/tree/${branch}/${path}/after-storybook?preset=node`;
};
export async function getTemplatesData() {
@ -28,12 +28,12 @@ export async function getTemplatesData() {
>
>;
const templatesData = Object.keys(reproTemplates).reduce<TemplatesData>(
(acc, curr: keyof typeof reproTemplates) => {
const templatesData = Object.keys(sandboxTemplates).reduce<TemplatesData>(
(acc, curr: keyof typeof sandboxTemplates) => {
const [dirName, templateName] = curr.split('/');
const groupName =
dirName === 'cra' ? 'CRA' : dirName.slice(0, 1).toUpperCase() + dirName.slice(1);
const generatorData = reproTemplates[curr];
const generatorData = sandboxTemplates[curr];
acc[groupName] = acc[groupName] || {};
acc[groupName][templateName] = {
...generatorData,

View File

@ -1,7 +1,7 @@
import { join } from 'path';
import { move, remove } from 'fs-extra';
// eslint-disable-next-line import/no-cycle
import { runCommand } from '../generate-repros';
import { runCommand } from '../generate-sandboxes';
interface SetupYarnOptions {
cwd: string;

View File

@ -27,7 +27,7 @@ export const generate: Task = {
}
// This uses an async import as it depends on `lib/cli` which requires `code` to be installed.
const { generate: generateRepro } = await import('../next-repro-generators/generate-repros');
const { generate: generateRepro } = await import('../sandbox-generators/generate-sandboxes');
await generateRepro({
template: details.key,