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

CLI: create temporary sb repro-next command that only degits repros #18834

Merged
merged 3 commits into from
Aug 1, 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
5 changes: 0 additions & 5 deletions .github/workflows/generate-repros-next.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@ name: Generate and push repros to the next branch
on:
schedule:
- cron: '2 2 */1 * *'
workflow_dispatch:
# To remove when the branch will be merged
push:
branches:
- yann/sb-509-create-github-action

jobs:
generate:
Expand Down
4 changes: 4 additions & 0 deletions code/lib/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
],
"scripts": {
"check": "tsc --noEmit",
"preprepare": "node ./scripts/generate-repro-templates-list.js",
"prepare": "node ../../../scripts/prepare.js",
"test": "jest test/**/*.test.js"
},
Expand All @@ -60,13 +61,15 @@
"commander": "^6.2.1",
"core-js": "^3.8.2",
"cross-spawn": "^7.0.3",
"degit": "^2.8.4",
"envinfo": "^7.7.3",
"execa": "^5.0.0",
"express": "^4.17.1",
"find-up": "^5.0.0",
"fs-extra": "^9.0.1",
"get-port": "^5.1.1",
"globby": "^11.0.2",
"js-yaml": "^3.14.1",
"jscodeshift": "^0.13.1",
"json5": "^2.1.3",
"leven": "^3.1.0",
Expand All @@ -81,6 +84,7 @@
"devDependencies": {
"@storybook/client-api": "7.0.0-alpha.17",
"@types/cross-spawn": "^6.0.2",
"@types/degit": "^2.8.3",
"@types/prompts": "^2.0.9",
"@types/puppeteer-core": "^2.1.0",
"@types/semver": "^7.3.4",
Expand Down
42 changes: 42 additions & 0 deletions code/lib/cli/scripts/generate-repro-templates-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env node

const { writeFile } = require('fs-extra');
const { exec } = require('child_process');
const path = require('path');
const { default: dedent } = require('ts-dedent');
const { readFile } = require('fs-extra');
const yml = require('js-yaml');

const logger = console;

async function getTemplatesData(filePath) {
const configContents = await readFile(filePath, 'utf8');
return yml.load(configContents);
}

const run = async () => {
logger.log('Generating templates list...');
const templatesData = await getTemplatesData(
path.resolve(__dirname, '../../../../scripts/next-repro-generators/repro-config.yml')
);
const destination = path.join(__dirname, '..', 'src', 'repro-templates.ts');

await writeFile(
destination,
dedent`
// This file was auto generated from generate-repro-templates-list.js, please do not edit!
export default ${JSON.stringify(templatesData, null, 2)}
`
);

exec(`yarn lint:js:cmd --fix ${destination}`, {
cwd: path.join(__dirname, '..', '..', '..'),
});

logger.log('Done! generated ', destination);
};

run().catch((e) => {
logger.error(e);
process.exit(1);
});
13 changes: 13 additions & 0 deletions code/lib/cli/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { migrate } from './migrate';
import { extract } from './extract';
import { upgrade } from './upgrade';
import { repro } from './repro';
import { reproNext } from './repro-next';
import { link } from './link';
import { automigrate } from './automigrate';
import { generateStorybookBabelConfigInCWD } from './babel-config';
Expand Down Expand Up @@ -146,6 +147,18 @@ program
})
);

program
.command('repro-next [filterValue]')
.description('Create a reproduction from a set of possible templates')
.option('-o --output <outDir>', 'Define an output directory')
.option('-b --branch <branch>', 'Define the branch to degit from', 'next')
.action((filterValue, options) =>
reproNext({ filterValue, ...options }).catch((e) => {
logger.error(e);
process.exit(1);
})
);

program
.command('link <repo-url-or-directory>')
.description('Pull down a repro from a URL (or a local directory), link it, and run storybook')
Expand Down
172 changes: 172 additions & 0 deletions code/lib/cli/src/repro-next.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import prompts from 'prompts';
import fs from 'fs';
import path from 'path';
import chalk from 'chalk';
import boxen from 'boxen';
import { dedent } from 'ts-dedent';
import degit from 'degit';

import TEMPLATES from './repro-templates';

const logger = console;

interface ReproOptions {
filterValue?: string;
output?: string;
branch?: string;
}
type Choice = keyof typeof TEMPLATES;

const toChoices = (c: Choice): prompts.Choice => ({ title: TEMPLATES[c].name, value: c });

export const reproNext = async ({ output: outputDirectory, filterValue, branch }: ReproOptions) => {
const keys = Object.keys(TEMPLATES) as Choice[];
// get value from template and reduce through TEMPLATES to filter out the correct template
const choices = keys.reduce<Choice[]>((acc, group) => {
const current = TEMPLATES[group];

const filterRegex = new RegExp(filterValue, 'i');
if (!filterValue) {
acc.push(group);
return acc;
}

if (
current.name.match(filterRegex) ||
group.match(filterRegex) ||
current.expected.builder.match(filterRegex) ||
current.expected.framework.match(filterRegex) ||
current.expected.renderer.match(filterRegex)
) {
acc.push(group);
return acc;
}

return acc;
}, []);

if (choices.length === 0) {
logger.info(
boxen(
dedent`
🔎 You filtered out all templates. 🔍
After filtering all the templates with "${chalk.yellow(
filterValue
)}", we found no templates.

Available templates:
${keys.map((key) => chalk.blue`- ${key}`).join('\n')}
`.trim(),
{ borderStyle: 'round', padding: 1, borderColor: '#F1618C' } as any
)
);
return;
}

let selectedTemplate: Choice | null = null;

if (choices.length === 1) {
[selectedTemplate] = choices;
} else {
logger.info(
boxen(
dedent`
🤗 Welcome to ${chalk.yellow('sb repro NEXT')}! 🤗

Create a ${chalk.green('new project')} to minimally reproduce Storybook issues.

1. select an environment that most closely matches your project setup.
2. select a location for the reproduction, outside of your project.

After the reproduction is ready, we'll guide you through the next steps.
`.trim(),
{ borderStyle: 'round', padding: 1, borderColor: '#F1618C' } as any
)
);

selectedTemplate = await promptSelectedTemplate(choices);
}

const hasSelectedTemplate = !!(selectedTemplate ?? null);
if (!hasSelectedTemplate) {
logger.error('Somehow we got no templates. Please rerun this command!');
return;
}

const selectedConfig = TEMPLATES[selectedTemplate];

if (!selectedConfig) {
throw new Error('🚨 Repro: please specify a valid template type');
}

let selectedDirectory = outputDirectory;
if (!selectedDirectory) {
const { directory } = await prompts({
type: 'text',
message: 'Enter the output directory',
name: 'directory',
initial: selectedTemplate,
validate: (directoryName) =>
fs.existsSync(directoryName)
? `${directoryName} already exists. Please choose another name.`
: true,
});
selectedDirectory = directory;
}

try {
const cwd = path.isAbsolute(selectedDirectory)
? selectedDirectory
: path.join(process.cwd(), selectedDirectory);

logger.info(`🏃 Adding ${selectedConfig.name} into ${cwd}`);

logger.log('📦 Downloading repro template...');
try {
// Download the repro based on subfolder "after-storybook" and selected branch
await degit(
`storybookjs/repro-templates-temp/${selectedTemplate}/after-storybook#${branch}`,
{
force: true,
}
).clone(selectedTemplate.replace('/', '-'));
} catch (err) {
logger.error(`🚨 Failed to download repro template: ${err.message}`);
return;
}

logger.info(
boxen(
dedent`
🎉 Your Storybook reproduction project is ready to use! 🎉

${chalk.yellow(`cd ${selectedDirectory}`)}
${chalk.yellow(`yarn storybook`)}

Once you've recreated the problem you're experiencing, please:

1. Document any additional steps in ${chalk.cyan('README.md')}
2. Publish the repository to github
3. Link to the repro repository in your issue

Having a clean repro helps us solve your issue faster! 🙏
`.trim(),
{ borderStyle: 'round', padding: 1, borderColor: '#F1618C' } as any
)
);
} catch (error) {
logger.error('🚨 Failed to create repro');
throw error;
}
};

async function promptSelectedTemplate(choices: Choice[]): Promise<Choice | null> {
const { template } = await prompts({
type: 'select',
message: '🌈 Select the template',
name: 'template',
choices: choices.map(toChoices),
});

return template || null;
}
21 changes: 21 additions & 0 deletions code/lib/cli/src/repro-templates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// auto generated file, do not edit
export default {
'cra/default-js': {
name: 'Create React App (Javascript)',
script: 'npx create-react-app .',
expected: {
framework: '@storybook/cra',
renderer: '@storybook/react',
builder: '@storybook/builder-webpack5',
},
},
'cra/default-ts': {
name: 'Create React App (Typescript)',
script: 'npx create-react-app . --template typescript',
expected: {
framework: '@storybook/cra',
renderer: '@storybook/react',
builder: '@storybook/builder-webpack5',
},
},
} as const;
19 changes: 19 additions & 0 deletions code/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7691,6 +7691,7 @@ __metadata:
"@storybook/semver": ^7.3.2
"@storybook/telemetry": 7.0.0-alpha.17
"@types/cross-spawn": ^6.0.2
"@types/degit": ^2.8.3
"@types/prompts": ^2.0.9
"@types/puppeteer-core": ^2.1.0
"@types/semver": ^7.3.4
Expand All @@ -7701,13 +7702,15 @@ __metadata:
commander: ^6.2.1
core-js: ^3.8.2
cross-spawn: ^7.0.3
degit: ^2.8.4
envinfo: ^7.7.3
execa: ^5.0.0
express: ^4.17.1
find-up: ^5.0.0
fs-extra: ^9.0.1
get-port: ^5.1.1
globby: ^11.0.2
js-yaml: ^3.14.1
jscodeshift: ^0.13.1
json5: ^2.1.3
leven: ^3.1.0
Expand Down Expand Up @@ -10110,6 +10113,13 @@ __metadata:
languageName: node
linkType: hard

"@types/degit@npm:^2.8.3":
version: 2.8.3
resolution: "@types/degit@npm:2.8.3"
checksum: 1693dc0033aa5aa5c339b76d570c462e3e0ff41e22a7cc2d0164276199ddbd6ed18813042868355bc5f60ee257c0b18bce904c193008685b790392454ec9fcbd
languageName: node
linkType: hard

"@types/detect-port@npm:^1.3.2":
version: 1.3.2
resolution: "@types/detect-port@npm:1.3.2"
Expand Down Expand Up @@ -18446,6 +18456,15 @@ __metadata:
languageName: node
linkType: hard

"degit@npm:^2.8.4":
version: 2.8.4
resolution: "degit@npm:2.8.4"
bin:
degit: degit
checksum: 25ae9daf8010b450ffe8307c5ca903fe8bfaa8bb8622da12f81f2b6c3b1bb24e96fe3ab0b4ec4a1a19684f674b2158a8a3a2178c481882cc4991c7a0859ec40a
languageName: node
linkType: hard

"del-cli@npm:^4.0.1":
version: 4.0.1
resolution: "del-cli@npm:4.0.1"
Expand Down