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: Fix upgrade detecting the wrong version of existing Storybooks #25752

Merged
merged 8 commits into from
Jan 29, 2024
36 changes: 33 additions & 3 deletions code/lib/cli/src/upgrade.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { describe, it, expect, vi } from 'vitest';
import { getStorybookCoreVersion } from '@storybook/telemetry';
import {
UpgradeStorybookToLowerVersionError,
UpgradeStorybookToSameVersionError,
Expand All @@ -8,11 +7,18 @@ import { doUpgrade, getStorybookVersion } from './upgrade';

import type * as sbcc from '@storybook/core-common';

const findInstallationsMock = vi.fn<string[], Promise<sbcc.InstallationMetadata | undefined>>();

vi.mock('@storybook/telemetry');
vi.mock('@storybook/core-common', async (importOriginal) => {
const originalModule = (await importOriginal()) as typeof sbcc;
return {
...originalModule,
JsPackageManagerFactory: {
getPackageManager: () => ({
findInstallations: findInstallationsMock,
}),
},
versions: Object.keys(originalModule.versions).reduce(
(acc, key) => {
acc[key] = '8.0.0';
Expand Down Expand Up @@ -46,13 +52,37 @@ describe.each([

describe('Upgrade errors', () => {
it('should throw an error when upgrading to a lower version number', async () => {
vi.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/cli']);
});
it('should throw an error when upgrading to the same version number', async () => {
vi.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/cli']);
});
});
23 changes: 18 additions & 5 deletions code/lib/cli/src/upgrade.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { sync as spawnSync } from 'cross-spawn';
import { telemetry, getStorybookCoreVersion } from '@storybook/telemetry';
import { telemetry } from '@storybook/telemetry';
import semver, { eq, lt, prerelease } from 'semver';
import { logger } from '@storybook/node-logger';
import { withTelemetry } from '@storybook/core-server';
Expand All @@ -11,7 +11,7 @@ import {
import chalk from 'chalk';
import dedent from 'ts-dedent';
import boxen from 'boxen';
import type { PackageManagerName } from '@storybook/core-common';
import type { JsPackageManager, PackageManagerName } from '@storybook/core-common';
import {
JsPackageManagerFactory,
isCorePackage,
Expand All @@ -37,6 +37,18 @@ export const getStorybookVersion = (line: string) => {
};
};

const getInstalledStorybookVersion = async (packageManager: JsPackageManager) => {
const installations = await packageManager.findInstallations(['storybook', '@storybook/cli']);
if (!installations) {
return;
}
const cliVersion = installations.dependencies['@storybook/cli']?.[0].version;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

installations.dependencies['@storybook/cli']?.[0] -> Can this be undefined? If so installations.dependencies['@storybook/cli']?.[0].version will through.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can't, TS would complain, and the current code producing it doesn't do that either.

if (cliVersion) {
return cliVersion;
}
return installations.dependencies['storybook']?.[0].version;
};

const deprecatedPackages = [
{
minVersion: '6.0.0-alpha.0',
Expand Down Expand Up @@ -113,8 +125,9 @@ export const doUpgrade = async ({
}: UpgradeOptions) => {
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');

Expand Down Expand Up @@ -206,7 +219,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,
Expand Down
2 changes: 0 additions & 2 deletions code/lib/telemetry/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
6 changes: 0 additions & 6 deletions code/lib/telemetry/src/package-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Comment on lines -32 to -35
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shilman this is a function in telemetry but it was only used by upgrade which doesn't use it anymore, so I felt it was okay to remove it. Let me know if not.