Skip to content

Commit

Permalink
Merge pull request #25037 from storybookjs/yann/improve-doctor-cli
Browse files Browse the repository at this point in the history
CLI: Improve dependency metadata detection in storybook doctor
(cherry picked from commit 7b2d407)
  • Loading branch information
yannbf committed Nov 29, 2023
1 parent 4155d1e commit ffbb86e
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 15 deletions.
1 change: 1 addition & 0 deletions code/lib/cli/src/doctor/getDuplicatedDepsWarnings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export function getDuplicatedDepsWarnings(
): string[] | undefined {
try {
if (
!installationMetadata ||
!installationMetadata?.duplicatedDependencies ||
Object.keys(installationMetadata.duplicatedDependencies).length === 0
) {
Expand Down
17 changes: 14 additions & 3 deletions code/lib/cli/src/doctor/getMismatchingVersionsWarning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,20 @@ export function getMismatchingVersionsWarnings(
installationMetadata?: InstallationMetadata,
allDependencies?: Record<string, string>
): string | undefined {
if (!installationMetadata) {
return undefined;
}

const messages: string[] = [];
try {
const frameworkPackageName = Object.keys(installationMetadata?.dependencies).find(
(packageName) => {
return Object.keys(frameworkPackages).includes(packageName);
}
);
const cliVersion = getPrimaryVersion('@storybook/cli', installationMetadata);
const cliVersion =
getPrimaryVersion('@storybook/cli', installationMetadata) ||
getPrimaryVersion('storybook', installationMetadata);
const frameworkVersion = getPrimaryVersion(frameworkPackageName, installationMetadata);

if (!cliVersion || !frameworkVersion || semver.eq(cliVersion, frameworkVersion)) {
Expand Down Expand Up @@ -65,15 +71,20 @@ export function getMismatchingVersionsWarnings(
);

if (filteredDependencies.length > 0) {
const packageJsonSuffix = '(in your package.json)';
messages.push(
`Based on your lockfile, these dependencies should be upgraded:`,
filteredDependencies
.map(
([name, dep]) =>
`${chalk.hex('#ff9800')(name)}: ${dep[0].version} ${
allDependencies[name] ? '(in your package.json)' : ''
allDependencies?.[name] ? packageJsonSuffix : ''
}`
)
.sort(
(a, b) =>
(b.includes(packageJsonSuffix) ? 1 : 0) - (a.includes(packageJsonSuffix) ? 1 : 0)
)
.join('\n')
);
}
Expand All @@ -82,7 +93,7 @@ export function getMismatchingVersionsWarnings(
`You can run ${chalk.cyan(
'npx storybook@latest upgrade'
)} to upgrade all of your Storybook packages to the latest version.
Alternatively you can try manually changing the versions to match in your package.json. We also recommend regenerating your lockfile, or running the following command to possibly deduplicate your Storybook package versions: ${chalk.cyan(
installationMetadata.dedupeCommand
)}`
Expand Down
35 changes: 24 additions & 11 deletions code/lib/cli/src/js-package-manager/NPMProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { sync as findUpSync } from 'find-up';
import { existsSync, readFileSync } from 'fs';
import path from 'path';
import semver from 'semver';
import { logger } from '@storybook/node-logger';
import { JsPackageManager } from './JsPackageManager';
import type { PackageJson } from './PackageJson';
import type { InstallationMetadata, PackageMetadata } from './types';
Expand Down Expand Up @@ -136,22 +137,34 @@ export class NPMProxy extends JsPackageManager {
}

public async findInstallations() {
const pipeToNull = platform() === 'win32' ? '2>NUL' : '2>/dev/null';
const commandResult = await this.executeCommand({
command: 'npm',
args: ['ls', '--json', '--depth=99', pipeToNull],
// ignore errors, because npm ls will exit with code 1 if there are e.g. unmet peer dependencies
ignoreError: true,
env: {
FORCE_COLOR: 'false',
},
});
const exec = async ({ depth }: { depth: number }) => {
const pipeToNull = platform() === 'win32' ? '2>NUL' : '2>/dev/null';
return this.executeCommand({
command: 'npm',
args: ['ls', '--json', `--depth=${depth}`, pipeToNull],
env: {
FORCE_COLOR: 'false',
},
});
};

try {
const commandResult = await exec({ depth: 99 });
const parsedOutput = JSON.parse(commandResult);

return this.mapDependencies(parsedOutput);
} catch (e) {
return undefined;
// when --depth is higher than 0, npm can return a non-zero exit code
// in case the user's project has peer dependency issues. So we try again with no depth
try {
const commandResult = await exec({ depth: 0 });
const parsedOutput = JSON.parse(commandResult);

return this.mapDependencies(parsedOutput);
} catch (err) {
logger.warn(`An issue occurred while trying to find dependencies metadata using npm.`);
return undefined;
}
}
}

Expand Down
5 changes: 4 additions & 1 deletion code/lib/cli/src/js-package-manager/util.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// input: @storybook/addon-essentials@npm:7.0.0
// output: { name: '@storybook/addon-essentials', value: { version : '7.0.0', location: '' } }
export const parsePackageData = (packageName = '') => {
const [first, second, third] = packageName.trim().split('@');
const [first, second, third] = packageName
.replace(/[└─├]+/g, '')
.trim()
.split('@');
const version = (third || second).replace('npm:', '');
const name = third ? `@${second}` : first;

Expand Down

0 comments on commit ffbb86e

Please sign in to comment.