From 9fd15f20d17fe0a74ef9b02ad9b56f33ff904380 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Wed, 28 Feb 2024 09:15:17 +0100 Subject: [PATCH] Doctor: Add dynamic check for incompatible storybook packages --- .../fixes/incompatible-addons.test.ts | 106 ------------ .../automigrate/fixes/incompatible-addons.ts | 34 ---- .../helpers/getMigrationSummary.test.ts | 36 +--- .../helpers/getMigrationSummary.ts | 10 -- code/lib/cli/src/automigrate/index.ts | 5 +- .../getIncompatibleStorybookPackages.test.ts | 122 ++++++++++++++ .../getIncompatibleStorybookPackages.ts | 155 ++++++++++++++++++ code/lib/cli/src/doctor/index.ts | 68 ++++---- code/lib/core-server/src/build-dev.ts | 2 +- .../src/utils/warnOnIncompatibleAddons.ts | 35 ++-- 10 files changed, 343 insertions(+), 230 deletions(-) delete mode 100644 code/lib/cli/src/automigrate/fixes/incompatible-addons.test.ts delete mode 100644 code/lib/cli/src/automigrate/fixes/incompatible-addons.ts create mode 100644 code/lib/cli/src/doctor/getIncompatibleStorybookPackages.test.ts create mode 100644 code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts 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 85de99111c87..f630bfe7d484 100644 --- a/code/lib/cli/src/automigrate/helpers/getMigrationSummary.test.ts +++ b/code/lib/cli/src/automigrate/helpers/getMigrationSummary.test.ts @@ -113,7 +113,8 @@ describe('getMigrationSummary', () => { `); }); - it('renders a summary with a warning if there are duplicated dependencies outside the allow list', () => { + // TODO: bring this back in case we decide to keep the duplicated deps warning + it.skip('renders a summary with a warning if there are duplicated dependencies outside the allow list', () => { const summary = getMigrationSummary({ fixResults: {}, fixSummary: { succeeded: [], failed: {}, manual: [], skipped: [] }, @@ -129,39 +130,12 @@ describe('getMigrationSummary', () => { 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: https://storybook.js.org/migration-guides/7.0 - And reach out on Discord if you need help: https://discord.gg/storybook - - ───────────────────────────────────────────────── - - Critical: The following dependencies are duplicated and WILL cause unexpected behavior: - - @storybook/instrumenter: - 6.0.0, 7.1.0 - - @storybook/core-common: - 6.0.0, 7.1.0 - - - - - Attention: The following dependencies are duplicated which might cause unexpected behavior: - - @storybook/addon-essentials: - 7.0.0, 7.1.0 - - - - - You can find more information for a given dependency by running yarn why - - - - - Please try de-duplicating these dependencies by running yarn dedupe" + And reach out on Discord if you need help: https://discord.gg/storybook" `); }); - it('renders a basic summary if there are no duplicated dependencies or migrations', () => { + // TODO: bring this back in case we decide to keep the duplicated deps warning + it.skip('renders a basic summary if there are no duplicated dependencies or migrations', () => { const summary = getMigrationSummary({ fixResults: {}, fixSummary: { succeeded: [], failed: {}, manual: [], skipped: [] }, diff --git a/code/lib/cli/src/automigrate/helpers/getMigrationSummary.ts b/code/lib/cli/src/automigrate/helpers/getMigrationSummary.ts index 1dcd0a0658c7..58179e9115f3 100644 --- a/code/lib/cli/src/automigrate/helpers/getMigrationSummary.ts +++ b/code/lib/cli/src/automigrate/helpers/getMigrationSummary.ts @@ -4,7 +4,6 @@ import dedent from 'ts-dedent'; import type { InstallationMetadata } from '@storybook/core-common'; import type { FixSummary } from '../types'; import { FixStatus } from '../types'; -import { getDuplicatedDepsWarnings } from '../../doctor/getDuplicatedDepsWarnings'; export const messageDivider = '\n\n'; const segmentDivider = '\n\n─────────────────────────────────────────────────\n\n'; @@ -53,7 +52,6 @@ export function getMigrationSummary({ fixResults, fixSummary, logFile, - installationMetadata, }: { fixResults: Record; fixSummary: FixSummary; @@ -75,14 +73,6 @@ export function getMigrationSummary({ And reach out on Discord if you need help: ${chalk.yellow('https://discord.gg/storybook')} `); - const duplicatedDepsMessage = installationMetadata - ? getDuplicatedDepsWarnings(installationMetadata) - : getDuplicatedDepsWarnings(); - - if (duplicatedDepsMessage) { - messages.push(duplicatedDepsMessage.join(messageDivider)); - } - const hasNoFixes = Object.values(fixResults).every((r) => r === FixStatus.UNNECESSARY); const hasFailures = Object.values(fixResults).some( (r) => r === FixStatus.FAILED || r === FixStatus.CHECK_FAILED 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/getIncompatibleStorybookPackages.test.ts b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.test.ts new file mode 100644 index 000000000000..e354497930f1 --- /dev/null +++ b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.test.ts @@ -0,0 +1,122 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { + getIncompatibleStorybookPackages, + getIncompatiblePackagesSummary, +} from './getIncompatibleStorybookPackages'; +import pkgUp from 'read-pkg-up'; +import type { JsPackageManager } from '@storybook/core-common'; + +vi.mock('chalk', () => { + return { + default: { + yellow: (str: string) => str, + cyan: (str: string) => str, + }, + }; +}); + +vi.mock('read-pkg-up', () => ({ + default: vi.fn(), +})); + +const packageManagerMock = { + getAllDependencies: () => + Promise.resolve({ + '@storybook/addon-essentials': '7.0.0', + }), + latestVersion: vi.fn(() => Promise.resolve('8.0.0')), +} as Partial; + +describe('getIncompatibleStorybookPackages', () => { + beforeEach(() => { + vi.resetAllMocks(); + }); + + it('returns an array of incompatible packages', async () => { + vi.mocked(pkgUp).mockResolvedValueOnce({ + packageJson: { + name: '@storybook/addon-essentials', + version: '7.0.0', + dependencies: { + '@storybook/core-common': '7.0.0', + }, + }, + path: '', + }); + + vi.mocked(packageManagerMock.latestVersion)?.mockResolvedValueOnce('8.0.0'); + + const result = await getIncompatibleStorybookPackages({ + currentStorybookVersion: '8.0.0', + packageManager: packageManagerMock as JsPackageManager, + }); + + expect(packageManagerMock.latestVersion).toHaveBeenCalled(); + expect(result).toEqual([ + { + packageName: '@storybook/addon-essentials', + packageVersion: '7.0.0', + hasIncompatibleDependencies: true, + homepage: undefined, + availableUpdate: true, + latestVersionOfPackage: '8.0.0', + }, + ]); + }); + + it('returns an array of incompatible packages without upgrade check', async () => { + vi.mocked(pkgUp).mockResolvedValueOnce({ + packageJson: { + name: '@storybook/addon-essentials', + version: '7.0.0', + dependencies: { + '@storybook/core-common': '7.0.0', + }, + }, + path: '', + }); + + const result = await getIncompatibleStorybookPackages({ + currentStorybookVersion: '8.0.0', + packageManager: packageManagerMock as JsPackageManager, + skipUpgradeCheck: true, + }); + + expect(packageManagerMock.latestVersion).not.toHaveBeenCalled(); + + expect(result).toEqual([ + { + packageName: '@storybook/addon-essentials', + packageVersion: '7.0.0', + hasIncompatibleDependencies: true, + homepage: undefined, + availableUpdate: false, + latestVersionOfPackage: undefined, + }, + ]); + }); +}); + +describe('getIncompatiblePackagesSummary', () => { + it('generates a summary message for incompatible packages', () => { + const analysedPackages = [ + { + packageName: 'storybook-react', + packageVersion: '1.0.0', + hasIncompatibleDependencies: true, + latestVersionOfPackage: '2.0.0', + availableUpdate: true, + }, + ]; + const summary = getIncompatiblePackagesSummary(analysedPackages, '7.0.0'); + expect(summary).toMatchInlineSnapshot(` + "The following addons are likely incompatible with Storybook 7.0.0: + - storybook-react@1.0.0 (2.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..e07ca9ec3489 --- /dev/null +++ b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts @@ -0,0 +1,155 @@ +/* eslint-disable local-rules/no-uncategorized-errors */ +import chalk from 'chalk'; +import semver from 'semver'; +import readPkgUp from 'read-pkg-up'; +import type { JsPackageManager } from '@storybook/core-common'; +import { JsPackageManagerFactory, versions as storybookCorePackages } from '@storybook/core-common'; + +type AnalysedPackage = { + packageName: string; + packageVersion?: string; + homepage?: string; + hasIncompatibleDependencies?: boolean; + latestVersionOfPackage?: string; + availableUpdate?: boolean; +}; + +export const getIncompatibleStorybookPackages = async ({ + currentStorybookVersion, + packageManager = JsPackageManagerFactory.getPackageManager(), + skipUpgradeCheck = false, + skipErrors = false, +}: { + currentStorybookVersion: string; + packageManager?: JsPackageManager; + skipUpgradeCheck?: boolean; + skipErrors?: boolean; +}): Promise => { + 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'); + } + + const isPackageIncompatible = (installedVersion: string) => { + const dependencyMajor = semver.coerce(installedVersion)!.major; + const storybookMajor = semver.coerce(currentStorybookVersion)!.major; + return dependencyMajor !== storybookMajor; + }; + + const checkCompatibility = async (dependency: string): Promise => { + try { + const resolvedPath = require.resolve(dependency); + const result = await readPkgUp({ cwd: resolvedPath }); + + if (!result?.packageJson) { + throw new Error(`No package.json found for ${dependency}`); + } + + const { + packageJson: { version: versionSpecifier, name, dependencies, peerDependencies, homepage }, + } = result; + const coercedVersion = new semver.SemVer(versionSpecifier); + const packageVersion = coercedVersion.version; + + const hasIncompatibleDependencies = !!Object.entries({ + ...dependencies, + ...peerDependencies, + }) + .filter(([dep]) => Object.keys(storybookCorePackages).includes(dep)) + .find(([, version]) => { + // prevent issues with "tag" based versions e.g. "latest" or "next" instead of actual numbers + return version && semver.validRange(version) && isPackageIncompatible(version); + }); + + let latestVersionOfPackage; + + if (!skipUpgradeCheck) { + try { + const isStorybookPreRelease = currentStorybookVersion.includes('-'); + // if the user is on a pre-release, we try to get the existing prereleases of all packages + if (isStorybookPreRelease) { + // this is mostly a guess that makes it work for external addons which use the next/latest release strategy + const constraint = currentStorybookVersion.includes('-') + ? `^${coercedVersion.major + 1}.0.0-alpha.0` + : `^${coercedVersion.major + 1}.0.0`; + + latestVersionOfPackage = await packageManager.latestVersion(name, constraint); + } else { + latestVersionOfPackage = await packageManager.latestVersion(name); + } + } catch (err) { + // things might not work when defining the prerelease constraint, so we fall back to "latest" + latestVersionOfPackage = await packageManager.latestVersion(name); + } + } + + return { + packageName: name, + packageVersion, + homepage, + hasIncompatibleDependencies, + latestVersionOfPackage, + availableUpdate: !!( + latestVersionOfPackage && semver.gt(latestVersionOfPackage, packageVersion) + ), + }; + } catch (err) { + // For the reviewers: When running sb doctor, this error message is only shown in the log file. + // Do we want it? maybe not? it's currently under a flag because this is also used in storybook dev and we do not want to show errors there + // We can choose to silently fail, but this has proven quite useful as some of our addons + // have faulty package.json files: @storybook/addon-onboarding, @storybook/addon-coverage + if (!skipErrors) { + console.error( + `Error checking compatibility for ${dependency}, please report an issue:\n`, + err + ); + } + return { packageName: dependency }; + } + }; + + return Promise.all(storybookLikeDeps.map((dep) => checkCompatibility(dep))); +}; + +export const getIncompatiblePackagesSummary = ( + dependencyAnalysis: AnalysedPackage[], + currentVersion: string +) => { + const summaryMessage: string[] = []; + + const incompatiblePackages = dependencyAnalysis.filter( + (dep) => dep.hasIncompatibleDependencies + ) as AnalysedPackage[]; + + if (incompatiblePackages.length > 0) { + summaryMessage.push( + `The following addons are likely incompatible with Storybook ${currentVersion}:` + ); + incompatiblePackages.forEach( + ({ + packageName: addonName, + packageVersion: addonVersion, + homepage, + availableUpdate, + latestVersionOfPackage, + }) => { + const packageDescription = `${chalk.cyan(addonName)}@${chalk.cyan(addonVersion)}`; + const updateMessage = availableUpdate ? ` (${latestVersionOfPackage} 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/index.ts b/code/lib/cli/src/doctor/index.ts index 9aaeede8bc0f..efd1b74642c5 100644 --- a/code/lib/cli/src/doctor/index.ts +++ b/code/lib/cli/src/doctor/index.ts @@ -9,10 +9,11 @@ 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'; const logger = console; const LOG_FILE_NAME = 'doctor-storybook.log'; @@ -45,14 +46,24 @@ type DoctorOptions = { packageManager?: PackageManagerName; }; +const logDiagnostic = (title: string, message: string) => { + logger.info( + boxen(message, { + borderStyle: 'round', + padding: 1, + title, + borderColor: '#F1618C', + }) + ); +}; + export const doctor = async ({ configDir: userSpecifiedConfigDir, packageManager: pkgMgr, }: DoctorOptions = {}) => { augmentLogsToFile(); - const diagnosticMessages: string[] = []; - logger.info('🩺 checking the health of your Storybook..'); + logger.info('🩺 The doctor is checking the health of your Storybook..'); const packageManager = JsPackageManagerFactory.getPackageManager({ force: pkgMgr }); let storybookVersion; @@ -89,9 +100,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,36 +118,29 @@ 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')); - } + logDiagnostic('Diagnostics', [mismatchingVersionMessage].join('\n\n-------\n\n')); } + // CHECK: Temporarily disable multiple versions warning as the incompatible packages mostly covers this + // else { + // const list = installationMetadata + // ? getDuplicatedDepsWarnings(installationMetadata) + // : getDuplicatedDepsWarnings(); + // if (list) { + // diagnosticMessages.push(list?.join('\n')); + // } + // } logger.info(); - const finalMessages = diagnosticMessages.filter(Boolean); + const foundIssues = incompatiblePackagesMessage || mismatchingVersionMessage; - if (finalMessages.length > 0) { - finalMessages.push(`You can find the full logs in ${chalk.cyan(LOG_FILE_PATH)}`); + if (foundIssues) { + logger.info(`You can find the full logs 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!'); 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); } };