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: add automigration summary #20276

Merged
merged 6 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from 4 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: 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
33 changes: 15 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,14 @@ 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 +189,15 @@ 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 +208,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
67 changes: 51 additions & 16 deletions code/lib/cli/src/automigrate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { JsPackageManagerFactory, type PackageManagerName } from '../js-package-

import type { Fix } from './fixes';
import { fixes } from './fixes';
import dedent from 'ts-dedent';

const logger = console;

Expand Down Expand Up @@ -33,26 +34,27 @@ 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)
boxen(message, { borderStyle: 'round', padding: 1, borderColor: '#F1618C' })
);

let runAnswer: { fix: boolean };
Expand All @@ -75,8 +77,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 +89,49 @@ 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;
fixResults[f.id] = fixStatus
}

logger.info();
logger.info('✅ migration check successfully ran');
logger.info();
logger.info()
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);
let title = hasNoFixes ? 'No migrations were applicable to your project' : hasFailures ? 'Migration check ran with failures' : 'Migration check ran successfully';

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

let 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';

let 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' });
}