Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use repro-next in the example script! #18839

Merged
merged 5 commits into from
Aug 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ dist
.cache
junit.xml
/repros
/sandbox

# Yarn stuff
/**/.yarn/*
Expand All @@ -17,4 +18,3 @@ junit.xml
!/**/.yarn/versions
/**/.pnp.*
/yarn.lock
./examples/
1 change: 0 additions & 1 deletion code/lib/cli/src/repro-generators/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ export const exec = async (
});

child.stderr.pipe(process.stderr);
child.stdout.pipe(process.stdout);

child.on('exit', (code) => {
if (code === 0) {
Expand Down
2 changes: 1 addition & 1 deletion code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
"clean:dist": "del **/dist",
"coverage": "codecov",
"danger": "danger",
"example": "ts-node ../scripts/example.ts",
"generate-repros": "zx ../scripts/repros-generator/index.mjs",
"github-release": "github-release-from-changelog",
"linear-export": "ts-node --project=../scripts/tsconfig.json ../scripts/linear-export.ts",
Expand All @@ -80,6 +79,7 @@
"publish:latest": "lerna publish --exact --concurrency 1 --force-publish",
"publish:next": "npm run publish:latest -- --npm-tag=next",
"run-chromatics": "node -r esm ../scripts/run-chromatics.js",
"sandbox": "ts-node ../scripts/sandbox.ts",
"serve-storybooks": "http-server ./built-storybooks -p 8001",
"smoketest-storybooks": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true node -r esm ../scripts/smoketest-storybooks.js",
"start": "yarn workspace official-storybook storybook --no-manager-cache",
Expand Down
2 changes: 1 addition & 1 deletion code/renderers/react/template/components/Button.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ export const Button = ({ onClick, children }) => (
Button.propTypes = {
onClick: PropTypes.func.isRequired,
children: PropTypes.node.isRequired,
}
};
84 changes: 46 additions & 38 deletions scripts/example.ts → scripts/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import { exec } from '../code/lib/cli/src/repro-generators/scripts';
import { getInterpretedFile } from '../code/lib/core-common';
import { ConfigFile, readConfig, writeConfig } from '../code/lib/csf-tools';
import { babelParse } from '../code/lib/csf-tools/src/babelParse';
import TEMPLATES from '../code/lib/cli/src/repro-templates';

const frameworks = ['react', 'angular'];
type Template = keyof typeof TEMPLATES;
const templates: Template[] = Object.keys(TEMPLATES) as any;
const addons = ['a11y', 'storysource'];
const defaultAddons = [
'actions',
Expand All @@ -25,17 +27,14 @@ const defaultAddons = [
'toolbars',
'viewport',
];
const examplesDir = path.resolve(__dirname, '../examples');
const sandboxDir = path.resolve(__dirname, '../sandbox');
const codeDir = path.resolve(__dirname, '../code');

// TODO -- how to encode this information
const renderersMap = { react: 'react', angular: 'angular' };

async function getOptions() {
return getOptionsOrPrompt('yarn example', {
framework: {
description: 'Which framework would you like to use?',
values: frameworks,
return getOptionsOrPrompt('yarn sandbox', {
template: {
description: 'Which template would you like to use?',
values: templates,
required: true as const,
},
addon: {
Expand All @@ -48,29 +47,29 @@ async function getOptions() {
promptType: (_, { framework }) => framework === 'react',
},
create: {
description: 'Create the example from scratch (rather than degitting it)?',
description: 'Create the template from scratch (rather than degitting it)?',
},
forceDelete: {
description: 'Always delete an existing example, even if it has the same configuration?',
description: 'Always delete an existing sandbox, even if it has the same configuration?',
promptType: false,
},
forceReuse: {
description: 'Always reuse an existing example, even if it has a different configuration?',
description: 'Always reuse an existing sandbox, even if it has a different configuration?',
promptType: false,
},
link: {
description: 'Link the storybook to the local code?',
inverse: true,
},
start: {
description: 'Start the example Storybook?',
description: 'Start the Storybook?',
inverse: true,
},
build: {
description: 'Build the example Storybook?',
description: 'Build the Storybook?',
},
watch: {
description: 'Start building used packages in watch mode as well as the example Storybook?',
description: 'Start building used packages in watch mode as well as the Storybook?',
},
dryRun: {
description: "Don't execute commands, just list them (dry run)?",
Expand All @@ -80,13 +79,15 @@ async function getOptions() {

const steps = {
repro: {
command: 'repro',
description: 'Bootstrapping example',
command: 'repro-next',
description: 'Bootstrapping Template',
icon: '👷',
hasArgument: true,
options: {
template: { values: frameworks },
e2e: {},
// TODO allow string valued options without fixed values
output: { values: [] as string[] },
// TODO allow default values for strings
branch: { values: ['next'] },
},
},
add: {
Expand All @@ -105,27 +106,34 @@ const steps = {
},
build: {
command: 'build',
description: 'Building example',
description: 'Building Storybook',
icon: '🔨',
options: {},
},
dev: {
command: 'dev',
description: 'Starting example',
description: 'Starting Storybook',
icon: '🖥 ',
options: {},
},
};

const logger = console;

const addPackageScripts = async ({
async function findFirstPath(paths: string[], { cwd }: { cwd: string }) {
for (const filePath of paths) {
if (await pathExists(path.join(cwd, filePath))) return filePath;
}
return null;
}

async function addPackageScripts({
cwd,
scripts,
}: {
cwd: string;
scripts: Record<string, string>;
}) => {
}) {
logger.info(`🔢 Adding package resolutions:`);
const packageJsonPath = path.join(cwd, 'package.json');
const packageJson = await readJSON(packageJsonPath);
Expand All @@ -134,7 +142,7 @@ const addPackageScripts = async ({
...scripts,
};
await writeJSON(packageJsonPath, packageJson, { spaces: 2 });
};
}

async function readMainConfig({ cwd }: { cwd: string }) {
const configDir = path.join(cwd, '.storybook');
Expand Down Expand Up @@ -164,10 +172,7 @@ const webpackFinalCode = `
})`;

// paths are of the form 'node_modules/@storybook/react'
async function addStories(
paths: string[],
{ mainConfig, cwd }: { mainConfig: ConfigFile; cwd: string }
) {
async function addStories(paths: string[], { mainConfig }: { mainConfig: ConfigFile }) {
const stories = mainConfig.getFieldValue(['stories']) as string[];
const extraStoryDirsAndExistence = await Promise.all(
paths
Expand All @@ -190,8 +195,8 @@ async function addStories(
async function main() {
const optionValues = await getOptions();

const { framework, forceDelete, forceReuse, link, dryRun } = optionValues;
const cwd = path.join(examplesDir, framework);
const { template, forceDelete, forceReuse, link, dryRun } = optionValues;
const cwd = path.join(sandboxDir, template.replace('/', '-'));

const exists = await pathExists(cwd);
let shouldDelete = exists && !forceReuse;
Expand All @@ -211,20 +216,19 @@ async function main() {

if (!exists || shouldDelete) {
await executeCLIStep(steps.repro, {
argument: cwd,
optionValues: { template: framework },
cwd: examplesDir,
argument: template,
optionValues: { output: cwd, branch: 'next' },
cwd: sandboxDir,
dryRun,
});

const mainConfig = await readMainConfig({ cwd });

// TODO -- can we get the options type to return something more specific
const renderer = renderersMap[framework as 'react' | 'angular'];
const storiesPath = 'stories'; // This may differ in different projects
const templateConfig = TEMPLATES[template as Template];
const storiesPath = await findFirstPath([path.join('src', 'stories'), 'stories'], { cwd });

// Link in the template/components/index.js from the renderer
const rendererPath = path.join('node_modules', '@storybook', renderer);
const rendererPath = path.join('node_modules', templateConfig.expected.renderer);
await ensureSymlink(
path.join(codeDir, rendererPath, 'template', 'components'),
path.resolve(cwd, storiesPath, 'components')
Expand All @@ -250,11 +254,15 @@ async function main() {
for (const addon of [...defaultAddons, ...optionValues.addon]) {
storiesToAdd.push(path.join('node_modules', '@storybook', `addon-${addon}`));
}
await addStories(storiesToAdd, { mainConfig, cwd });
await addStories(storiesToAdd, { mainConfig });

await writeConfig(mainConfig);

if (link) {
await exec('yarn set version berry', { cwd }, { dryRun });
await exec('yarn config set enableGlobalCache true', { cwd }, { dryRun });
await exec('yarn config set nodeLinker node-modules', { cwd }, { dryRun });

await executeCLIStep(steps.link, {
argument: cwd,
cwd: codeDir,
Expand Down