Skip to content

Commit

Permalink
Merge pull request #20276 from storybookjs/feat/automigration-summary
Browse files Browse the repository at this point in the history
CLI: add automigration summary
  • Loading branch information
yannbf authored Dec 15, 2022
2 parents 4ca7e4a + 8f711a4 commit 67a0309
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 51 deletions.
5 changes: 2 additions & 3 deletions code/lib/cli/src/automigrate/fixes/mainjsFramework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@ export const mainjsFramework: Fix<MainjsFrameworkRunOptions> = {

const storybookCoerced = storybookVersion && semver.coerce(storybookVersion)?.version;
if (!storybookCoerced) {
logger.warn(dedent`
❌ Unable to determine storybook version, skipping ${chalk.cyan('mainjsFramework')} fix.
throw new Error(dedent`
❌ Unable to determine storybook version.
🤔 Are you running automigrate from your project directory?
`);
return null;
}

const main = await readConfig(mainConfig);
Expand Down
39 changes: 21 additions & 18 deletions code/lib/cli/src/automigrate/fixes/new-frameworks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,10 @@ export const newFrameworks: Fix<NewFrameworkRunOptions> = {

const storybookCoerced = storybookVersion && semver.coerce(storybookVersion)?.version;
if (!storybookCoerced) {
logger.warn(dedent`
❌ Unable to determine storybook version, skipping ${chalk.cyan('newFrameworks')} fix.
throw new Error(dedent`
❌ Unable to determine storybook version.
🤔 Are you running automigrate from your project directory?
`);
return null;
}

if (!semver.gte(storybookCoerced, '7.0.0')) {
Expand Down Expand Up @@ -151,18 +150,6 @@ export const newFrameworks: Fix<NewFrameworkRunOptions> = {
return null;
}

if (allDeps.vite && semver.lt(semver.coerce(allDeps.vite).version, '3.0.0')) {
logger.warn(dedent`
❌ Detected Vite ${
allDeps.vite
}, which is unsupported in Storybook 7.0, so the ${chalk.cyan(
'newFrameworks'
)} fix will be skipped.
Please upgrade vite to 3.0.0 or higher and rerun this automigration with "npx storybook@future automigrate".
`);
return null;
}

const frameworkOptions =
// svelte-vite doesn't support svelteOptions so there's no need to move them
newFrameworkPackage === '@storybook/svelte-vite' ? {} : getFrameworkOptions(framework, main);
Expand All @@ -183,6 +170,18 @@ export const newFrameworks: Fix<NewFrameworkRunOptions> = {
dependenciesToAdd.push(newFrameworkPackage);
}

if (allDeps.vite && semver.lt(semver.coerce(allDeps.vite).version, '3.0.0')) {
throw new Error(dedent`
❌ Your project should be upgraded to use the framework package ${chalk.bold(
newFrameworkPackage
)}, but we detected that you are using Vite ${chalk.bold(
allDeps.vite
)}, which is unsupported in ${chalk.bold(
'Storybook 7.0'
)}. Please upgrade Vite to ${chalk.bold('3.0.0 or higher')} and rerun this migration.
`);
}

return {
main,
dependenciesToAdd,
Expand All @@ -194,13 +193,17 @@ export const newFrameworks: Fix<NewFrameworkRunOptions> = {
};
},

prompt() {
prompt({ frameworkPackage, dependenciesToRemove }) {
return dedent`
We've detected you are using an older format of Storybook frameworks and builders.
In Storybook 7, frameworks also specify the builder to be used.
We can remove the dependencies that are no longer needed and install the new framework that already includes the builder.
We can remove the dependencies that are no longer needed: ${chalk.yellow(
dependenciesToRemove.join(', ')
)}
And set up the ${chalk.magenta(frameworkPackage)} framework that already includes the builder.
To learn more about the framework field, see: ${chalk.yellow(
'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#framework-field-mandatory'
Expand All @@ -211,7 +214,7 @@ export const newFrameworks: Fix<NewFrameworkRunOptions> = {
Unless you're using Storybook's Vite builder, this automigration will install a Webpack5-based framework.
If you were using Storybook's Webpack4 builder (default in 6.x, discontinued in 7.0), this could be a breaking
change--especially if your project has a custom webpack configuration.
change -- especially if your project has a custom webpack configuration.
To learn more about migrating from Webpack4, see: ${chalk.yellow(
'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#webpack4-support-discontinued'
Expand Down
5 changes: 2 additions & 3 deletions code/lib/cli/src/automigrate/fixes/nextjs-framework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,10 @@ export const nextjsFramework: Fix<NextjsFrameworkRunOptions> = {

const storybookCoerced = storybookVersion && semver.coerce(storybookVersion)?.version;
if (!storybookCoerced) {
logger.warn(dedent`
❌ Unable to determine storybook version, skipping ${chalk.cyan('nextjsFramework')} fix.
throw new Error(dedent`
❌ Unable to determine storybook version.
🤔 Are you running automigrate from your project directory?
`);
return null;
}

if (!semver.gte(storybookCoerced, '7.0.0')) {
Expand Down
5 changes: 2 additions & 3 deletions code/lib/cli/src/automigrate/fixes/sb-binary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,10 @@ export const sbBinary: Fix<SbBinaryRunOptions> = {

const storybookCoerced = storybookVersion && semver.coerce(storybookVersion)?.version;
if (!storybookCoerced) {
logger.warn(dedent`
❌ Unable to determine storybook version, skipping ${chalk.cyan(this.id)} fix.
throw new Error(dedent`
❌ Unable to determine storybook version.
🤔 Are you running automigrate from your project directory?
`);
return null;
}

if (semver.lt(storybookCoerced, '7.0.0')) {
Expand Down
5 changes: 2 additions & 3 deletions code/lib/cli/src/automigrate/fixes/sb-scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,10 @@ export const sbScripts: Fix<SbScriptsRunOptions> = {

const storybookCoerced = storybookVersion && semver.coerce(storybookVersion)?.version;
if (!storybookCoerced) {
logger.warn(dedent`
❌ Unable to determine storybook version, skipping ${chalk.cyan(this.id)} fix.
throw new Error(dedent`
❌ Unable to determine storybook version.
🤔 Are you running automigrate from your project directory?
`);
return null;
}

if (semver.lt(storybookCoerced, '7.0.0')) {
Expand Down
5 changes: 2 additions & 3 deletions code/lib/cli/src/automigrate/fixes/sveltekit-framework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,10 @@ export const sveltekitFramework: Fix<SvelteKitFrameworkRunOptions> = {

const sbVersionCoerced = storybookVersion && semver.coerce(storybookVersion)?.version;
if (!sbVersionCoerced) {
logger.warn(dedent`
❌ Unable to determine Storybook version, skipping ${chalk.cyan(fixId)} fix.
throw new Error(dedent`
❌ Unable to determine storybook version.
🤔 Are you running automigrate from your project directory?
`);
return null;
}

if (!semver.gte(sbVersionCoerced, '7.0.0')) {
Expand Down
5 changes: 2 additions & 3 deletions code/lib/cli/src/automigrate/fixes/webpack5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ export const webpack5: Fix<Webpack5RunOptions> & CheckBuilder = {

const storybookCoerced = storybookVersion && semver.coerce(storybookVersion)?.version;
if (!storybookCoerced) {
logger.warn(dedent`
❌ Unable to determine storybook version, skipping ${chalk.cyan('webpack5')} fix.
throw new Error(dedent`
❌ Unable to determine storybook version.
🤔 Are you running automigrate from your project directory?
`);
return null;
}

if (semver.lt(storybookCoerced, '6.3.0')) {
Expand Down
91 changes: 76 additions & 15 deletions code/lib/cli/src/automigrate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import prompts from 'prompts';
import chalk from 'chalk';
import boxen from 'boxen';
import dedent from 'ts-dedent';
import { JsPackageManagerFactory, type PackageManagerName } from '../js-package-manager';

import type { Fix } from './fixes';
Expand Down Expand Up @@ -33,27 +34,29 @@ export const automigrate = async ({ fixId, dryRun, yes, useNpm, force }: FixOpti

logger.info('🔎 checking possible migrations..');
const fixResults = {} as Record<FixId, FixStatus>;
const fixSummary = { succeeded: [], failed: {} } as {
succeeded: FixId[];
failed: Record<FixId, string>;
};

for (let i = 0; i < filtered.length; i += 1) {
const f = fixes[i] as Fix;
let result;
let fixStatus;
let fixStatus = FixStatus.UNNECESSARY;

try {
result = await f.check({ packageManager });
} catch (e) {
} catch (error) {
logger.info(`⚠️ failed to check fix ${chalk.bold(f.id)}`);
fixStatus = FixStatus.CHECK_FAILED;
logger.info(`failed to check fix: ${f.id}`);
fixSummary.failed[f.id] = error.message;
}
if (!result) {
fixStatus = FixStatus.UNNECESSARY;
} else {
logger.info(`🔎 found a '${chalk.cyan(f.id)}' migration:`);
logger.info();

if (result) {
logger.info(`\n🔎 found a '${chalk.cyan(f.id)}' migration:`);
const message = f.prompt(result);

logger.info(
boxen(message, { borderStyle: 'round', padding: 1, borderColor: '#F1618C' } as any)
);
logger.info(boxen(message, { borderStyle: 'round', padding: 1, borderColor: '#F1618C' }));

let runAnswer: { fix: boolean };

Expand All @@ -75,8 +78,10 @@ export const automigrate = async ({ fixId, dryRun, yes, useNpm, force }: FixOpti
await f.run({ result, packageManager, dryRun });
logger.info(`✅ ran ${chalk.cyan(f.id)} migration`);
fixStatus = FixStatus.SUCCEEDED;
fixSummary.succeeded.push(f.id);
} catch (error) {
fixStatus = FixStatus.FAILED;
fixSummary.failed[f.id] = error.message;
logger.info(`❌ error when running ${chalk.cyan(f.id)} migration:`);
logger.info(error);
logger.info();
Expand All @@ -85,18 +90,74 @@ export const automigrate = async ({ fixId, dryRun, yes, useNpm, force }: FixOpti
fixStatus = FixStatus.SKIPPED;
logger.info(`Skipping the ${chalk.cyan(f.id)} migration.`);
logger.info();
logger.info(
`If you change your mind, run '${chalk.cyan('npx storybook@next automigrate')}'`
);
}
}

fixResults[f.id] = fixStatus;
}

logger.info();
logger.info('✅ migration check successfully ran');
logger.info(getMigrationSummary(fixResults, fixSummary));
logger.info();

return fixResults;
};

function getMigrationSummary(
fixResults: Record<string, FixStatus>,
fixSummary: { succeeded: FixId[]; failed: Record<FixId, string> }
) {
const hasNoFixes = Object.values(fixResults).every((r) => r === FixStatus.UNNECESSARY);
const hasFailures = Object.values(fixResults).some(
(r) => r === FixStatus.FAILED || r === FixStatus.CHECK_FAILED
);
// eslint-disable-next-line no-nested-ternary
const title = hasNoFixes
? 'No migrations were applicable to your project'
: hasFailures
? 'Migration check ran with failures'
: 'Migration check ran successfully';

const successfulFixesMessage =
fixSummary.succeeded.length > 0
? `
${chalk.bold('Migrations that succeeded:')}\n\n ${fixSummary.succeeded
.map((m) => chalk.green(m))
.join(', ')}
`
: '';

const failedFixesMessage =
Object.keys(fixSummary.failed).length > 0
? `
${chalk.bold('Migrations that failed:')}\n ${Object.entries(fixSummary.failed).reduce(
(acc, [id, error]) => {
return `${acc}\n${chalk.redBright(id)}:\n${error}\n`;
},
''
)}
\n`
: '';

const divider = hasNoFixes ? '' : '\n─────────────────────────────────────────────────\n\n';

const summaryMessage = dedent`
${successfulFixesMessage}${failedFixesMessage}${divider}If you'd like to run the migrations again, you can do so by running '${chalk.cyan(
'npx storybook@next automigrate'
)}'
The automigrations try to migrate common patterns in your project, but might not contain everything needed to migrate to the latest version of Storybook.
Please check the changelog and migration guide for manual migrations and more information: ${chalk.yellow(
'https://storybook.js.org/migration-guides/7.0'
)}
And reach out on Discord if you need help: ${chalk.yellow('https://discord.gg/storybook')}
`;

return boxen(summaryMessage, {
borderStyle: 'round',
padding: 1,
title,
borderColor: hasFailures ? 'red' : 'green',
});
}

0 comments on commit 67a0309

Please sign in to comment.