diff --git a/code/lib/cli/src/automigrate/fixes/incompatible-addons.test.ts b/code/lib/cli/src/automigrate/fixes/incompatible-addons.test.ts deleted file mode 100644 index d23f369da214..000000000000 --- a/code/lib/cli/src/automigrate/fixes/incompatible-addons.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { describe, afterEach, it, expect, vi } from 'vitest'; - -import type { StorybookConfig } from '@storybook/types'; -import { incompatibleAddons } from './incompatible-addons'; -import type { JsPackageManager } from '@storybook/core-common'; - -const check = async ({ - packageManager, - main: mainConfig = {}, - storybookVersion = '7.0.0', -}: { - packageManager: Partial; - main?: Partial & Record; - storybookVersion?: string; -}) => { - return incompatibleAddons.check({ - packageManager: packageManager as any, - configDir: '', - mainConfig: mainConfig as any, - storybookVersion, - }); -}; - -describe('incompatible-addons fix', () => { - afterEach(() => { - vi.restoreAllMocks(); - }); - - it('should show incompatible addons registered in main.js', async () => { - await expect( - check({ - packageManager: { - getPackageVersion(packageName, basePath) { - switch (packageName) { - case '@storybook/addon-essentials': - return Promise.resolve('7.0.0'); - case '@storybook/addon-info': - return Promise.resolve('5.3.21'); - default: - return Promise.resolve(null); - } - }, - getAllDependencies: async () => ({}), - }, - main: { addons: ['@storybook/essentials', '@storybook/addon-info'] }, - }) - ).resolves.toEqual({ - incompatibleAddonList: [ - { - name: '@storybook/addon-info', - version: '5.3.21', - }, - ], - }); - }); - - it('should show incompatible addons from package.json', async () => { - await expect( - check({ - packageManager: { - getPackageVersion(packageName, basePath) { - switch (packageName) { - case '@storybook/addon-essentials': - return Promise.resolve('7.0.0'); - case '@storybook/addon-info': - return Promise.resolve('5.3.21'); - default: - return Promise.resolve(null); - } - }, - getAllDependencies: async () => ({ - '@storybook/addon-essentials': '7.0.0', - '@storybook/addon-info': '5.3.21', - }), - }, - main: { addons: [] }, - }) - ).resolves.toEqual({ - incompatibleAddonList: [ - { - name: '@storybook/addon-info', - version: '5.3.21', - }, - ], - }); - }); - - it('no-op when there are no incompatible addons', async () => { - await expect( - check({ - packageManager: { - getPackageVersion(packageName, basePath) { - switch (packageName) { - case '@storybook/addon-essentials': - return Promise.resolve('7.0.0'); - default: - return Promise.resolve(null); - } - }, - getAllDependencies: async () => ({}), - }, - main: { addons: ['@storybook/essentials'] }, - }) - ).resolves.toBeNull(); - }); -}); diff --git a/code/lib/cli/src/automigrate/fixes/incompatible-addons.ts b/code/lib/cli/src/automigrate/fixes/incompatible-addons.ts deleted file mode 100644 index fdf1c9678763..000000000000 --- a/code/lib/cli/src/automigrate/fixes/incompatible-addons.ts +++ /dev/null @@ -1,34 +0,0 @@ -import chalk from 'chalk'; -import dedent from 'ts-dedent'; -import type { Fix } from '../types'; -import { getIncompatibleAddons } from '../../doctor/getIncompatibleAddons'; - -interface IncompatibleAddonsOptions { - incompatibleAddonList: { name: string; version: string }[]; -} - -export const incompatibleAddons: Fix = { - id: 'incompatible-addons', - promptType: 'manual', - versionRange: ['*', '*'], - - async check({ mainConfig, packageManager }) { - const incompatibleAddonList = await getIncompatibleAddons(mainConfig, packageManager); - - return incompatibleAddonList.length > 0 ? { incompatibleAddonList } : null; - }, - prompt({ incompatibleAddonList }) { - return dedent` - ${chalk.bold( - 'Attention' - )}: We've detected that you're using the following addons in versions which are known to be incompatible with Storybook 8: - - ${incompatibleAddonList - .map(({ name, version }) => `- ${chalk.cyan(`${name}@${version}`)}`) - .join('\n')} - - Please be aware they might not work in Storybook 8. Reach out to their maintainers for updates and check the following Github issue for more information: - ${chalk.yellow('https://github.com/storybookjs/storybook/issues/26031')} - `; - }, -}; diff --git a/code/lib/cli/src/automigrate/helpers/getMigrationSummary.test.ts b/code/lib/cli/src/automigrate/helpers/getMigrationSummary.test.ts index f5bd5a74fa0d..f43e84370852 100644 --- a/code/lib/cli/src/automigrate/helpers/getMigrationSummary.test.ts +++ b/code/lib/cli/src/automigrate/helpers/getMigrationSummary.test.ts @@ -152,12 +152,12 @@ describe('getMigrationSummary', () => { - You can find more information for a given dependency by running yarn why + Please try de-duplicating these dependencies by running yarn dedupe - Please try de-duplicating these dependencies by running yarn dedupe" + You can find more information for a given dependency by running yarn why " `); }); diff --git a/code/lib/cli/src/automigrate/index.ts b/code/lib/cli/src/automigrate/index.ts index 92d21e2ec6c2..b0864a7071c6 100644 --- a/code/lib/cli/src/automigrate/index.ts +++ b/code/lib/cli/src/automigrate/index.ts @@ -27,6 +27,7 @@ import { FixStatus, allFixes } from './fixes'; import { cleanLog } from './helpers/cleanLog'; import { getMigrationSummary } from './helpers/getMigrationSummary'; import { getStorybookData } from './helpers/mainConfigFile'; +import { doctor } from '../doctor'; const logger = console; const LOG_FILE_NAME = 'migration-storybook.log'; @@ -83,7 +84,7 @@ export const doAutomigrate = async (options: AutofixOptionsFromCLI) => { throw new Error('Could not determine main config path'); } - return automigrate({ + await automigrate({ ...options, packageManager, storybookVersion, @@ -92,6 +93,8 @@ export const doAutomigrate = async (options: AutofixOptionsFromCLI) => { configDir, isUpgrade: false, }); + + await doctor({ configDir, packageManager: options.packageManager }); }; export const automigrate = async ({ diff --git a/code/lib/cli/src/doctor/getDuplicatedDepsWarnings.ts b/code/lib/cli/src/doctor/getDuplicatedDepsWarnings.ts index d76c01d9ee97..272313300728 100644 --- a/code/lib/cli/src/doctor/getDuplicatedDepsWarnings.ts +++ b/code/lib/cli/src/doctor/getDuplicatedDepsWarnings.ts @@ -101,15 +101,15 @@ export function getDuplicatedDepsWarnings( messages.push( '\n', - `You can find more information for a given dependency by running ${chalk.cyan( - `${installationMetadata.infoCommand} ` + `Please try de-duplicating these dependencies by running ${chalk.cyan( + `${installationMetadata.dedupeCommand}` )}` ); messages.push( '\n', - `Please try de-duplicating these dependencies by running ${chalk.cyan( - `${installationMetadata.dedupeCommand}` + `You can find more information for a given dependency by running ${chalk.cyan( + `${installationMetadata.infoCommand} ` )}` ); diff --git a/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.test.ts b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.test.ts new file mode 100644 index 000000000000..5d5a2d8a6e87 --- /dev/null +++ b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.test.ts @@ -0,0 +1,158 @@ +import { describe, it, expect, vi } from 'vitest'; +import type { AnalysedPackage } from './getIncompatibleStorybookPackages'; +import { + getIncompatibleStorybookPackages, + getIncompatiblePackagesSummary, + checkPackageCompatibility, +} from './getIncompatibleStorybookPackages'; +import type { JsPackageManager } from '@storybook/core-common'; + +vi.mock('chalk', () => { + return { + default: { + yellow: (str: string) => str, + cyan: (str: string) => str, + bold: (str: string) => str, + }, + }; +}); + +vi.mock('./utils', () => ({ + getPackageJsonPath: vi.fn(() => Promise.resolve('package.json')), + getPackageJsonOfDependency: vi.fn(() => Promise.resolve({})), + PackageJsonNotFoundError: Error, +})); + +const packageManagerMock = { + getAllDependencies: () => + Promise.resolve({ + '@storybook/addon-essentials': '7.0.0', + }), + latestVersion: vi.fn(() => Promise.resolve('8.0.0')), + getPackageJSON: vi.fn(() => Promise.resolve('8.0.0')), +} as any as JsPackageManager; + +describe('checkPackageCompatibility', () => { + it('returns that a package is incompatible', async () => { + const packageName = 'my-storybook-package'; + vi.mocked(packageManagerMock.getPackageJSON).mockResolvedValueOnce({ + name: packageName, + version: '1.0.0', + dependencies: { + '@storybook/core-common': '7.0.0', + }, + }); + const result = await checkPackageCompatibility(packageName, { + currentStorybookVersion: '8.0.0', + packageManager: packageManagerMock as JsPackageManager, + }); + expect(result).toEqual( + expect.objectContaining({ + packageName: 'my-storybook-package', + packageVersion: '1.0.0', + hasIncompatibleDependencies: true, + }) + ); + }); + + it('returns that a package is compatible', async () => { + const packageName = 'my-storybook-package'; + vi.mocked(packageManagerMock.getPackageJSON).mockResolvedValueOnce({ + name: packageName, + version: '1.0.0', + dependencies: { + '@storybook/core-common': '8.0.0', + }, + }); + const result = await checkPackageCompatibility(packageName, { + currentStorybookVersion: '8.0.0', + packageManager: packageManagerMock as JsPackageManager, + }); + expect(result).toEqual( + expect.objectContaining({ + packageName: 'my-storybook-package', + packageVersion: '1.0.0', + hasIncompatibleDependencies: false, + }) + ); + }); + + it('returns that a package is incompatible and because it is core, can be upgraded', async () => { + const packageName = '@storybook/addon-essentials'; + + vi.mocked(packageManagerMock.getPackageJSON).mockResolvedValueOnce({ + name: packageName, + version: '7.0.0', + dependencies: { + '@storybook/core-common': '7.0.0', + }, + }); + + const result = await checkPackageCompatibility(packageName, { + currentStorybookVersion: '8.0.0', + packageManager: packageManagerMock, + }); + + expect(result).toEqual( + expect.objectContaining({ + packageName: '@storybook/addon-essentials', + packageVersion: '7.0.0', + hasIncompatibleDependencies: true, + availableUpdate: '8.0.0', + }) + ); + }); +}); + +describe('getIncompatibleStorybookPackages', () => { + it('returns an array of incompatible packages', async () => { + vi.mocked(packageManagerMock.getPackageJSON).mockResolvedValueOnce({ + name: '@storybook/addon-essentials', + version: '7.0.0', + dependencies: { + '@storybook/core-common': '7.0.0', + }, + }); + + const result = await getIncompatibleStorybookPackages({ + currentStorybookVersion: '8.0.0', + packageManager: packageManagerMock as JsPackageManager, + }); + + expect(result).toEqual([ + expect.objectContaining({ + packageName: '@storybook/addon-essentials', + hasIncompatibleDependencies: true, + }), + ]); + }); +}); + +describe('getIncompatiblePackagesSummary', () => { + it('generates a summary message for incompatible packages', () => { + const analysedPackages: AnalysedPackage[] = [ + { + packageName: 'storybook-react', + packageVersion: '1.0.0', + hasIncompatibleDependencies: true, + }, + { + packageName: '@storybook/addon-essentials', + packageVersion: '7.0.0', + hasIncompatibleDependencies: true, + availableUpdate: '8.0.0', + }, + ]; + const summary = getIncompatiblePackagesSummary(analysedPackages, '8.0.0'); + expect(summary).toMatchInlineSnapshot(` + "The following packages are incompatible with Storybook 8.0.0 as they depend on different major versions of Storybook packages: + - storybook-react@1.0.0 + - @storybook/addon-essentials@7.0.0 (8.0.0 available!) + + + Please consider updating your packages or contacting the maintainers for compatibility details. + For more on Storybook 8 compatibility, see the linked GitHub issue: + https://github.com/storybookjs/storybook/issues/26031" + `); + }); +}); diff --git a/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts new file mode 100644 index 000000000000..d481fae93c82 --- /dev/null +++ b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts @@ -0,0 +1,135 @@ +/* eslint-disable local-rules/no-uncategorized-errors */ +import chalk from 'chalk'; +import semver from 'semver'; +import type { JsPackageManager } from '@storybook/core-common'; +import { JsPackageManagerFactory, versions as storybookCorePackages } from '@storybook/core-common'; + +export type AnalysedPackage = { + packageName: string; + packageVersion?: string; + homepage?: string; + hasIncompatibleDependencies?: boolean; + availableUpdate?: string; +}; + +type Context = { + currentStorybookVersion: string; + packageManager: JsPackageManager; + skipUpgradeCheck?: boolean; + skipErrors?: boolean; +}; + +const isPackageIncompatible = (installedVersion: string, currentStorybookVersion: string) => { + const storybookVersion = semver.coerce(currentStorybookVersion); + const packageVersion = semver.coerce(installedVersion); + return storybookVersion?.major !== packageVersion?.major; +}; + +export const checkPackageCompatibility = async (dependency: string, context: Context) => { + const { currentStorybookVersion, skipErrors, packageManager } = context; + try { + const dependencyPackageJson = await packageManager.getPackageJSON(dependency); + if (dependencyPackageJson === null) { + return { packageName: dependency }; + } + + const { + version: packageVersion, + name = dependency, + dependencies, + peerDependencies, + homepage, + } = dependencyPackageJson; + + const hasIncompatibleDependencies = !!Object.entries({ + ...dependencies, + ...peerDependencies, + }) + .filter(([dep]) => storybookCorePackages[dep as keyof typeof storybookCorePackages]) + .find(([, version]) => { + // prevent issues with "tag" based versions e.g. "latest" or "next" instead of actual numbers + return ( + version && + semver.validRange(version) && + isPackageIncompatible(version, currentStorybookVersion) + ); + }); + + const isCorePackage = storybookCorePackages[name as keyof typeof storybookCorePackages]; + + let availableUpdate; + + // For now, we notify about updates only for core packages (which will match the currently installed storybook version) + // In the future, we can use packageManager.latestVersion(name, constraint) for all packages + if (isCorePackage && semver.gt(currentStorybookVersion, packageVersion!)) { + availableUpdate = currentStorybookVersion; + } + + return { + packageName: name, + packageVersion, + homepage, + hasIncompatibleDependencies, + availableUpdate, + }; + } catch (err) { + if (!skipErrors) { + console.log(`Error checking compatibility for ${dependency}, please report an issue:\n`, err); + } + return { packageName: dependency }; + } +}; + +export const getIncompatibleStorybookPackages = async ( + context: Omit & Partial> +): Promise => { + const packageManager = context.packageManager ?? JsPackageManagerFactory.getPackageManager(); + + const allDeps = await packageManager.getAllDependencies(); + const storybookLikeDeps = Object.keys(allDeps).filter((dep) => dep.includes('storybook')); + + if (storybookLikeDeps.length === 0) { + throw new Error('No Storybook dependencies found in the package.json'); + } + + return Promise.all( + storybookLikeDeps.map((dep) => checkPackageCompatibility(dep, { ...context, packageManager })) + ); +}; + +export const getIncompatiblePackagesSummary = ( + dependencyAnalysis: AnalysedPackage[], + currentStorybookVersion: string +) => { + const summaryMessage: string[] = []; + + const incompatiblePackages = dependencyAnalysis.filter( + (dep) => dep.hasIncompatibleDependencies + ) as AnalysedPackage[]; + + if (incompatiblePackages.length > 0) { + summaryMessage.push( + `The following packages are incompatible with Storybook ${chalk.bold( + currentStorybookVersion + )} as they depend on different major versions of Storybook packages:` + ); + incompatiblePackages.forEach( + ({ packageName: addonName, packageVersion: addonVersion, homepage, availableUpdate }) => { + const packageDescription = `${chalk.cyan(addonName)}@${chalk.cyan(addonVersion)}`; + const updateMessage = availableUpdate ? ` (${availableUpdate} available!)` : ''; + const packageRepo = homepage ? `\n Repo: ${chalk.yellow(homepage)}` : ''; + + summaryMessage.push(`- ${packageDescription}${updateMessage}${packageRepo}`); + } + ); + + summaryMessage.push( + '\n', + 'Please consider updating your packages or contacting the maintainers for compatibility details.', + 'For more on Storybook 8 compatibility, see the linked GitHub issue:', + chalk.yellow('https://github.com/storybookjs/storybook/issues/26031') + ); + } + + return summaryMessage.join('\n'); +}; diff --git a/code/lib/cli/src/doctor/getMismatchingVersionsWarning.ts b/code/lib/cli/src/doctor/getMismatchingVersionsWarning.ts index 18f0008c537f..f8c9e0874a0f 100644 --- a/code/lib/cli/src/doctor/getMismatchingVersionsWarning.ts +++ b/code/lib/cli/src/doctor/getMismatchingVersionsWarning.ts @@ -75,7 +75,7 @@ export function getMismatchingVersionsWarnings( if (filteredDependencies.length > 0) { const packageJsonSuffix = '(in your package.json)'; messages.push( - `Based on your lockfile, these dependencies should be upgraded:`, + `Based on your lockfile, these dependencies should be aligned:`, filteredDependencies .map( ([name, dep]) => diff --git a/code/lib/cli/src/doctor/index.ts b/code/lib/cli/src/doctor/index.ts index 9aaeede8bc0f..69884c2f6755 100644 --- a/code/lib/cli/src/doctor/index.ts +++ b/code/lib/cli/src/doctor/index.ts @@ -9,10 +9,13 @@ import { JsPackageManagerFactory } from '@storybook/core-common'; import type { PackageManagerName } from '@storybook/core-common'; import { getStorybookData } from '../automigrate/helpers/mainConfigFile'; import { cleanLog } from '../automigrate/helpers/cleanLog'; -import { incompatibleAddons } from '../automigrate/fixes/incompatible-addons'; -import { getDuplicatedDepsWarnings } from './getDuplicatedDepsWarnings'; -import { getIncompatibleAddons } from './getIncompatibleAddons'; import { getMismatchingVersionsWarnings } from './getMismatchingVersionsWarning'; +import { + getIncompatiblePackagesSummary, + getIncompatibleStorybookPackages, +} from './getIncompatibleStorybookPackages'; +import { getDuplicatedDepsWarnings } from './getDuplicatedDepsWarnings'; +import { isPrerelease } from './utils'; const logger = console; const LOG_FILE_NAME = 'doctor-storybook.log'; @@ -50,9 +53,21 @@ export const doctor = async ({ packageManager: pkgMgr, }: DoctorOptions = {}) => { augmentLogsToFile(); - const diagnosticMessages: string[] = []; - logger.info('🩺 checking the health of your Storybook..'); + let foundIssues = false; + const logDiagnostic = (title: string, message: string) => { + foundIssues = true; + logger.info( + boxen(message, { + borderStyle: 'round', + padding: 1, + title, + borderColor: '#F1618C', + }) + ); + }; + + logger.info('🩺 The doctor is checking the health of your Storybook..'); const packageManager = JsPackageManagerFactory.getPackageManager({ force: pkgMgr }); let storybookVersion; @@ -89,9 +104,17 @@ export const doctor = async ({ throw new Error('mainConfig is undefined'); } - const incompatibleAddonList = await getIncompatibleAddons(mainConfig); - if (incompatibleAddonList.length > 0) { - diagnosticMessages.push(incompatibleAddons.prompt({ incompatibleAddonList })); + const allDependencies = (await packageManager.getAllDependencies()) as Record; + + const incompatibleStorybookPackagesList = await getIncompatibleStorybookPackages({ + currentStorybookVersion: storybookVersion, + }); + const incompatiblePackagesMessage = getIncompatiblePackagesSummary( + incompatibleStorybookPackagesList, + storybookVersion + ); + if (incompatiblePackagesMessage) { + logDiagnostic('Incompatible packages found', incompatiblePackagesMessage); } const installationMetadata = await packageManager.findInstallations([ @@ -99,39 +122,44 @@ export const doctor = async ({ 'storybook', ]); - const allDependencies = (await packageManager.getAllDependencies()) as Record; - const mismatchingVersionMessage = getMismatchingVersionsWarnings( - installationMetadata, - allDependencies - ); - if (mismatchingVersionMessage) { - diagnosticMessages.push(mismatchingVersionMessage); - } else { - const list = installationMetadata - ? getDuplicatedDepsWarnings(installationMetadata) - : getDuplicatedDepsWarnings(); - if (list) { - diagnosticMessages.push(list?.join('\n')); + // If we found incompatible packages, we let the users fix that first + // If they run doctor again and there are still issues, we show the other warnings + if (!incompatiblePackagesMessage) { + const mismatchingVersionMessage = getMismatchingVersionsWarnings( + installationMetadata, + allDependencies + ); + if (mismatchingVersionMessage) { + logDiagnostic('Diagnostics', [mismatchingVersionMessage].join('\n\n-------\n\n')); + } else { + const list = installationMetadata + ? getDuplicatedDepsWarnings(installationMetadata) + : getDuplicatedDepsWarnings(); + if (Array.isArray(list) && list.length > 0) { + logDiagnostic('Duplicated dependencies found', list?.join('\n')); + } } } + + const doctorCommand = isPrerelease(storybookVersion) + ? 'npx storybook@next doctor' + : 'npx storybook@latest doctor'; + + const commandMessage = `You can always recheck the health of your project by running:\n${chalk.cyan( + doctorCommand + )}`; logger.info(); - const finalMessages = diagnosticMessages.filter(Boolean); + if (foundIssues) { + logger.info(commandMessage); + logger.info(); - if (finalMessages.length > 0) { - finalMessages.push(`You can find the full logs in ${chalk.cyan(LOG_FILE_PATH)}`); + logger.info(`Full logs are available in ${chalk.cyan(LOG_FILE_PATH)}`); - logger.info( - boxen(finalMessages.join('\n\n-------\n\n'), { - borderStyle: 'round', - padding: 1, - title: 'Diagnostics', - borderColor: 'red', - }) - ); await move(TEMP_LOG_FILE_PATH, join(process.cwd(), LOG_FILE_NAME), { overwrite: true }); } else { - logger.info('🥳 Your Storybook project looks good!'); + logger.info(`🥳 Your Storybook project looks good!`); + logger.info(commandMessage); await remove(TEMP_LOG_FILE_PATH); } logger.info(); diff --git a/code/lib/cli/src/doctor/utils.ts b/code/lib/cli/src/doctor/utils.ts new file mode 100644 index 000000000000..65963febaa2f --- /dev/null +++ b/code/lib/cli/src/doctor/utils.ts @@ -0,0 +1,3 @@ +export const isPrerelease = (version: string) => { + return version.includes('-'); +}; diff --git a/code/lib/core-server/src/build-dev.ts b/code/lib/core-server/src/build-dev.ts index b55b5e22b8a7..de47bcd7a575 100644 --- a/code/lib/core-server/src/build-dev.ts +++ b/code/lib/core-server/src/build-dev.ts @@ -89,7 +89,7 @@ export async function buildDevStandalone( frameworkName = frameworkName || 'custom'; try { - await warnOnIncompatibleAddons(config); + await warnOnIncompatibleAddons(packageJson.version); } catch (e) { console.warn('Storybook failed to check addon compatibility', e); } diff --git a/code/lib/core-server/src/utils/warnOnIncompatibleAddons.ts b/code/lib/core-server/src/utils/warnOnIncompatibleAddons.ts index fd4aaac39286..6d7359a21edb 100644 --- a/code/lib/core-server/src/utils/warnOnIncompatibleAddons.ts +++ b/code/lib/core-server/src/utils/warnOnIncompatibleAddons.ts @@ -1,25 +1,22 @@ -import type { StorybookConfig } from '@storybook/types'; import { logger } from '@storybook/node-logger'; -import chalk from 'chalk'; -import dedent from 'ts-dedent'; +import { + getIncompatibleStorybookPackages, + getIncompatiblePackagesSummary, +} from '../../../cli/src/doctor/getIncompatibleStorybookPackages'; -import { getIncompatibleAddons } from '../../../cli/src/doctor/getIncompatibleAddons'; +export const warnOnIncompatibleAddons = async (currentStorybookVersion: string) => { + const incompatiblePackagesList = await getIncompatibleStorybookPackages({ + skipUpgradeCheck: true, + skipErrors: true, + currentStorybookVersion, + }); -export const warnOnIncompatibleAddons = async (config: StorybookConfig) => { - const incompatibleAddons = await getIncompatibleAddons(config); + const incompatiblePackagesMessage = await getIncompatiblePackagesSummary( + incompatiblePackagesList, + currentStorybookVersion + ); - if (incompatibleAddons.length > 0) { - logger.warn(dedent` - ${chalk.bold( - chalk.red('Attention') - )}: We've detected that you're using the following addons in versions which are known to be incompatible with Storybook 7: - - ${incompatibleAddons - .map(({ name, version }) => `- ${chalk.cyan(`${name}@${version}`)}`) - .join('\n')} - - Please be aware they might not work in Storybook 7. Reach out to their maintainers for updates and check the following Github issue for more information: - ${chalk.yellow('https://github.com/storybookjs/storybook/issues/20529')} - `); + if (incompatiblePackagesMessage) { + logger.warn(incompatiblePackagesMessage); } };