diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a70cafb01a6..c1a25029e92c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 7.6.12 + +- CLI: Fix `upgrade` detecting the wrong version of existing Storybooks - [#25752](https://github.com/storybookjs/storybook/pull/25752), thanks [@JReinhold](https://github.com/JReinhold)! + ## 7.6.11 - CLI: Update init for react native v7 - [#25780](https://github.com/storybookjs/storybook/pull/25780), thanks [@dannyhw](https://github.com/dannyhw)! diff --git a/code/lib/cli/src/upgrade.test.ts b/code/lib/cli/src/upgrade.test.ts index 56827546b548..7252e3ad6ba4 100644 --- a/code/lib/cli/src/upgrade.test.ts +++ b/code/lib/cli/src/upgrade.test.ts @@ -1,4 +1,3 @@ -import { getStorybookCoreVersion } from '@storybook/telemetry'; import { UpgradeStorybookToLowerVersionError, UpgradeStorybookToSameVersionError, @@ -16,6 +15,20 @@ jest.mock('./versions', () => { }; }); +const findInstallationsMock = jest.fn(); + +jest.mock('./js-package-manager', () => { + const originalModule = jest.requireActual('./js-package-manager'); + return { + ...originalModule, + JsPackageManagerFactory: { + getPackageManager: () => ({ + findInstallations: findInstallationsMock, + }), + }, + }; +}); + describe.each([ ['│ │ │ ├── @babel/code-frame@7.10.3 deduped', null], [ @@ -39,13 +52,37 @@ describe.each([ describe('Upgrade errors', () => { it('should throw an error when upgrading to a lower version number', async () => { - jest.mocked(getStorybookCoreVersion).mockResolvedValue('8.1.0'); + findInstallationsMock.mockResolvedValue({ + dependencies: { + '@storybook/cli': [ + { + version: '8.1.0', + }, + ], + }, + duplicatedDependencies: {}, + infoCommand: '', + dedupeCommand: '', + }); await expect(doUpgrade({} as any)).rejects.toThrowError(UpgradeStorybookToLowerVersionError); + expect(findInstallationsMock).toHaveBeenCalledWith(['storybook', '@storybook/cli']); }); it('should throw an error when upgrading to the same version number', async () => { - jest.mocked(getStorybookCoreVersion).mockResolvedValue('8.0.0'); + findInstallationsMock.mockResolvedValue({ + dependencies: { + '@storybook/cli': [ + { + version: '8.0.0', + }, + ], + }, + duplicatedDependencies: {}, + infoCommand: '', + dedupeCommand: '', + }); await expect(doUpgrade({} as any)).rejects.toThrowError(UpgradeStorybookToSameVersionError); + expect(findInstallationsMock).toHaveBeenCalledWith(['storybook', '@storybook/cli']); }); }); diff --git a/code/lib/cli/src/upgrade.ts b/code/lib/cli/src/upgrade.ts index 5537d3fe6b2a..e222e2603c44 100644 --- a/code/lib/cli/src/upgrade.ts +++ b/code/lib/cli/src/upgrade.ts @@ -1,5 +1,5 @@ import { sync as spawnSync } from 'cross-spawn'; -import { telemetry, getStorybookCoreVersion } from '@storybook/telemetry'; +import { telemetry } from '@storybook/telemetry'; import semver, { coerce, eq, lt } from 'semver'; import { deprecate, logger } from '@storybook/node-logger'; import { withTelemetry } from '@storybook/core-server'; @@ -11,7 +11,11 @@ import { import chalk from 'chalk'; import dedent from 'ts-dedent'; import boxen from 'boxen'; -import type { PackageJsonWithMaybeDeps, PackageManagerName } from './js-package-manager'; +import type { + JsPackageManager, + PackageJsonWithMaybeDeps, + PackageManagerName, +} from './js-package-manager'; import { JsPackageManagerFactory, getPackageDetails, useNpmWarning } from './js-package-manager'; import { commandLog } from './helpers'; import { automigrate } from './automigrate'; @@ -34,6 +38,18 @@ export const getStorybookVersion = (line: string) => { }; }; +const getInstalledStorybookVersion = async (packageManager: JsPackageManager) => { + const installations = await packageManager.findInstallations(['storybook', '@storybook/cli']); + if (!installations) { + return undefined; + } + const cliVersion = installations.dependencies['@storybook/cli']?.[0].version; + if (cliVersion) { + return cliVersion; + } + return installations.dependencies['storybook']?.[0].version; +}; + const deprecatedPackages = [ { minVersion: '6.0.0-alpha.0', @@ -91,9 +107,7 @@ export const checkVersionConsistency = () => { }); }; -/** - * DEPRECATED BEHAVIOR SECTION - */ +// #region DEPRECATED BEHAVIOR SECTION type ExtraFlags = Record; const EXTRA_FLAGS: ExtraFlags = { @@ -170,7 +184,8 @@ export const deprecatedUpgrade = async ({ } const packageManager = JsPackageManagerFactory.getPackageManager({ force: pkgMgr }); - const beforeVersion = await getStorybookCoreVersion(); + // If we can't determine the existing version fallback to v0.0.0 to not block the upgrade + const beforeVersion = (await getInstalledStorybookVersion(packageManager)) ?? '0.0.0'; commandLog(`Checking for latest versions of '@storybook/*' packages`); @@ -221,7 +236,7 @@ export const deprecatedUpgrade = async ({ automigrationResults = await automigrate({ dryRun, yes, packageManager: pkgMgr, configDir }); } if (!options.disableTelemetry) { - const afterVersion = await getStorybookCoreVersion(); + const afterVersion = await getInstalledStorybookVersion(packageManager); const { preCheckFailure, fixResults } = automigrationResults || {}; const automigrationTelemetry = { automigrationResults: preCheckFailure ? null : fixResults, @@ -237,9 +252,7 @@ export const deprecatedUpgrade = async ({ } }; -/** - * DEPRECATED BEHAVIOR SECTION END - */ +// #endregion DEPRECATED BEHAVIOR SECTION export interface UpgradeOptions { /** @@ -292,8 +305,9 @@ export const doUpgrade = async ({ const packageManager = JsPackageManagerFactory.getPackageManager({ force: pkgMgr }); - // If we can't determine the existing version (Yarn PnP), fallback to v0.0.0 to not block the upgrade - const beforeVersion = (await getStorybookCoreVersion()) ?? '0.0.0'; + // If we can't determine the existing version fallback to v0.0.0 to not block the upgrade + const beforeVersion = (await getInstalledStorybookVersion(packageManager)) ?? '0.0.0'; + const currentVersion = versions['@storybook/cli']; const isCanary = currentVersion.startsWith('0.0.0'); @@ -385,7 +399,7 @@ export const doUpgrade = async ({ automigrationResults = await automigrate({ dryRun, yes, packageManager: pkgMgr, configDir }); } if (!options.disableTelemetry) { - const afterVersion = await getStorybookCoreVersion(); + const afterVersion = await getInstalledStorybookVersion(packageManager); const { preCheckFailure, fixResults } = automigrationResults || {}; const automigrationTelemetry = { automigrationResults: preCheckFailure ? null : fixResults, diff --git a/code/lib/telemetry/src/index.ts b/code/lib/telemetry/src/index.ts index cd5e81dd83c2..5a318cd91b64 100644 --- a/code/lib/telemetry/src/index.ts +++ b/code/lib/telemetry/src/index.ts @@ -11,8 +11,6 @@ export * from './storybook-metadata'; export * from './types'; -export { getStorybookCoreVersion } from './package-json'; - export { getPrecedingUpgrade } from './event-cache'; export { addToGlobalContext } from './telemetry'; diff --git a/code/lib/telemetry/src/package-json.ts b/code/lib/telemetry/src/package-json.ts index 56e6823b5920..fe860382dd7f 100644 --- a/code/lib/telemetry/src/package-json.ts +++ b/code/lib/telemetry/src/package-json.ts @@ -27,9 +27,3 @@ export const getActualPackageJson = async (packageName: string) => { const packageJson = await fs.readJson(resolvedPackageJson); return packageJson; }; - -// Note that this probably doesn't work in Yarn PNP mode because @storybook/telemetry doesn't depend on @storybook/cli -export const getStorybookCoreVersion = async () => { - const { version } = await getActualPackageVersion('@storybook/cli'); - return version; -}; diff --git a/code/package.json b/code/package.json index ab8c7f26f8ce..057086fcdbcc 100644 --- a/code/package.json +++ b/code/package.json @@ -329,5 +329,6 @@ "Dependency Upgrades" ] ] - } + }, + "deferredNextVersion": "7.6.12" } diff --git a/docs/api/cli-options.md b/docs/api/cli-options.md index 1ccbb4d1f124..8b2a0f58cae3 100644 --- a/docs/api/cli-options.md +++ b/docs/api/cli-options.md @@ -14,6 +14,12 @@ Storybook collects completely anonymous data to help us improve user experience. All of the following documentation is available in the CLI by running `storybook --help`. + + +Passing options to these commands works slightly differently if you're using npm instead of Yarn. You must prefix all of your options with `--`. For example, `npm run storybook build -- -o ./path/to/build --quiet`. + + + ### `dev` Compiles and serves a development build of your Storybook that reflects your source code changes in the browser in real time. Should be run from the root of your project. @@ -76,8 +82,152 @@ Options include: | `--disable-telemetry` | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.md).
`storybook build --disable-telemetry` | | `--test` | Optimize Storybook's production build for performance and tests by removing unnecessary features with the `test` option. Learn more [here](../api/main-config-build.md).
`storybook build --test` | - + + +### `init` + +Installs and initializes the specified version (e.g., `@latest`, `@8`, `@next`) of Storybook into your project. Read more in the [installation guide](../get-started/install.md). + +```shell +storybook[@version] init [options] +``` + +For example, `storybook@latest init` will install the latest version of Storybook into your project. + +Options include: + +| Option | Description | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `-b`, `--builder` | Defines the [builder](../builders/index.md) to use for your Storybook instance
`storybook init --builder webpack5` | +| `-f`,`--force` | Forcefully installs Storybook into your project, prompting you to overwrite existing files
`storybook init --force` | +| `-s`, `--skip-install` | Skips the dependency installation step. Used only when you need to configure Storybook manually
`storybook init --skip-install` | +| `-t`, `--type` | Defines the [framework](../configure/frameworks.md) to use for your Storybook instance
`storybook init --type solid` | +| `-y`, `--yes` | Skips interactive prompts and automatically installs Storybook per specified version
`storybook init --yes` | +| `--package-manager` | Sets the package manager to use when installing the addon.
Available package managers include `npm`, `yarn`, and `pnpm`
`storybook init --package-manager pnpm` | +| `--use-pnp` | Enables [Plug'n'Play](https://yarnpkg.com/features/pnp) support for Yarn. This option is only available when using Yarn as your package manager
`storybook init --use-pnp` | + +### `add` + +Installs a Storybook addon and configures your project for it. Read more in the [addon installation guide](../addons/install-addons.md). + +```shell +storybook add [addon] [options] +``` + +Options include: + +| Option | Description | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--package-manager` | Sets the package manager to use when installing the addon.
Available package managers include `npm`, `yarn`, and `pnpm`
`storybook add [addon] --package-manager pnpm` | +| `-s`, `--skip-postinstall` | Skips post-install configuration. Used only when you need to configure the addon yourself
`storybook add [addon] --skip-postinstall` | + +### `remove` + +Deletes a Storybook addon from your project. Read more in the [addon installation guide](../addons/install-addons.md#removing-addons). + +```shell +storybook remove [addon] [options] +``` + +Options include: + +| Option | Description | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--package-manager` | Sets the package manager to use when removing the addon.
Available package managers include `npm`, `yarn`, and `pnpm`
`storybook remove [addon]--package-manager pnpm` | + +### `upgrade` + +Upgrades your Storybook instance to the specified version (e.g., `@latest`, `@8`, `@next`). Read more in the [upgrade guide](../configure/upgrading.md). + +```shell +storybook[@version] upgrade [options] +``` + +For example, `storybook@latest upgrade --dry-run` will perform a dry run (no actual changes) of upgrading your project to the latest version of Storybook. + +Options include: + +| Option | Description | +| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `-c`, `--config-dir` | Directory where to load Storybook configurations from
`storybook upgrade --config-dir .storybook` | +| `-n`, `--dry-run` | Checks for version upgrades without installing them
`storybook upgrade --dry-run` | +| `-s`, `--skip-check` | Skips the migration check step during the upgrade process
`storybook upgrade --skip-check` | +| `-y`, `--yes` | Skips interactive prompts and automatically upgrades Storybook to the latest version
`storybook upgrade --yes` | +| `--package-manager` | Sets the package manager to use when installing the addon.
Available package managers include `npm`, `yarn`, and `pnpm`
`storybook upgrade --package-manager pnpm` | + +### `doctor` + +Performs a health check on your Storybook project for common issues (e.g., duplicate dependencies, incompatible addons or mismatched versions) and provides suggestions on how to fix them. Applicable when [upgrading](../configure/upgrading.md#verifying-the-upgrade) Storybook versions. + +```shell +storybook doctor [options] +``` + +Options include: + +| Option | Description | +| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `-c`, `--config-dir` | Directory where to load Storybook configurations from
`storybook doctor --config-dir .storybook` | +| `--package-manager` | Sets the package manager to use when running the health check.
Available package managers include `npm`, `yarn`, and `pnpm`
`storybook doctor --package-manager pnpm` | + +### `info` + +Reports useful debugging information about your environment. Helpful in providing information when opening an issue or a discussion. + +```shell +storybook info +``` + +Example output: + +```shell +Storybook Environment Info: + + System: + OS: macOS 14.2 + CPU: (8) arm64 Apple M3 + Shell: 5.9 - /bin/zsh + Binaries: + Node: 18.19.0 - ~/.nvm/versions/node/v18.19.0/bin/node + npm: 10.2.3 - ~/.nvm/versions/node/v18.19.0/bin/npm <----- active + Browsers: + Chrome: 120.0.6099.199 + npmPackages: + @storybook/addon-essentials: ^7.6.6 => 7.6.6 + @storybook/addon-interactions: ^7.6.6 => 7.6.6 + @storybook/addon-links: ^7.6.6 => 7.6.6 + @storybook/addon-onboarding: ^1.0.10 => 1.0.10 + @storybook/blocks: ^7.6.6 => 7.6.6 + @storybook/preset-create-react-app: ^7.6.6 => 7.6.6 + @storybook/react: ^7.6.6 => 7.6.6 + @storybook/react-webpack5: ^7.6.6 => 7.6.6 + @storybook/test: ^7.6.6 => 7.6.6 + storybook: ^7.6.6 => 7.6.6 + npmGlobalPackages: + chromatic: ^10.2.0 => 10.2.0 +``` + +### `sandbox` + +Generates a local sandbox project using the specified version (e.g., `@latest`, `@8`, `@next`) for testing Storybook features based on the list of supported [frameworks](../configure/frameworks.md). Useful for reproducing bugs when opening an issue or a discussion. + +```shell +storybook[@version] sandbox [framework-filter] [options] +``` + +For example, `storybook@next sandbox` will generated sandboxes using the newest pre-release version of Storybook. + +The `framework-filter` argument is optional and can filter the list of available frameworks. For example, `storybook@next sandbox react` will only offer to generate React-based sandboxes. + +Options include: + +| Option | Description | +| --------------------------- | ---------------------------------------------------------------------------------------------------- | +| `-o`, `--output [dir-name]` | Configures the location of the sandbox project
`storybook sandbox --output /my-sandbox-project` | +| `--no-init` | Generates a sandbox project without without initializing Storybook
`storybook sandbox --no-init` | + + -If you're using npm instead of yarn to publish Storybook, the commands work slightly different. For example, `npm run storybook build -- -o ./path/to/build`. +If you're looking for a hosted version of the available sandboxes, see [storybook.new](https://storybook.new). diff --git a/docs/configure/upgrading.md b/docs/configure/upgrading.md index c5e57d8d714e..4ed46c2e6553 100644 --- a/docs/configure/upgrading.md +++ b/docs/configure/upgrading.md @@ -22,10 +22,16 @@ To help ease the pain of keeping Storybook up-to-date, we provide a command-line -After running the command the script will: +The `upgrade` command will use whichever version you specify. For example: -- Upgrade all Storybook packages in your project to the latest stable version -- Run the relevant [automigrations](../migration-guide.md#automatic-upgrade) factoring in the [breaking changes](../migration-guide.md#major-breaking-changes) between your current version and the latest stable version +- `storybook@latest upgrade` will upgrade to the latest version +- `storybook@7.6.10 upgrade` will upgrade to `7.6.10` +- `storybook@7 upgrade` will upgrade to the newest `7.x.x` version + +After running the command, the script will: + +- Upgrade all Storybook packages in your project to the specified version +- Run the relevant [automigrations](../migration-guide.md#automatic-upgrade) factoring in the [breaking changes](../migration-guide.md#major-breaking-changes) between your current version and the specified version @@ -69,6 +75,12 @@ To upgrade to the latest pre-release: +The `upgrade` command will use whichever version you specify. For example: + +- `storybook@next upgrade` will upgrade to the newest pre-release version +- `storybook@8.0.0-beta.1 upgrade` will upgrade to `8.0.0-beta.1` +- `storybook@8 upgrade` will upgrade to the newest `8.x` version + If you'd like to downgrade to a stable version, manually edit the package version numbers in your `package.json` and re-install. diff --git a/docs/get-started/install.md b/docs/get-started/install.md index 01ad6d3ff4e7..5053819c06f9 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -17,17 +17,13 @@ Use the Storybook CLI to install it in a single command. Run this inside your _e
+Install a specific version -storybook init is not made for empty projects +The `init` command will use whichever version you specify. For example: -Storybook needs to be installed into a project that is already set up with a framework. It will not work on an empty project. There are many ways to bootstrap an app in a given framework, including: - -- 📦 [Create an Angular Workspace](https://angular.io/cli/new) -- 📦 [Create React App](https://reactjs.org/docs/create-a-new-react-app.html) -- 📦 [Create a Vue App](https://vuejs.org/guide/quick-start.html) -- 📦 [Ember CLI](https://guides.emberjs.com/release/getting-started/quick-start/) -- 📦 [Vite CLI](https://vitejs.dev/guide/#scaffolding-your-first-vite-project) -- Or any other tooling available. +- `storybook@latest init` will initialize the latest version +- `storybook@7.6.10 init` will initialize `7.6.10` +- `storybook@7 init` will initialize the newest `7.x.x` version
diff --git a/docs/snippets/common/storybook-upgrade-prerelease.npm.js.mdx b/docs/snippets/common/storybook-upgrade-prerelease.npm.js.mdx index 58a5cb6dd40c..2627dd4df0f9 100644 --- a/docs/snippets/common/storybook-upgrade-prerelease.npm.js.mdx +++ b/docs/snippets/common/storybook-upgrade-prerelease.npm.js.mdx @@ -1,3 +1,3 @@ ```shell -npx storybook@latest upgrade --prerelease +npx storybook@next upgrade ``` diff --git a/docs/snippets/common/storybook-upgrade-prerelease.pnpm.js.mdx b/docs/snippets/common/storybook-upgrade-prerelease.pnpm.js.mdx index 1e7199a4b8c3..0992b91d603b 100644 --- a/docs/snippets/common/storybook-upgrade-prerelease.pnpm.js.mdx +++ b/docs/snippets/common/storybook-upgrade-prerelease.pnpm.js.mdx @@ -1,3 +1,3 @@ ```shell -pnpm dlx storybook@latest upgrade --prerelease +pnpm dlx storybook@next upgrade ``` diff --git a/docs/snippets/common/storybook-upgrade-prerelease.yarn.js.mdx b/docs/snippets/common/storybook-upgrade-prerelease.yarn.js.mdx index 2033dc73e8dd..97f21c53a131 100644 --- a/docs/snippets/common/storybook-upgrade-prerelease.yarn.js.mdx +++ b/docs/snippets/common/storybook-upgrade-prerelease.yarn.js.mdx @@ -1,3 +1,3 @@ ```shell -yarn dlx storybook@latest upgrade --prerelease +yarn dlx storybook@next upgrade ``` diff --git a/docs/versions/latest.json b/docs/versions/latest.json index a0c13e3e124d..1f2574bd8083 100644 --- a/docs/versions/latest.json +++ b/docs/versions/latest.json @@ -1 +1 @@ -{"version":"7.6.11","info":{"plain":"- CLI: Fix `upgrade` detecting the wrong version of existing Storybooks - [#25752](https://github.com/storybookjs/storybook/pull/25752), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Update init for react native v7 - [#25780](https://github.com/storybookjs/storybook/pull/25780), thanks [@dannyhw](https://github.com/dannyhw)!\n- Codemods: Add support for multiple file extensions in runCodemod function - [#25708](https://github.com/storybookjs/storybook/pull/25708), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!"}} +{"version":"7.6.12","info":{"plain":"- CLI: Fix `upgrade` detecting the wrong version of existing Storybooks - [#25752](https://github.com/storybookjs/storybook/pull/25752), thanks [@JReinhold](https://github.com/JReinhold)!"}} diff --git a/docs/versions/next.json b/docs/versions/next.json index f32c9fefec9d..5cafa5e5cdea 100644 --- a/docs/versions/next.json +++ b/docs/versions/next.json @@ -1 +1 @@ -{"version":"8.0.0-alpha.15","info":{"plain":"- Next.js: Add logger statements for compiler selection - [#25755](https://github.com/storybookjs/storybook/pull/25755), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- React-Native: Fixes for v8 compatibility - [#25678](https://github.com/storybookjs/storybook/pull/25678), thanks [@shilman](https://github.com/shilman)!\n- UI: Remove use of React.FC in components - [#25588](https://github.com/storybookjs/storybook/pull/25588), thanks [@ShaunEvening](https://github.com/ShaunEvening)!\n- Vue3: Fix support for `onX` and empty attributes in Show Code - [#25219](https://github.com/storybookjs/storybook/pull/25219), thanks [@Tap-Kim](https://github.com/Tap-Kim)!\n- Vue3: Introduce portable stories API - [#25443](https://github.com/storybookjs/storybook/pull/25443), thanks [@yannbf](https://github.com/yannbf)!"}} +{"version":"8.0.0-alpha.16","info":{"plain":"- CLI: Fix `upgrade` detecting the wrong version of existing Storybooks - [#25752](https://github.com/storybookjs/storybook/pull/25752), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Update init for react native v7 - [#25780](https://github.com/storybookjs/storybook/pull/25780), thanks [@dannyhw](https://github.com/dannyhw)!\n- UI: Improve how the addon panel work on mobile - [#25787](https://github.com/storybookjs/storybook/pull/25787), thanks [@cdedreuille](https://github.com/cdedreuille)!"}}