diff --git a/code/lib/cli/src/automigrate/fixes/mainjsFramework.ts b/code/lib/cli/src/automigrate/fixes/mainjsFramework.ts index 69cad36afe62..b08460602cf8 100644 --- a/code/lib/cli/src/automigrate/fixes/mainjsFramework.ts +++ b/code/lib/cli/src/automigrate/fixes/mainjsFramework.ts @@ -31,11 +31,10 @@ export const mainjsFramework: Fix = { 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); diff --git a/code/lib/cli/src/automigrate/fixes/new-frameworks.ts b/code/lib/cli/src/automigrate/fixes/new-frameworks.ts index 88cac278c3a2..dee016f57808 100644 --- a/code/lib/cli/src/automigrate/fixes/new-frameworks.ts +++ b/code/lib/cli/src/automigrate/fixes/new-frameworks.ts @@ -113,11 +113,10 @@ export const newFrameworks: Fix = { 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')) { @@ -151,18 +150,6 @@ export const newFrameworks: Fix = { 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); @@ -183,6 +170,18 @@ export const newFrameworks: Fix = { 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, @@ -194,13 +193,17 @@ export const newFrameworks: Fix = { }; }, - 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' @@ -211,7 +214,7 @@ export const newFrameworks: Fix = { 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' diff --git a/code/lib/cli/src/automigrate/fixes/nextjs-framework.ts b/code/lib/cli/src/automigrate/fixes/nextjs-framework.ts index ca737b5fe03b..5dbe0f5b22cc 100644 --- a/code/lib/cli/src/automigrate/fixes/nextjs-framework.ts +++ b/code/lib/cli/src/automigrate/fixes/nextjs-framework.ts @@ -65,11 +65,10 @@ export const nextjsFramework: Fix = { 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')) { diff --git a/code/lib/cli/src/automigrate/fixes/sb-binary.ts b/code/lib/cli/src/automigrate/fixes/sb-binary.ts index 075e841bb7cf..91f647ba7a52 100644 --- a/code/lib/cli/src/automigrate/fixes/sb-binary.ts +++ b/code/lib/cli/src/automigrate/fixes/sb-binary.ts @@ -34,11 +34,10 @@ export const sbBinary: Fix = { 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')) { diff --git a/code/lib/cli/src/automigrate/fixes/sb-scripts.ts b/code/lib/cli/src/automigrate/fixes/sb-scripts.ts index e561cf2f7e01..73dd8ac39776 100644 --- a/code/lib/cli/src/automigrate/fixes/sb-scripts.ts +++ b/code/lib/cli/src/automigrate/fixes/sb-scripts.ts @@ -77,11 +77,10 @@ export const sbScripts: Fix = { 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')) { diff --git a/code/lib/cli/src/automigrate/fixes/sveltekit-framework.ts b/code/lib/cli/src/automigrate/fixes/sveltekit-framework.ts index b2201a0791b7..3422da2cfc61 100644 --- a/code/lib/cli/src/automigrate/fixes/sveltekit-framework.ts +++ b/code/lib/cli/src/automigrate/fixes/sveltekit-framework.ts @@ -46,11 +46,10 @@ export const sveltekitFramework: Fix = { 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')) { diff --git a/code/lib/cli/src/automigrate/fixes/webpack5.ts b/code/lib/cli/src/automigrate/fixes/webpack5.ts index ee6052edac7a..9cd2839d598f 100644 --- a/code/lib/cli/src/automigrate/fixes/webpack5.ts +++ b/code/lib/cli/src/automigrate/fixes/webpack5.ts @@ -39,11 +39,10 @@ export const webpack5: Fix & 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')) { diff --git a/code/lib/cli/src/automigrate/index.ts b/code/lib/cli/src/automigrate/index.ts index fd142694f649..06cb92d0d468 100644 --- a/code/lib/cli/src/automigrate/index.ts +++ b/code/lib/cli/src/automigrate/index.ts @@ -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'; @@ -33,27 +34,29 @@ export const automigrate = async ({ fixId, dryRun, yes, useNpm, force }: FixOpti logger.info('šŸ”Ž checking possible migrations..'); const fixResults = {} as Record; + const fixSummary = { succeeded: [], failed: {} } as { + succeeded: FixId[]; + failed: Record; + }; 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 }; @@ -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(); @@ -85,9 +90,6 @@ 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')}'` - ); } } @@ -95,8 +97,67 @@ export const automigrate = async ({ fixId, dryRun, yes, useNpm, force }: FixOpti } logger.info(); - logger.info('āœ… migration check successfully ran'); + logger.info(getMigrationSummary(fixResults, fixSummary)); logger.info(); return fixResults; }; + +function getMigrationSummary( + fixResults: Record, + fixSummary: { succeeded: FixId[]; failed: Record } +) { + 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', + }); +}