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
yannbf authored Nov 29, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents b62a2ed + 19e54ce commit 7b2d407
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
@@ -44,6 +44,7 @@ export function getDuplicatedDepsWarnings(
): string[] | undefined {
try {
if (
!installationMetadata ||
!installationMetadata?.duplicatedDependencies ||
Object.keys(installationMetadata.duplicatedDependencies).length === 0
) {
17 changes: 14 additions & 3 deletions code/lib/cli/src/doctor/getMismatchingVersionsWarning.ts
Original file line number Diff line number Diff line change
@@ -20,14 +20,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)) {
@@ -68,15 +74,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')
);
}
@@ -85,7 +96,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
)}`
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
@@ -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';
@@ -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;
}
}
}

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;

0 comments on commit 7b2d407

Please sign in to comment.