diff --git a/code/frameworks/angular/src/builders/utils/run-compodoc.spec.ts b/code/frameworks/angular/src/builders/utils/run-compodoc.spec.ts index 5e25c046bb07..449d211fe05b 100644 --- a/code/frameworks/angular/src/builders/utils/run-compodoc.spec.ts +++ b/code/frameworks/angular/src/builders/utils/run-compodoc.spec.ts @@ -8,7 +8,7 @@ const mockRunScript = jest.fn(); jest.mock('@storybook/cli', () => ({ JsPackageManagerFactory: { getPackageManager: () => ({ - runPackageCommand: mockRunScript, + runPackageCommandSync: mockRunScript, }), }, })); diff --git a/code/frameworks/angular/src/builders/utils/run-compodoc.ts b/code/frameworks/angular/src/builders/utils/run-compodoc.ts index 6f167070789c..ebec682ba2e1 100644 --- a/code/frameworks/angular/src/builders/utils/run-compodoc.ts +++ b/code/frameworks/angular/src/builders/utils/run-compodoc.ts @@ -28,7 +28,7 @@ export const runCompodoc = ( const packageManager = JsPackageManagerFactory.getPackageManager(); try { - const stdout = packageManager.runPackageCommand( + const stdout = packageManager.runPackageCommandSync( 'compodoc', finalCompodocArgs, context.workspaceRoot diff --git a/code/lib/cli/src/add.ts b/code/lib/cli/src/add.ts index df350c7e1151..efced649c957 100644 --- a/code/lib/cli/src/add.ts +++ b/code/lib/cli/src/add.ts @@ -80,7 +80,7 @@ export async function add( pkgMgr = 'npm'; } const packageManager = JsPackageManagerFactory.getPackageManager({ force: pkgMgr }); - const packageJson = packageManager.retrievePackageJson(); + const packageJson = await packageManager.retrievePackageJson(); const [addonName, versionSpecifier] = getVersionSpecifier(addon); const { mainConfig, version: storybookVersion } = getStorybookInfo(packageJson); @@ -90,7 +90,7 @@ export async function add( } const main = await readConfig(mainConfig); logger.log(`Verifying ${addonName}`); - const latestVersion = packageManager.latestVersion(addonName); + const latestVersion = await packageManager.latestVersion(addonName); if (!latestVersion) { logger.error(`Unknown addon ${addonName}`); } @@ -100,7 +100,7 @@ export async function add( const version = versionSpecifier || (isStorybookAddon ? storybookVersion : latestVersion); const addonWithVersion = `${addonName}@${version}`; logger.log(`Installing ${addonWithVersion}`); - packageManager.addDependencies({ installAsDevDependencies: true }, [addonWithVersion]); + await packageManager.addDependencies({ installAsDevDependencies: true }, [addonWithVersion]); // add to main.js logger.log(`Adding '${addon}' to main.js addons field.`); diff --git a/code/lib/cli/src/automigrate/fixes/add-react.test.ts b/code/lib/cli/src/automigrate/fixes/add-react.test.ts index f497f4013016..42bb20b60e2e 100644 --- a/code/lib/cli/src/automigrate/fixes/add-react.test.ts +++ b/code/lib/cli/src/automigrate/fixes/add-react.test.ts @@ -3,7 +3,7 @@ import { addReact } from './add-react'; const checkAddReact = async (packageJson: PackageJson) => { const packageManager = { - retrievePackageJson: () => ({ dependencies: {}, devDependencies: {}, ...packageJson }), + retrievePackageJson: async () => ({ dependencies: {}, devDependencies: {}, ...packageJson }), } as JsPackageManager; return addReact.check({ packageManager }); }; diff --git a/code/lib/cli/src/automigrate/fixes/add-react.ts b/code/lib/cli/src/automigrate/fixes/add-react.ts index 420be48912f1..25ad88df2571 100644 --- a/code/lib/cli/src/automigrate/fixes/add-react.ts +++ b/code/lib/cli/src/automigrate/fixes/add-react.ts @@ -14,7 +14,7 @@ export const addReact: Fix = { id: 'addReact', async check({ packageManager }) { - const packageJson = packageManager.retrievePackageJson(); + const packageJson = await packageManager.retrievePackageJson(); const installedDependencies = new Set( Object.keys({ ...packageJson.dependencies, ...packageJson.devDependencies }) ); @@ -63,7 +63,10 @@ export const addReact: Fix = { async run({ packageManager, result: { additionalDependencies }, dryRun }) { if (!dryRun) { - packageManager.addDependencies({ installAsDevDependencies: true }, additionalDependencies); + await packageManager.addDependencies( + { installAsDevDependencies: true }, + additionalDependencies + ); } }, }; diff --git a/code/lib/cli/src/automigrate/fixes/angular-builders-multiproject.ts b/code/lib/cli/src/automigrate/fixes/angular-builders-multiproject.ts index 14d767e1ca59..2cd0a42fa987 100644 --- a/code/lib/cli/src/automigrate/fixes/angular-builders-multiproject.ts +++ b/code/lib/cli/src/automigrate/fixes/angular-builders-multiproject.ts @@ -12,14 +12,14 @@ export const angularBuildersMultiproject: Fix = { id: 'angular-builders', async check({ packageManager, configDir }) { - const packageJSON = packageManager.retrievePackageJson(); + const packageJSON = await packageManager.retrievePackageJson(); // Skip in case of NX if (isNxProject(packageJSON)) { return null; } - const allDependencies = packageManager.getAllDependencies(); + const allDependencies = await packageManager.getAllDependencies(); const angularVersion = allDependencies['@angular/core']; const angularCoerced = semver.coerce(angularVersion)?.version; @@ -98,7 +98,7 @@ export const angularBuilders: Fix = { angularJSON.write(); - packageManager.addScripts({ + await packageManager.addScripts({ storybook: `ng run ${angularProjectName}:storybook`, 'build-storybook': `ng run ${angularProjectName}:build-storybook`, }); diff --git a/code/lib/cli/src/automigrate/fixes/angular12.ts b/code/lib/cli/src/automigrate/fixes/angular12.ts index a778556e9207..c8b98e6b0f00 100644 --- a/code/lib/cli/src/automigrate/fixes/angular12.ts +++ b/code/lib/cli/src/automigrate/fixes/angular12.ts @@ -21,7 +21,7 @@ export const angular12: Fix = { id: 'angular12', async check({ packageManager, configDir }) { - const allDependencies = packageManager.getAllDependencies(); + const allDependencies = await packageManager.getAllDependencies(); const angularVersion = allDependencies['@angular/core']; const angularCoerced = semver.coerce(angularVersion)?.version; diff --git a/code/lib/cli/src/automigrate/fixes/builder-vite.ts b/code/lib/cli/src/automigrate/fixes/builder-vite.ts index c107cc6d7d17..9fef70b8b9d6 100644 --- a/code/lib/cli/src/automigrate/fixes/builder-vite.ts +++ b/code/lib/cli/src/automigrate/fixes/builder-vite.ts @@ -27,7 +27,7 @@ export const builderVite: Fix = { id: 'builder-vite', async check({ configDir, packageManager }) { - const packageJson = packageManager.retrievePackageJson(); + const packageJson = await packageManager.retrievePackageJson(); const { mainConfig } = await getStorybookData({ configDir, packageManager }); const builder = mainConfig.core?.builder; const builderName = typeof builder === 'string' ? builder : builder?.name; @@ -64,12 +64,12 @@ export const builderVite: Fix = { if (!dryRun) { delete dependencies['storybook-builder-vite']; delete devDependencies['storybook-builder-vite']; - packageManager.writePackageJson(packageJson); + await packageManager.writePackageJson(packageJson); } logger.info(`✅ Adding '@storybook/builder-vite' as dev dependency`); if (!dryRun) { - packageManager.addDependencies({ installAsDevDependencies: true }, [ + await packageManager.addDependencies({ installAsDevDependencies: true }, [ '@storybook/builder-vite', ]); } diff --git a/code/lib/cli/src/automigrate/fixes/cra5.ts b/code/lib/cli/src/automigrate/fixes/cra5.ts index 04ca458d6871..1280a5de3155 100644 --- a/code/lib/cli/src/automigrate/fixes/cra5.ts +++ b/code/lib/cli/src/automigrate/fixes/cra5.ts @@ -21,7 +21,7 @@ export const cra5: Fix = { id: 'cra5', async check({ packageManager, configDir }) { - const allDependencies = packageManager.getAllDependencies(); + const allDependencies = await packageManager.getAllDependencies(); const craVersion = allDependencies['react-scripts']; const craCoerced = semver.coerce(craVersion)?.version; diff --git a/code/lib/cli/src/automigrate/fixes/eslint-plugin.ts b/code/lib/cli/src/automigrate/fixes/eslint-plugin.ts index c5b155ff5366..9b461e97d1a7 100644 --- a/code/lib/cli/src/automigrate/fixes/eslint-plugin.ts +++ b/code/lib/cli/src/automigrate/fixes/eslint-plugin.ts @@ -25,7 +25,7 @@ export const eslintPlugin: Fix = { id: 'eslintPlugin', async check({ packageManager }) { - const allDependencies = packageManager.getAllDependencies(); + const allDependencies = await packageManager.getAllDependencies(); const eslintPluginStorybook = allDependencies['eslint-plugin-storybook']; const eslintDependency = allDependencies.eslint; @@ -64,8 +64,9 @@ export const eslintPlugin: Fix = { const deps = [`eslint-plugin-storybook`]; logger.info(`✅ Adding dependencies: ${deps}`); - if (!dryRun) - packageManager.addDependencies({ installAsDevDependencies: true, skipInstall }, deps); + if (!dryRun) { + await packageManager.addDependencies({ installAsDevDependencies: true, skipInstall }, deps); + } if (!dryRun && unsupportedExtension) { logger.info(dedent` diff --git a/code/lib/cli/src/automigrate/fixes/mdx-gfm.ts b/code/lib/cli/src/automigrate/fixes/mdx-gfm.ts index e4f0f6b8b7cd..7989b5c1517a 100644 --- a/code/lib/cli/src/automigrate/fixes/mdx-gfm.ts +++ b/code/lib/cli/src/automigrate/fixes/mdx-gfm.ts @@ -81,8 +81,10 @@ export const mdxgfm: Fix = { async run({ packageManager, dryRun, mainConfigPath, skipInstall }) { if (!dryRun) { - const packageJson = packageManager.retrievePackageJson(); - const versionToInstall = getStorybookVersionSpecifier(packageManager.retrievePackageJson()); + const packageJson = await packageManager.retrievePackageJson(); + const versionToInstall = getStorybookVersionSpecifier( + await packageManager.retrievePackageJson() + ); await packageManager.addDependencies( { installAsDevDependencies: true, skipInstall, packageJson }, [`@storybook/addon-mdx-gfm@${versionToInstall}`] diff --git a/code/lib/cli/src/automigrate/fixes/missing-babelrc.ts b/code/lib/cli/src/automigrate/fixes/missing-babelrc.ts index 07f94b1f4d50..2e13685fd8b4 100644 --- a/code/lib/cli/src/automigrate/fixes/missing-babelrc.ts +++ b/code/lib/cli/src/automigrate/fixes/missing-babelrc.ts @@ -24,7 +24,7 @@ export const missingBabelRc: Fix = { id: 'missing-babelrc', async check({ configDir, packageManager }) { - const packageJson = packageManager.retrievePackageJson(); + const packageJson = await packageManager.retrievePackageJson(); const { mainConfig, storybookVersion } = await getStorybookData({ configDir, packageManager }); if (!semver.gte(storybookVersion, '7.0.0')) { diff --git a/code/lib/cli/src/automigrate/fixes/new-frameworks.ts b/code/lib/cli/src/automigrate/fixes/new-frameworks.ts index 11c23cc5b348..d2be64bf877a 100644 --- a/code/lib/cli/src/automigrate/fixes/new-frameworks.ts +++ b/code/lib/cli/src/automigrate/fixes/new-frameworks.ts @@ -67,7 +67,7 @@ export const newFrameworks: Fix = { configDir: userDefinedConfigDir, packageManager, }) { - const packageJson = packageManager.retrievePackageJson(); + const packageJson = await packageManager.retrievePackageJson(); const { storybookVersion, mainConfig, mainConfigPath, configDir } = await getStorybookData({ packageManager, configDir: userDefinedConfigDir, @@ -108,7 +108,7 @@ export const newFrameworks: Fix = { return null; } - const allDependencies = packageManager.getAllDependencies(); + const allDependencies = await packageManager.getAllDependencies(); const builderInfo = await detectBuilderInfo({ mainConfig, @@ -448,7 +448,7 @@ export const newFrameworks: Fix = { if (dependenciesToRemove.length > 0) { logger.info(`✅ Removing dependencies: ${dependenciesToRemove.join(', ')}`); if (!dryRun) { - packageManager.removeDependencies( + await packageManager.removeDependencies( { skipInstall: skipInstall || dependenciesToAdd.length > 0, packageJson }, dependenciesToRemove ); @@ -460,7 +460,7 @@ export const newFrameworks: Fix = { if (!dryRun) { const versionToInstall = getStorybookVersionSpecifier(packageJson); const depsToAdd = dependenciesToAdd.map((dep) => `${dep}@${versionToInstall}`); - packageManager.addDependencies( + await packageManager.addDependencies( { installAsDevDependencies: true, skipInstall, packageJson }, depsToAdd ); diff --git a/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.test.ts b/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.test.ts index 0ae9971db053..a8fa9d050b9c 100644 --- a/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.test.ts +++ b/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.test.ts @@ -16,7 +16,7 @@ const check = async ({ packageJson = {}, contents }: any) => { }); } const packageManager = { - retrievePackageJson: () => ({ dependencies: {}, devDependencies: {}, ...packageJson }), + retrievePackageJson: async () => ({ dependencies: {}, devDependencies: {}, ...packageJson }), } as JsPackageManager; return migration.check({ packageManager }); }; diff --git a/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.ts b/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.ts index 9e725b810d73..9888b22a6be9 100644 --- a/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.ts +++ b/code/lib/cli/src/automigrate/fixes/remove-global-client-apis.ts @@ -23,7 +23,7 @@ export const removedGlobalClientAPIs: Fix = { promptOnly: true, async check({ packageManager, configDir }) { - const packageJson = packageManager.retrievePackageJson(); + const packageJson = await packageManager.retrievePackageJson(); const { previewConfig } = getStorybookInfo(packageJson, configDir); diff --git a/code/lib/cli/src/automigrate/fixes/sb-binary.ts b/code/lib/cli/src/automigrate/fixes/sb-binary.ts index b97d1faa5536..22d0283e3de3 100644 --- a/code/lib/cli/src/automigrate/fixes/sb-binary.ts +++ b/code/lib/cli/src/automigrate/fixes/sb-binary.ts @@ -26,8 +26,8 @@ export const sbBinary: Fix = { id: 'storybook-binary', async check({ packageManager, configDir }) { - const packageJson = packageManager.retrievePackageJson(); - const allDependencies = packageManager.getAllDependencies(); + const packageJson = await packageManager.retrievePackageJson(); + const allDependencies = await packageManager.getAllDependencies(); const { storybookVersion } = await getStorybookData({ packageManager, configDir }); // Nx provides their own binary, so we don't need to do anything @@ -82,7 +82,7 @@ export const sbBinary: Fix = { if (hasSbBinary) { logger.info(`✅ Removing 'sb' dependency`); if (!dryRun) { - packageManager.removeDependencies( + await packageManager.removeDependencies( { skipInstall: skipInstall || !hasStorybookBinary, packageJson }, ['sb'] ); @@ -95,7 +95,7 @@ export const sbBinary: Fix = { logger.log(); if (!dryRun) { const versionToInstall = getStorybookVersionSpecifier(packageJson); - packageManager.addDependencies( + await packageManager.addDependencies( { installAsDevDependencies: true, packageJson, skipInstall }, [`storybook@${versionToInstall}`] ); diff --git a/code/lib/cli/src/automigrate/fixes/sb-scripts.ts b/code/lib/cli/src/automigrate/fixes/sb-scripts.ts index 9c84d7b75062..b624d494af5a 100644 --- a/code/lib/cli/src/automigrate/fixes/sb-scripts.ts +++ b/code/lib/cli/src/automigrate/fixes/sb-scripts.ts @@ -72,7 +72,7 @@ export const sbScripts: Fix = { id: 'sb-scripts', async check({ packageManager, configDir }) { - const packageJson = packageManager.retrievePackageJson(); + const packageJson = await packageManager.retrievePackageJson(); const { scripts = {} } = packageJson; const { storybookVersion } = await getStorybookData({ packageManager, configDir }); @@ -133,7 +133,7 @@ export const sbScripts: Fix = { logger.log(); - packageManager.addScripts(newScripts); + await packageManager.addScripts(newScripts); } }, }; diff --git a/code/lib/cli/src/automigrate/fixes/vue3.ts b/code/lib/cli/src/automigrate/fixes/vue3.ts index f1c5041e1885..0d3aaca104af 100644 --- a/code/lib/cli/src/automigrate/fixes/vue3.ts +++ b/code/lib/cli/src/automigrate/fixes/vue3.ts @@ -20,7 +20,7 @@ export const vue3: Fix = { id: 'vue3', async check({ configDir, packageManager }) { - const allDependencies = packageManager.getAllDependencies(); + const allDependencies = await packageManager.getAllDependencies(); const vueVersion = allDependencies.vue; const vueCoerced = semver.coerce(vueVersion)?.version; diff --git a/code/lib/cli/src/automigrate/fixes/webpack5.ts b/code/lib/cli/src/automigrate/fixes/webpack5.ts index edac5e468696..c60dc9f0eed1 100644 --- a/code/lib/cli/src/automigrate/fixes/webpack5.ts +++ b/code/lib/cli/src/automigrate/fixes/webpack5.ts @@ -26,7 +26,7 @@ export const webpack5: Fix = { id: 'webpack5', async check({ configDir, packageManager }) { - const allDependencies = packageManager.retrievePackageJson().dependencies; + const allDependencies = (await packageManager.retrievePackageJson()).dependencies; const webpackVersion = allDependencies.webpack; const webpackCoerced = semver.coerce(webpackVersion)?.version; @@ -72,7 +72,9 @@ export const webpack5: Fix = { deps.push('webpack@5'); } logger.info(`✅ Adding dependencies: ${deps}`); - if (!dryRun) packageManager.addDependencies({ installAsDevDependencies: true }, deps); + if (!dryRun) { + await packageManager.addDependencies({ installAsDevDependencies: true }, deps); + } logger.info('✅ Setting `core.builder` to `@storybook/builder-webpack5` in main.js'); if (!dryRun) { diff --git a/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts b/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts index c16b97afebd6..f843f57097f9 100644 --- a/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts +++ b/code/lib/cli/src/automigrate/helpers/mainConfigFile.ts @@ -16,7 +16,7 @@ export const getStorybookData = async ({ packageManager: JsPackageManager; configDir: string; }) => { - const packageJson = packageManager.retrievePackageJson(); + const packageJson = await packageManager.retrievePackageJson(); const { mainConfig: mainConfigPath, version: storybookVersionSpecifier, diff --git a/code/lib/cli/src/automigrate/helpers/testing-helpers.ts b/code/lib/cli/src/automigrate/helpers/testing-helpers.ts index 2c9cd34d6251..3651fe472caf 100644 --- a/code/lib/cli/src/automigrate/helpers/testing-helpers.ts +++ b/code/lib/cli/src/automigrate/helpers/testing-helpers.ts @@ -15,8 +15,8 @@ jest.mock('@storybook/core-common', () => ({ export const makePackageManager = (packageJson: PackageJson) => { const { dependencies = {}, devDependencies = {}, peerDependencies = {} } = packageJson; return { - retrievePackageJson: () => ({ dependencies: {}, devDependencies: {}, ...packageJson }), - getAllDependencies: () => ({ + retrievePackageJson: async () => ({ dependencies: {}, devDependencies: {}, ...packageJson }), + getAllDependencies: async () => ({ ...dependencies, ...devDependencies, ...peerDependencies, diff --git a/code/lib/cli/src/automigrate/index.ts b/code/lib/cli/src/automigrate/index.ts index e412f483fcc8..14c1865262a8 100644 --- a/code/lib/cli/src/automigrate/index.ts +++ b/code/lib/cli/src/automigrate/index.ts @@ -148,7 +148,7 @@ export async function runFixes({ configDir: inferredConfigDir, mainConfig: mainConfigPath, version: storybookVersion, - } = getStorybookInfo(packageManager.retrievePackageJson(), userSpecifiedConfigDir); + } = getStorybookInfo(await packageManager.retrievePackageJson(), userSpecifiedConfigDir); const sbVersionCoerced = storybookVersion && semver.coerce(storybookVersion)?.version; if (!sbVersionCoerced) { diff --git a/code/lib/cli/src/babel-config.ts b/code/lib/cli/src/babel-config.ts index 70bc127ae9ee..e97b51f0328d 100644 --- a/code/lib/cli/src/babel-config.ts +++ b/code/lib/cli/src/babel-config.ts @@ -90,7 +90,7 @@ export const generateStorybookBabelConfig = async ({ target }: { target: string const packageManager = JsPackageManagerFactory.getPackageManager(); - packageManager.addDependencies({ installAsDevDependencies: true }, added); + await packageManager.addDependencies({ installAsDevDependencies: true }, added); } else { logger.info( `⚠️ Please remember to install the required dependencies yourself: (${added.join(', ')})` diff --git a/code/lib/cli/src/detect-webpack.ts b/code/lib/cli/src/detect-webpack.ts index 992eb0c09968..d0a980567d29 100644 --- a/code/lib/cli/src/detect-webpack.ts +++ b/code/lib/cli/src/detect-webpack.ts @@ -1,18 +1,18 @@ import type { JsPackageManager } from './js-package-manager'; -export const detectWebpack = (packageManager: JsPackageManager): number | false => { +export const detectWebpack = async (packageManager: JsPackageManager): Promise => { try { let out = ''; if (packageManager.type === 'npm') { try { // npm <= v7 - out = packageManager.executeCommand('npm', ['ls', 'webpack']); + out = await packageManager.executeCommand({ command: 'npm', args: ['ls', 'webpack'] }); } catch (e2) { // npm >= v8 - out = packageManager.executeCommand('npm', ['why', 'webpack']); + out = await packageManager.executeCommand({ command: 'npm', args: ['why', 'webpack'] }); } } else { - out = packageManager.executeCommand('yarn', ['why', 'webpack']); + out = await packageManager.executeCommand({ command: 'yarn', args: ['why', 'webpack'] }); } // if the user has BOTH webpack 4 and 5 installed already, we'll pick the safest options (4) diff --git a/code/lib/cli/src/dirs.ts b/code/lib/cli/src/dirs.ts index e5baef79237f..6f3fa0e06864 100644 --- a/code/lib/cli/src/dirs.ts +++ b/code/lib/cli/src/dirs.ts @@ -20,7 +20,9 @@ const resolveUsingBranchInstall = async (packageManager: JsPackageManager, reque // FIXME: this might not be the right version for community packages const version = versions[name] || (await packageManager.latestVersion(request)); - const url = getNpmTarballUrl(request, version, { registry: packageManager.getRegistryURL() }); + const url = getNpmTarballUrl(request, version, { + registry: await packageManager.getRegistryURL(), + }); // this unzips the tarball into the temp directory await downloadTarball({ url, dir: tempDirectory }); diff --git a/code/lib/cli/src/generators/ANGULAR/index.ts b/code/lib/cli/src/generators/ANGULAR/index.ts index 2740be11589a..b820339d95b9 100644 --- a/code/lib/cli/src/generators/ANGULAR/index.ts +++ b/code/lib/cli/src/generators/ANGULAR/index.ts @@ -14,11 +14,11 @@ const generator: Generator<{ projectName: string }> = async ( commandOptions ) => { const angularVersionFromDependencies = semver.coerce( - packageManager.retrievePackageJson().dependencies['@angular/core'] + (await packageManager.retrievePackageJson()).dependencies['@angular/core'] )?.version; const angularVersionFromDevDependencies = semver.coerce( - packageManager.retrievePackageJson().devDependencies['@angular/core'] + (await packageManager.retrievePackageJson()).devDependencies['@angular/core'] )?.version; const angularVersion = angularVersionFromDependencies || angularVersionFromDevDependencies; diff --git a/code/lib/cli/src/generators/RAX/index.ts b/code/lib/cli/src/generators/RAX/index.ts index 44243b677d06..e3a0acefc2f8 100644 --- a/code/lib/cli/src/generators/RAX/index.ts +++ b/code/lib/cli/src/generators/RAX/index.ts @@ -3,7 +3,7 @@ import type { Generator } from '../types'; const generator: Generator = async (packageManager, npmOptions, options) => { const [latestRaxVersion] = await packageManager.getVersions('rax'); - const packageJson = packageManager.retrievePackageJson(); + const packageJson = await packageManager.retrievePackageJson(); const raxVersion = packageJson.dependencies.rax || latestRaxVersion; @@ -16,7 +16,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => { packageJson.dependencies['rax-text'] = packageJson.dependencies['rax-text'] || raxVersion; packageJson.dependencies['rax-view'] = packageJson.dependencies['rax-view'] || raxVersion; - packageManager.writePackageJson(packageJson); + await packageManager.writePackageJson(packageJson); await baseGenerator(packageManager, npmOptions, options, 'rax', { extraPackages: ['rax'], diff --git a/code/lib/cli/src/generators/REACT_NATIVE/index.ts b/code/lib/cli/src/generators/REACT_NATIVE/index.ts index f3cc42668ddf..dc3e14ed0f7e 100644 --- a/code/lib/cli/src/generators/REACT_NATIVE/index.ts +++ b/code/lib/cli/src/generators/REACT_NATIVE/index.ts @@ -7,7 +7,7 @@ const generator = async ( packageManager: JsPackageManager, npmOptions: NpmOptions ): Promise => { - const packageJson = packageManager.retrievePackageJson(); + const packageJson = await packageManager.retrievePackageJson(); const missingReactDom = !packageJson.dependencies['react-dom'] && !packageJson.devDependencies['react-dom']; @@ -41,7 +41,7 @@ const generator = async ( missingReactDom && reactVersion && `react-dom@${reactVersion}`, ].filter(Boolean); - packageManager.addDependencies({ ...npmOptions, packageJson }, packages); + await packageManager.addDependencies({ ...npmOptions, packageJson }, packages); packageManager.addScripts({ 'storybook-generate': 'sb-rn-get-stories', 'storybook-watch': 'sb-rn-watcher', diff --git a/code/lib/cli/src/generators/REACT_SCRIPTS/index.ts b/code/lib/cli/src/generators/REACT_SCRIPTS/index.ts index c8001d54f2a4..1871a13faedb 100644 --- a/code/lib/cli/src/generators/REACT_SCRIPTS/index.ts +++ b/code/lib/cli/src/generators/REACT_SCRIPTS/index.ts @@ -25,9 +25,8 @@ const generator: Generator = async (packageManager, npmOptions, options) => { } : {}; - const craVersion = semver.coerce( - packageManager.retrievePackageJson().dependencies['react-scripts'] - )?.version; + const packageJson = await packageManager.retrievePackageJson(); + const craVersion = semver.coerce(packageJson.dependencies['react-scripts'])?.version; const isCra5OrHigher = craVersion && semver.gte(craVersion, '5.0.0'); const updatedOptions = isCra5OrHigher ? { ...options, builder: CoreBuilder.Webpack5 } : options; diff --git a/code/lib/cli/src/generators/baseGenerator.ts b/code/lib/cli/src/generators/baseGenerator.ts index 65f732b97f20..9a44785b7146 100644 --- a/code/lib/cli/src/generators/baseGenerator.ts +++ b/code/lib/cli/src/generators/baseGenerator.ts @@ -197,7 +197,7 @@ export async function baseGenerator( const files = await fse.readdir(process.cwd()); - const packageJson = packageManager.retrievePackageJson(); + const packageJson = await packageManager.retrievePackageJson(); const installedDependencies = new Set( Object.keys({ ...packageJson.dependencies, ...packageJson.devDependencies }) ); @@ -274,17 +274,17 @@ export async function baseGenerator( const depsToInstall = [...versionedPackages, ...babelDependencies]; if (depsToInstall.length > 0) { - packageManager.addDependencies({ ...npmOptions, packageJson }, depsToInstall); + await packageManager.addDependencies({ ...npmOptions, packageJson }, depsToInstall); } if (addScripts) { - packageManager.addStorybookCommandInScripts({ + await packageManager.addStorybookCommandInScripts({ port: 6006, }); } if (addESLint) { - packageManager.addESLintConfig(); + await packageManager.addESLintConfig(); } if (addComponents) { diff --git a/code/lib/cli/src/helpers.test.ts b/code/lib/cli/src/helpers.test.ts index db242f85f52b..4f5c3d37afee 100644 --- a/code/lib/cli/src/helpers.test.ts +++ b/code/lib/cli/src/helpers.test.ts @@ -33,7 +33,7 @@ jest.mock('path', () => { }); const packageManagerMock = { - retrievePackageJson: () => ({ dependencies: {}, devDependencies: {} }), + retrievePackageJson: async () => ({ dependencies: {}, devDependencies: {} }), } as JsPackageManager; describe('Helpers', () => { diff --git a/code/lib/cli/src/initiate.ts b/code/lib/cli/src/initiate.ts index bd7b5712ac93..1d02074d40fa 100644 --- a/code/lib/cli/src/initiate.ts +++ b/code/lib/cli/src/initiate.ts @@ -41,7 +41,7 @@ import { HandledError } from './HandledError'; const logger = console; -const installStorybook = ( +const installStorybook = async ( projectType: Project, packageManager: JsPackageManager, options: CommandOptions @@ -53,7 +53,7 @@ const installStorybook = ( let packageJson; try { - packageJson = packageManager.readPackageJson(); + packageJson = await packageManager.readPackageJson(); } catch (err) { // } @@ -228,7 +228,7 @@ const installStorybook = ( }; try { - return runGenerator(); + return await runGenerator(); } catch (err) { logger.error(`\n ${chalk.red(err.stack)}`); throw new HandledError(err); @@ -291,7 +291,7 @@ async function doInitiate(options: CommandOptions, pkg: PackageJson): Promise; public abstract getRunStorybookCommand(): string; public abstract getRunCommand(command: string): string; + public readonly cwd?: string; + // NOTE: for some reason yarn prefers the npm registry in // local development, so always use npm - setRegistryURL(url: string) { + async setRegistryURL(url: string) { if (url) { - this.executeCommand('npm', ['config', 'set', 'registry', url]); + await this.executeCommand({ command: 'npm', args: ['config', 'set', 'registry', url] }); } else { - this.executeCommand('npm', ['config', 'delete', 'registry']); + await this.executeCommand({ command: 'npm', args: ['config', 'delete', 'registry'] }); } } - getRegistryURL() { - const url = this.executeCommand('npm', ['config', 'get', 'registry']).trim(); + async getRegistryURL() { + const res = await this.executeCommand({ command: 'npm', args: ['config', 'get', 'registry'] }); + const url = res.trim(); return url === 'undefined' ? undefined : url; } - public readonly cwd?: string; - constructor(options?: JsPackageManagerOptions) { this.cwd = options?.cwd; } @@ -68,7 +72,7 @@ export abstract class JsPackageManager { /** * Install dependencies listed in `package.json` */ - public installDependencies(): void { + public async installDependencies() { let done = commandLog('Preparing to install dependencies'); done(); logger.log(); @@ -77,7 +81,7 @@ export abstract class JsPackageManager { done = commandLog('Installing dependencies'); try { - this.runInstall(); + await this.runInstall(); } catch (e) { done('An error occurred while installing dependencies.'); throw new HandledError(e); @@ -89,17 +93,17 @@ export abstract class JsPackageManager { return this.cwd ? path.resolve(this.cwd, 'package.json') : path.resolve('package.json'); } - readPackageJson(): PackageJson { + async readPackageJson(): Promise { const packageJsonPath = this.packageJsonPath(); if (!fs.existsSync(packageJsonPath)) { throw new Error(`Could not read package.json file at ${packageJsonPath}`); } - const jsonContent = fs.readFileSync(packageJsonPath, 'utf8'); + const jsonContent = await readFile(packageJsonPath, 'utf8'); return JSON.parse(jsonContent); } - writePackageJson(packageJson: PackageJson) { + async writePackageJson(packageJson: PackageJson) { const packageJsonToWrite = { ...packageJson }; // make sure to not accidentally add empty fields if ( @@ -122,20 +126,31 @@ export abstract class JsPackageManager { } const content = `${JSON.stringify(packageJsonToWrite, null, 2)}\n`; - fs.writeFileSync(this.packageJsonPath(), content, 'utf8'); + await writeFile(this.packageJsonPath(), content, 'utf8'); } /** * Read the `package.json` file available in the directory the command was call from * If there is no `package.json` it will create one. */ - public retrievePackageJson(): PackageJsonWithDepsAndDevDeps { + public async retrievePackageJson(): Promise { let packageJson; try { - packageJson = this.readPackageJson(); + packageJson = await this.readPackageJson(); } catch (err) { - this.initPackageJson(); - packageJson = this.readPackageJson(); + if (err.message.includes('Could not read package.json')) { + await this.initPackageJson(); + packageJson = await this.readPackageJson(); + } else { + throw new Error( + dedent` + There was an error while reading the package.json file at ${this.packageJsonPath()}: ${ + err.message + } + Please fix the error and try again. + ` + ); + } } return { @@ -146,8 +161,8 @@ export abstract class JsPackageManager { }; } - public getAllDependencies(): Record { - const { dependencies, devDependencies, peerDependencies } = this.retrievePackageJson(); + public async getAllDependencies(): Promise> { + const { dependencies, devDependencies, peerDependencies } = await this.retrievePackageJson(); return { ...dependencies, @@ -169,14 +184,14 @@ export abstract class JsPackageManager { * `@storybook/preview-api@${addonsVersion}`, * ]); */ - public addDependencies( + public async addDependencies( options: { skipInstall?: boolean; installAsDevDependencies?: boolean; packageJson?: PackageJson; }, dependencies: string[] - ): void { + ) { const { skipInstall } = options; if (skipInstall) { @@ -198,10 +213,10 @@ export abstract class JsPackageManager { ...dependenciesMap, }; } - this.writePackageJson(packageJson); + await this.writePackageJson(packageJson); } else { try { - this.runAddDeps(dependencies, options.installAsDevDependencies); + await this.runAddDeps(dependencies, options.installAsDevDependencies); } catch (e) { logger.error('An error occurred while installing dependencies.'); logger.log(e.message); @@ -337,22 +352,22 @@ export abstract class JsPackageManager { return versions.reverse().find((version) => satisfies(version, constraint)); } - public addStorybookCommandInScripts(options?: { port: number; preCommand?: string }) { + public async addStorybookCommandInScripts(options?: { port: number; preCommand?: string }) { const sbPort = options?.port ?? 6006; const storybookCmd = `storybook dev -p ${sbPort}`; const buildStorybookCmd = `storybook build`; const preCommand = options?.preCommand ? this.getRunCommand(options.preCommand) : undefined; - this.addScripts({ + await this.addScripts({ storybook: [preCommand, storybookCmd].filter(Boolean).join(' && '), 'build-storybook': [preCommand, buildStorybookCmd].filter(Boolean).join(' && '), }); } - public addESLintConfig() { - const packageJson = this.retrievePackageJson(); - this.writePackageJson({ + public async addESLintConfig() { + const packageJson = await this.retrievePackageJson(); + await this.writePackageJson({ ...packageJson, eslintConfig: { ...packageJson.eslintConfig, @@ -369,9 +384,9 @@ export abstract class JsPackageManager { }); } - public addScripts(scripts: Record) { - const packageJson = this.retrievePackageJson(); - this.writePackageJson({ + public async addScripts(scripts: Record) { + const packageJson = await this.retrievePackageJson(); + await this.writePackageJson({ ...packageJson, scripts: { ...packageJson.scripts, @@ -380,17 +395,20 @@ export abstract class JsPackageManager { }); } - public addPackageResolutions(versions: Record) { - const packageJson = this.retrievePackageJson(); + public async addPackageResolutions(versions: Record) { + const packageJson = await this.retrievePackageJson(); const resolutions = this.getResolutions(packageJson, versions); this.writePackageJson({ ...packageJson, ...resolutions }); } - protected abstract runInstall(): void; + protected abstract runInstall(): Promise; - protected abstract runAddDeps(dependencies: string[], installAsDevDependencies: boolean): void; + protected abstract runAddDeps( + dependencies: string[], + installAsDevDependencies: boolean + ): Promise; - protected abstract runRemoveDeps(dependencies: string[]): void; + protected abstract runRemoveDeps(dependencies: string[]): Promise; protected abstract getResolutions( packageJson: PackageJson, @@ -409,27 +427,73 @@ export abstract class JsPackageManager { ): // Use generic and conditional type to force `string[]` if fetchAllVersions is true and `string` if false Promise; - public abstract runPackageCommand(command: string, args: string[], cwd?: string): string; - public abstract findInstallations(pattern?: string[]): InstallationMetadata | undefined; - - public executeCommand( - command: string, - args: string[], - stdio?: 'pipe' | 'inherit', - cwd?: string, - ignoreError?: boolean - ): string { - const commandResult = spawnSync(command, args, { - cwd: cwd ?? this.cwd, - stdio: stdio ?? 'pipe', - encoding: 'utf-8', - shell: true, - }); + public abstract runPackageCommand(command: string, args: string[], cwd?: string): Promise; + public abstract runPackageCommandSync(command: string, args: string[], cwd?: string): string; + public abstract findInstallations(pattern?: string[]): Promise; + + public executeCommandSync({ + command, + args = [], + stdio, + cwd, + ignoreError = false, + env, + ...execaOptions + }: CommonOptions & { + command: string; + args: string[]; + cwd?: string; + ignoreError?: boolean; + }): string { + try { + const commandResult = execaCommandSync(command, args, { + cwd: cwd ?? this.cwd, + stdio: stdio ?? 'pipe', + encoding: 'utf-8', + shell: true, + env, + ...execaOptions, + }); - if (commandResult.status !== 0 && ignoreError !== true) { - throw new Error(commandResult.stderr ?? ''); + return commandResult.stdout ?? ''; + } catch (err) { + if (ignoreError !== true) { + throw err; + } + return ''; } + } + + public async executeCommand({ + command, + args = [], + stdio, + cwd, + ignoreError = false, + env, + ...execaOptions + }: CommonOptions & { + command: string; + args: string[]; + cwd?: string; + ignoreError?: boolean; + }): Promise { + try { + const commandResult = await execaCommand([command, ...args].join(' '), { + cwd: cwd ?? this.cwd, + stdio: stdio ?? 'pipe', + encoding: 'utf-8', + shell: true, + env, + ...execaOptions, + }); - return commandResult.stdout ?? ''; + return commandResult.stdout ?? ''; + } catch (err) { + if (ignoreError !== true) { + throw err; + } + return ''; + } } } diff --git a/code/lib/cli/src/js-package-manager/NPMProxy.test.ts b/code/lib/cli/src/js-package-manager/NPMProxy.test.ts index aa40df1a80cd..c0c8cb63be52 100644 --- a/code/lib/cli/src/js-package-manager/NPMProxy.test.ts +++ b/code/lib/cli/src/js-package-manager/NPMProxy.test.ts @@ -12,77 +12,91 @@ describe('NPM Proxy', () => { }); describe('initPackageJson', () => { - it('should run `npm init -y`', () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue(''); + it('should run `npm init -y`', async () => { + const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockResolvedValueOnce(''); - npmProxy.initPackageJson(); + await npmProxy.initPackageJson(); - expect(executeCommandSpy).toHaveBeenCalledWith('npm', ['init', '-y']); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ command: 'npm', args: ['init', '-y'] }) + ); }); }); describe('setRegistryUrl', () => { - it('should run `npm config set registry https://foo.bar`', () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue(''); + it('should run `npm config set registry https://foo.bar`', async () => { + const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockResolvedValueOnce(''); - npmProxy.setRegistryURL('https://foo.bar'); + await npmProxy.setRegistryURL('https://foo.bar'); - expect(executeCommandSpy).toHaveBeenCalledWith('npm', [ - 'config', - 'set', - 'registry', - 'https://foo.bar', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'npm', + args: ['config', 'set', 'registry', 'https://foo.bar'], + }) + ); }); }); describe('installDependencies', () => { describe('npm6', () => { - it('should run `npm install`', () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('6.0.0'); + it('should run `npm install`', async () => { + const executeCommandSpy = jest + .spyOn(npmProxy, 'executeCommand') + .mockResolvedValueOnce('6.0.0'); - npmProxy.installDependencies(); + await npmProxy.installDependencies(); - expect(executeCommandSpy).toHaveBeenLastCalledWith('npm', ['install'], expect.any(String)); + expect(executeCommandSpy).toHaveBeenLastCalledWith( + expect.objectContaining({ command: 'npm', args: ['install'] }) + ); }); }); describe('npm7', () => { - it('should run `npm install`', () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('7.1.0'); + it('should run `npm install`', async () => { + const executeCommandSpy = jest + .spyOn(npmProxy, 'executeCommand') + .mockResolvedValueOnce('7.1.0'); - npmProxy.installDependencies(); + await npmProxy.installDependencies(); - expect(executeCommandSpy).toHaveBeenLastCalledWith('npm', ['install'], expect.any(String)); + expect(executeCommandSpy).toHaveBeenLastCalledWith( + expect.objectContaining({ command: 'npm', args: ['install'] }) + ); }); }); }); describe('runScript', () => { describe('npm6', () => { - it('should execute script `npm exec -- compodoc -e json -d .`', () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('6.0.0'); + it('should execute script `npm exec -- compodoc -e json -d .`', async () => { + const executeCommandSpy = jest + .spyOn(npmProxy, 'executeCommand') + .mockResolvedValueOnce('6.0.0'); npmProxy.runPackageCommand('compodoc', ['-e', 'json', '-d', '.']); expect(executeCommandSpy).toHaveBeenLastCalledWith( - 'npm', - ['exec', '--', 'compodoc', '-e', 'json', '-d', '.'], - undefined, - undefined + expect.objectContaining({ + command: 'npm', + args: ['exec', '--', 'compodoc', '-e', 'json', '-d', '.'], + }) ); }); }); describe('npm7', () => { - it('should execute script `npm run compodoc -- -e json -d .`', () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('7.1.0'); + it('should execute script `npm run compodoc -- -e json -d .`', async () => { + const executeCommandSpy = jest + .spyOn(npmProxy, 'executeCommand') + .mockResolvedValueOnce('7.1.0'); - npmProxy.runPackageCommand('compodoc', ['-e', 'json', '-d', '.']); + await npmProxy.runPackageCommand('compodoc', ['-e', 'json', '-d', '.']); expect(executeCommandSpy).toHaveBeenLastCalledWith( - 'npm', - ['exec', '--', 'compodoc', '-e', 'json', '-d', '.'], - undefined, - undefined + expect.objectContaining({ + command: 'npm', + args: ['exec', '--', 'compodoc', '-e', 'json', '-d', '.'], + }) ); }); }); @@ -90,28 +104,38 @@ describe('NPM Proxy', () => { describe('addDependencies', () => { describe('npm6', () => { - it('with devDep it should run `npm install -D @storybook/preview-api`', () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('6.0.0'); + it('with devDep it should run `npm install -D @storybook/preview-api`', async () => { + const executeCommandSpy = jest + .spyOn(npmProxy, 'executeCommand') + .mockResolvedValueOnce('6.0.0'); - npmProxy.addDependencies({ installAsDevDependencies: true }, ['@storybook/preview-api']); + await npmProxy.addDependencies({ installAsDevDependencies: true }, [ + '@storybook/preview-api', + ]); expect(executeCommandSpy).toHaveBeenLastCalledWith( - 'npm', - ['install', '-D', '@storybook/preview-api'], - expect.any(String) + expect.objectContaining({ + command: 'npm', + args: ['install', '-D', '@storybook/preview-api'], + }) ); }); }); describe('npm7', () => { - it('with devDep it should run `npm install -D @storybook/preview-api`', () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('7.0.0'); + it('with devDep it should run `npm install -D @storybook/preview-api`', async () => { + const executeCommandSpy = jest + .spyOn(npmProxy, 'executeCommand') + .mockResolvedValueOnce('7.0.0'); - npmProxy.addDependencies({ installAsDevDependencies: true }, ['@storybook/preview-api']); + await npmProxy.addDependencies({ installAsDevDependencies: true }, [ + '@storybook/preview-api', + ]); expect(executeCommandSpy).toHaveBeenLastCalledWith( - 'npm', - ['install', '-D', '@storybook/preview-api'], - expect.any(String) + expect.objectContaining({ + command: 'npm', + args: ['install', '-D', '@storybook/preview-api'], + }) ); }); }); @@ -119,39 +143,41 @@ describe('NPM Proxy', () => { describe('removeDependencies', () => { describe('npm6', () => { - it('with devDep it should run `npm uninstall @storybook/preview-api`', () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('6.0.0'); + it('with devDep it should run `npm uninstall @storybook/preview-api`', async () => { + const executeCommandSpy = jest + .spyOn(npmProxy, 'executeCommand') + .mockResolvedValueOnce('6.0.0'); npmProxy.removeDependencies({}, ['@storybook/preview-api']); expect(executeCommandSpy).toHaveBeenLastCalledWith( - 'npm', - ['uninstall', '@storybook/preview-api'], - expect.any(String) + expect.objectContaining({ command: 'npm', args: ['uninstall', '@storybook/preview-api'] }) ); }); }); describe('npm7', () => { - it('with devDep it should run `npm uninstall @storybook/preview-api`', () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('7.0.0'); + it('with devDep it should run `npm uninstall @storybook/preview-api`', async () => { + const executeCommandSpy = jest + .spyOn(npmProxy, 'executeCommand') + .mockResolvedValueOnce('7.0.0'); - npmProxy.removeDependencies({}, ['@storybook/preview-api']); + await npmProxy.removeDependencies({}, ['@storybook/preview-api']); expect(executeCommandSpy).toHaveBeenLastCalledWith( - 'npm', - ['uninstall', '@storybook/preview-api'], - expect.any(String) + expect.objectContaining({ command: 'npm', args: ['uninstall', '@storybook/preview-api'] }) ); }); }); describe('skipInstall', () => { - it('should only change package.json without running install', () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('7.0.0'); + it('should only change package.json without running install', async () => { + const executeCommandSpy = jest + .spyOn(npmProxy, 'executeCommand') + .mockResolvedValueOnce('7.0.0'); const writePackageSpy = jest .spyOn(npmProxy, 'writePackageJson') - .mockImplementation(jest.fn); + .mockImplementation(jest.fn()); - npmProxy.removeDependencies( + await npmProxy.removeDependencies( { skipInstall: true, packageJson: { @@ -176,37 +202,39 @@ describe('NPM Proxy', () => { describe('latestVersion', () => { it('without constraint it returns the latest version', async () => { - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('"5.3.19"'); + const executeCommandSpy = jest + .spyOn(npmProxy, 'executeCommand') + .mockResolvedValueOnce('"5.3.19"'); const version = await npmProxy.latestVersion('@storybook/preview-api'); - expect(executeCommandSpy).toHaveBeenCalledWith('npm', [ - 'info', - '@storybook/preview-api', - 'version', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'npm', + args: ['info', '@storybook/preview-api', 'version', '--json'], + }) + ); expect(version).toEqual('5.3.19'); }); it('with constraint it returns the latest version satisfying the constraint', async () => { const executeCommandSpy = jest .spyOn(npmProxy, 'executeCommand') - .mockReturnValue('["4.25.3","5.3.19","6.0.0-beta.23"]'); + .mockResolvedValueOnce('["4.25.3","5.3.19","6.0.0-beta.23"]'); const version = await npmProxy.latestVersion('@storybook/preview-api', '5.X'); - expect(executeCommandSpy).toHaveBeenCalledWith('npm', [ - 'info', - '@storybook/preview-api', - 'versions', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'npm', + args: ['info', '@storybook/preview-api', 'versions', '--json'], + }) + ); expect(version).toEqual('5.3.19'); }); it('throws an error if command output is not a valid JSON', async () => { - jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('NOT A JSON'); + jest.spyOn(npmProxy, 'executeCommand').mockResolvedValueOnce('NOT A JSON'); await expect(npmProxy.latestVersion('@storybook/preview-api')).rejects.toThrow(); }); @@ -216,16 +244,18 @@ describe('NPM Proxy', () => { it('with a Storybook package listed in versions.json it returns the version', async () => { // eslint-disable-next-line global-require const storybookAngularVersion = require('../versions').default['@storybook/angular']; - const executeCommandSpy = jest.spyOn(npmProxy, 'executeCommand').mockReturnValue('"5.3.19"'); + const executeCommandSpy = jest + .spyOn(npmProxy, 'executeCommand') + .mockResolvedValueOnce('"5.3.19"'); const version = await npmProxy.getVersion('@storybook/angular'); - expect(executeCommandSpy).toHaveBeenCalledWith('npm', [ - 'info', - '@storybook/angular', - 'version', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'npm', + args: ['info', '@storybook/angular', 'version', '--json'], + }) + ); expect(version).toEqual(`^${storybookAngularVersion}`); }); @@ -233,26 +263,28 @@ describe('NPM Proxy', () => { const packageVersion = '5.3.19'; const executeCommandSpy = jest .spyOn(npmProxy, 'executeCommand') - .mockReturnValue(`"${packageVersion}"`); + .mockResolvedValueOnce(`"${packageVersion}"`); const version = await npmProxy.getVersion('@storybook/react-native'); - expect(executeCommandSpy).toHaveBeenCalledWith('npm', [ - 'info', - '@storybook/react-native', - 'version', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'npm', + args: ['info', '@storybook/react-native', 'version', '--json'], + }) + ); expect(version).toEqual(`^${packageVersion}`); }); }); describe('addPackageResolutions', () => { - it('adds resolutions to package.json and account for existing resolutions', () => { - const writePackageSpy = jest.spyOn(npmProxy, 'writePackageJson').mockImplementation(jest.fn); + it('adds resolutions to package.json and account for existing resolutions', async () => { + const writePackageSpy = jest + .spyOn(npmProxy, 'writePackageJson') + .mockImplementation(jest.fn()); jest.spyOn(npmProxy, 'retrievePackageJson').mockImplementation( - jest.fn(() => ({ + jest.fn(async () => ({ dependencies: {}, devDependencies: {}, overrides: { @@ -264,7 +296,7 @@ describe('NPM Proxy', () => { const versions = { foo: 'x.x.x', }; - npmProxy.addPackageResolutions(versions); + await npmProxy.addPackageResolutions(versions); expect(writePackageSpy).toHaveBeenCalledWith({ dependencies: {}, @@ -280,7 +312,7 @@ describe('NPM Proxy', () => { describe('mapDependencies', () => { it('should display duplicated dependencies based on npm output', async () => { // npm ls --depth 10 --json - jest.spyOn(npmProxy, 'executeCommand').mockReturnValue(` + jest.spyOn(npmProxy, 'executeCommand').mockResolvedValueOnce(` { "dependencies": { "unrelated-and-should-be-filtered": { diff --git a/code/lib/cli/src/js-package-manager/NPMProxy.ts b/code/lib/cli/src/js-package-manager/NPMProxy.ts index f8f7eb9f231f..090bc93fed16 100644 --- a/code/lib/cli/src/js-package-manager/NPMProxy.ts +++ b/code/lib/cli/src/js-package-manager/NPMProxy.ts @@ -24,8 +24,8 @@ export class NPMProxy extends JsPackageManager { installArgs: string[] | undefined; - initPackageJson() { - return this.executeCommand('npm', ['init', '-y']); + async initPackageJson() { + await this.executeCommand({ command: 'npm', args: ['init', '-y'] }); } getRunStorybookCommand(): string { @@ -36,8 +36,8 @@ export class NPMProxy extends JsPackageManager { return `npm run ${command}`; } - getNpmVersion(): string { - return this.executeCommand('npm', ['--version']); + async getNpmVersion(): Promise { + return this.executeCommand({ command: 'npm', args: ['--version'] }); } getInstallArgs(): string[] { @@ -47,20 +47,30 @@ export class NPMProxy extends JsPackageManager { return this.installArgs; } - public runPackageCommand(command: string, args: string[], cwd?: string): string { - return this.executeCommand('npm', ['exec', '--', command, ...args], undefined, cwd); + public runPackageCommandSync(command: string, args: string[], cwd?: string): string { + return this.executeCommandSync({ + command: 'npm', + args: ['exec', '--', command, ...args], + cwd, + }); } - public findInstallations() { + public async runPackageCommand(command: string, args: string[], cwd?: string): Promise { + return this.executeCommand({ + command: 'npm', + args: ['exec', '--', command, ...args], + cwd, + }); + } + + public async findInstallations() { const pipeToNull = platform() === 'win32' ? '2>NUL' : '2>/dev/null'; - const commandResult = this.executeCommand( - 'npm', - ['ls', '--json', '--depth=99', pipeToNull], - undefined, - undefined, + 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 - true - ); + ignoreError: true, + }); try { const parsedOutput = JSON.parse(commandResult); @@ -79,33 +89,48 @@ export class NPMProxy extends JsPackageManager { }; } - protected runInstall(): void { - this.executeCommand('npm', ['install', ...this.getInstallArgs()], 'inherit'); + protected async runInstall() { + await this.executeCommand({ + command: 'npm', + args: ['install', ...this.getInstallArgs()], + stdio: 'inherit', + }); } - protected runAddDeps(dependencies: string[], installAsDevDependencies: boolean): void { + protected async runAddDeps(dependencies: string[], installAsDevDependencies: boolean) { let args = [...dependencies]; if (installAsDevDependencies) { args = ['-D', ...args]; } - this.executeCommand('npm', ['install', ...this.getInstallArgs(), ...args], 'inherit'); + await this.executeCommand({ + command: 'npm', + args: ['install', ...this.getInstallArgs(), ...args], + stdio: 'inherit', + }); } - protected runRemoveDeps(dependencies: string[]): void { + protected async runRemoveDeps(dependencies: string[]) { const args = [...dependencies]; - this.executeCommand('npm', ['uninstall', ...this.getInstallArgs(), ...args], 'inherit'); + await this.executeCommand({ + command: 'npm', + args: ['uninstall', ...this.getInstallArgs(), ...args], + stdio: 'inherit', + }); } - protected runGetVersions( + protected async runGetVersions( packageName: string, fetchAllVersions: T ): Promise { const args = [fetchAllVersions ? 'versions' : 'version', '--json']; - const commandResult = this.executeCommand('npm', ['info', packageName, ...args]); + const commandResult = await this.executeCommand({ + command: 'npm', + args: ['info', packageName, ...args], + }); try { const parsedOutput = JSON.parse(commandResult); diff --git a/code/lib/cli/src/js-package-manager/PNPMProxy.test.ts b/code/lib/cli/src/js-package-manager/PNPMProxy.test.ts index 84edf7fd98ab..eb82f1a06465 100644 --- a/code/lib/cli/src/js-package-manager/PNPMProxy.test.ts +++ b/code/lib/cli/src/js-package-manager/PNPMProxy.test.ts @@ -12,90 +12,102 @@ describe('NPM Proxy', () => { }); describe('initPackageJson', () => { - it('should run `npm init -y`', () => { - const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue(''); + it('should run `npm init -y`', async () => { + const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockResolvedValueOnce(''); - pnpmProxy.initPackageJson(); + await pnpmProxy.initPackageJson(); - expect(executeCommandSpy).toHaveBeenCalledWith('pnpm', ['init', '-y']); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ command: 'pnpm', args: ['init', '-y'] }) + ); }); }); describe('setRegistryUrl', () => { - it('should run `npm config set registry https://foo.bar`', () => { - const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue(''); + it('should run `npm config set registry https://foo.bar`', async () => { + const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockResolvedValueOnce(''); - pnpmProxy.setRegistryURL('https://foo.bar'); + await pnpmProxy.setRegistryURL('https://foo.bar'); - expect(executeCommandSpy).toHaveBeenCalledWith('npm', [ - 'config', - 'set', - 'registry', - 'https://foo.bar', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'npm', + args: ['config', 'set', 'registry', 'https://foo.bar'], + }) + ); }); }); describe('installDependencies', () => { - it('should run `pnpm install`', () => { - const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('7.1.0'); + it('should run `pnpm install`', async () => { + const executeCommandSpy = jest + .spyOn(pnpmProxy, 'executeCommand') + .mockResolvedValueOnce('7.1.0'); - pnpmProxy.installDependencies(); + await pnpmProxy.installDependencies(); - expect(executeCommandSpy).toHaveBeenLastCalledWith('pnpm', ['install'], expect.any(String)); + expect(executeCommandSpy).toHaveBeenLastCalledWith( + expect.objectContaining({ command: 'pnpm', args: ['install'] }) + ); }); }); describe('runScript', () => { - it('should execute script `yarn compodoc -- -e json -d .`', () => { - const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('7.1.0'); + it('should execute script `yarn compodoc -- -e json -d .`', async () => { + const executeCommandSpy = jest + .spyOn(pnpmProxy, 'executeCommand') + .mockResolvedValueOnce('7.1.0'); - pnpmProxy.runPackageCommand('compodoc', ['-e', 'json', '-d', '.']); + await pnpmProxy.runPackageCommand('compodoc', ['-e', 'json', '-d', '.']); expect(executeCommandSpy).toHaveBeenLastCalledWith( - 'pnpm', - ['exec', 'compodoc', '-e', 'json', '-d', '.'], - undefined, - undefined + expect.objectContaining({ + command: 'pnpm', + args: ['exec', 'compodoc', '-e', 'json', '-d', '.'], + }) ); }); }); describe('addDependencies', () => { - it('with devDep it should run `pnpm add -D @storybook/preview-api`', () => { - const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('6.0.0'); + it('with devDep it should run `pnpm add -D @storybook/preview-api`', async () => { + const executeCommandSpy = jest + .spyOn(pnpmProxy, 'executeCommand') + .mockResolvedValueOnce('6.0.0'); - pnpmProxy.addDependencies({ installAsDevDependencies: true }, ['@storybook/preview-api']); + await pnpmProxy.addDependencies({ installAsDevDependencies: true }, [ + '@storybook/preview-api', + ]); expect(executeCommandSpy).toHaveBeenLastCalledWith( - 'pnpm', - ['add', '-D', '@storybook/preview-api'], - expect.any(String) + expect.objectContaining({ command: 'pnpm', args: ['add', '-D', '@storybook/preview-api'] }) ); }); }); describe('removeDependencies', () => { - it('with devDep it should run `npm uninstall @storybook/preview-api`', () => { - const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('6.0.0'); + it('with devDep it should run `npm uninstall @storybook/preview-api`', async () => { + const executeCommandSpy = jest + .spyOn(pnpmProxy, 'executeCommand') + .mockResolvedValueOnce('6.0.0'); - pnpmProxy.removeDependencies({}, ['@storybook/preview-api']); + await pnpmProxy.removeDependencies({}, ['@storybook/preview-api']); expect(executeCommandSpy).toHaveBeenLastCalledWith( - 'pnpm', - ['remove', '@storybook/preview-api'], - expect.any(String) + expect.objectContaining({ command: 'pnpm', args: ['remove', '@storybook/preview-api'] }) ); }); describe('skipInstall', () => { - it('should only change package.json without running install', () => { - const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('7.0.0'); + it('should only change package.json without running install', async () => { + const executeCommandSpy = jest + .spyOn(pnpmProxy, 'executeCommand') + .mockResolvedValueOnce('7.0.0'); const writePackageSpy = jest .spyOn(pnpmProxy, 'writePackageJson') - .mockImplementation(jest.fn); + .mockImplementation(jest.fn()); - pnpmProxy.removeDependencies( + await pnpmProxy.removeDependencies( { skipInstall: true, packageJson: { @@ -120,37 +132,39 @@ describe('NPM Proxy', () => { describe('latestVersion', () => { it('without constraint it returns the latest version', async () => { - const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('"5.3.19"'); + const executeCommandSpy = jest + .spyOn(pnpmProxy, 'executeCommand') + .mockResolvedValueOnce('"5.3.19"'); const version = await pnpmProxy.latestVersion('@storybook/preview-api'); - expect(executeCommandSpy).toHaveBeenCalledWith('pnpm', [ - 'info', - '@storybook/preview-api', - 'version', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'pnpm', + args: ['info', '@storybook/preview-api', 'version', '--json'], + }) + ); expect(version).toEqual('5.3.19'); }); it('with constraint it returns the latest version satisfying the constraint', async () => { const executeCommandSpy = jest .spyOn(pnpmProxy, 'executeCommand') - .mockReturnValue('["4.25.3","5.3.19","6.0.0-beta.23"]'); + .mockResolvedValueOnce('["4.25.3","5.3.19","6.0.0-beta.23"]'); const version = await pnpmProxy.latestVersion('@storybook/preview-api', '5.X'); - expect(executeCommandSpy).toHaveBeenCalledWith('pnpm', [ - 'info', - '@storybook/preview-api', - 'versions', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'pnpm', + args: ['info', '@storybook/preview-api', 'versions', '--json'], + }) + ); expect(version).toEqual('5.3.19'); }); it('throws an error if command output is not a valid JSON', async () => { - jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('NOT A JSON'); + jest.spyOn(pnpmProxy, 'executeCommand').mockResolvedValueOnce('NOT A JSON'); await expect(pnpmProxy.latestVersion('@storybook/preview-api')).rejects.toThrow(); }); @@ -160,16 +174,18 @@ describe('NPM Proxy', () => { it('with a Storybook package listed in versions.json it returns the version', async () => { // eslint-disable-next-line global-require const storybookAngularVersion = require('../versions').default['@storybook/angular']; - const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('"5.3.19"'); + const executeCommandSpy = jest + .spyOn(pnpmProxy, 'executeCommand') + .mockResolvedValueOnce('"5.3.19"'); const version = await pnpmProxy.getVersion('@storybook/angular'); - expect(executeCommandSpy).toHaveBeenCalledWith('pnpm', [ - 'info', - '@storybook/angular', - 'version', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'pnpm', + args: ['info', '@storybook/angular', 'version', '--json'], + }) + ); expect(version).toEqual(`^${storybookAngularVersion}`); }); @@ -177,23 +193,25 @@ describe('NPM Proxy', () => { const packageVersion = '5.3.19'; const executeCommandSpy = jest .spyOn(pnpmProxy, 'executeCommand') - .mockReturnValue(`"${packageVersion}"`); + .mockResolvedValueOnce(`"${packageVersion}"`); const version = await pnpmProxy.getVersion('@storybook/react-native'); - expect(executeCommandSpy).toHaveBeenCalledWith('pnpm', [ - 'info', - '@storybook/react-native', - 'version', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'pnpm', + args: ['info', '@storybook/react-native', 'version', '--json'], + }) + ); expect(version).toEqual(`^${packageVersion}`); }); }); describe('addPackageResolutions', () => { - it('adds resolutions to package.json and account for existing resolutions', () => { - const writePackageSpy = jest.spyOn(pnpmProxy, 'writePackageJson').mockImplementation(jest.fn); + it('adds resolutions to package.json and account for existing resolutions', async () => { + const writePackageSpy = jest + .spyOn(pnpmProxy, 'writePackageJson') + .mockImplementation(jest.fn()); jest.spyOn(pnpmProxy, 'retrievePackageJson').mockImplementation( // @ts-expect-error (not strict) @@ -207,7 +225,7 @@ describe('NPM Proxy', () => { const versions = { foo: 'x.x.x', }; - pnpmProxy.addPackageResolutions(versions); + await pnpmProxy.addPackageResolutions(versions); expect(writePackageSpy).toHaveBeenCalledWith({ overrides: { @@ -221,7 +239,7 @@ describe('NPM Proxy', () => { describe('mapDependencies', () => { it('should display duplicated dependencies based on pnpm output', async () => { // pnpm list "@storybook/*" "storybook" --depth 10 --json - jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue(` + jest.spyOn(pnpmProxy, 'executeCommand').mockResolvedValueOnce(` [ { "peerDependencies": { diff --git a/code/lib/cli/src/js-package-manager/PNPMProxy.ts b/code/lib/cli/src/js-package-manager/PNPMProxy.ts index 05482391057a..1c644cdb387c 100644 --- a/code/lib/cli/src/js-package-manager/PNPMProxy.ts +++ b/code/lib/cli/src/js-package-manager/PNPMProxy.ts @@ -34,8 +34,11 @@ export class PNPMProxy extends JsPackageManager { return pathExistsSync(pnpmWorkspaceYaml); } - initPackageJson() { - return this.executeCommand('pnpm', ['init', '-y']); + async initPackageJson() { + await this.executeCommand({ + command: 'pnpm', + args: ['init', '-y'], + }); } getRunStorybookCommand(): string { @@ -46,8 +49,11 @@ export class PNPMProxy extends JsPackageManager { return `pnpm run ${command}`; } - getPnpmVersion(): string { - return this.executeCommand('pnpm', ['--version']); + async getPnpmVersion(): Promise { + return this.executeCommand({ + command: 'pnpm', + args: ['--version'], + }); } getInstallArgs(): string[] { @@ -61,17 +67,27 @@ export class PNPMProxy extends JsPackageManager { return this.installArgs; } - runPackageCommand(command: string, args: string[], cwd?: string): string { - return this.executeCommand(`pnpm`, ['exec', command, ...args], undefined, cwd); + public runPackageCommandSync(command: string, args: string[], cwd?: string): string { + return this.executeCommandSync({ + command: 'pnpm', + args: ['exec', command, ...args], + cwd, + }); } - public findInstallations(pattern: string[]) { - const commandResult = this.executeCommand('pnpm', [ - 'list', - pattern.map((p) => `"${p}"`).join(' '), - '--json', - '--depth=99', - ]); + async runPackageCommand(command: string, args: string[], cwd?: string): Promise { + return this.executeCommand({ + command: 'pnpm', + args: ['exec', command, ...args], + cwd, + }); + } + + public async findInstallations(pattern: string[]) { + const commandResult = await this.executeCommand({ + command: 'pnpm', + args: ['list', pattern.map((p) => `"${p}"`).join(' '), '--json', '--depth=99'], + }); try { const parsedOutput = JSON.parse(commandResult); @@ -90,33 +106,48 @@ export class PNPMProxy extends JsPackageManager { }; } - protected runInstall(): void { - this.executeCommand('pnpm', ['install', ...this.getInstallArgs()], 'inherit'); + protected async runInstall() { + await this.executeCommand({ + command: 'pnpm', + args: ['install', ...this.getInstallArgs()], + stdio: 'inherit', + }); } - protected runAddDeps(dependencies: string[], installAsDevDependencies: boolean): void { + protected async runAddDeps(dependencies: string[], installAsDevDependencies: boolean) { let args = [...dependencies]; if (installAsDevDependencies) { args = ['-D', ...args]; } - this.executeCommand('pnpm', ['add', ...args, ...this.getInstallArgs()], 'inherit'); + await this.executeCommand({ + command: 'pnpm', + args: ['add', ...args, ...this.getInstallArgs()], + stdio: 'inherit', + }); } - protected runRemoveDeps(dependencies: string[]): void { + protected async runRemoveDeps(dependencies: string[]) { const args = [...dependencies]; - this.executeCommand('pnpm', ['remove', ...args, ...this.getInstallArgs()], 'inherit'); + await this.executeCommand({ + command: 'pnpm', + args: ['remove', ...args, ...this.getInstallArgs()], + stdio: 'inherit', + }); } - protected runGetVersions( + protected async runGetVersions( packageName: string, fetchAllVersions: T ): Promise { const args = [fetchAllVersions ? 'versions' : 'version', '--json']; - const commandResult = this.executeCommand('pnpm', ['info', packageName, ...args]); + const commandResult = await this.executeCommand({ + command: 'pnpm', + args: ['info', packageName, ...args], + }); try { const parsedOutput = JSON.parse(commandResult); diff --git a/code/lib/cli/src/js-package-manager/Yarn1Proxy.test.ts b/code/lib/cli/src/js-package-manager/Yarn1Proxy.test.ts index d7c853cc32f3..fb9edaef3cc0 100644 --- a/code/lib/cli/src/js-package-manager/Yarn1Proxy.test.ts +++ b/code/lib/cli/src/js-package-manager/Yarn1Proxy.test.ts @@ -12,93 +12,101 @@ describe('Yarn 1 Proxy', () => { }); describe('initPackageJson', () => { - it('should run `yarn init -y`', () => { - const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockReturnValue(''); + it('should run `yarn init -y`', async () => { + const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockResolvedValueOnce(''); - yarn1Proxy.initPackageJson(); + await yarn1Proxy.initPackageJson(); - expect(executeCommandSpy).toHaveBeenCalledWith('yarn', ['init', '-y']); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ command: 'yarn', args: ['init', '-y'] }) + ); }); }); describe('setRegistryUrl', () => { - it('should run `yarn config set npmRegistryServer https://foo.bar`', () => { - const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockReturnValue(''); + it('should run `yarn config set npmRegistryServer https://foo.bar`', async () => { + const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockResolvedValueOnce(''); - yarn1Proxy.setRegistryURL('https://foo.bar'); + await yarn1Proxy.setRegistryURL('https://foo.bar'); - expect(executeCommandSpy).toHaveBeenCalledWith('npm', [ - 'config', - 'set', - 'registry', - 'https://foo.bar', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'npm', + args: ['config', 'set', 'registry', 'https://foo.bar'], + }) + ); }); }); describe('installDependencies', () => { - it('should run `yarn`', () => { - const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockReturnValue(''); + it('should run `yarn`', async () => { + const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockResolvedValueOnce(''); - yarn1Proxy.installDependencies(); + await yarn1Proxy.installDependencies(); expect(executeCommandSpy).toHaveBeenCalledWith( - 'yarn', - ['install', '--ignore-workspace-root-check'], - expect.any(String) + expect.objectContaining({ + command: 'yarn', + args: ['install', '--ignore-workspace-root-check'], + }) ); }); }); describe('runScript', () => { - it('should execute script `yarn compodoc -- -e json -d .`', () => { - const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockReturnValue('7.1.0'); + it('should execute script `yarn compodoc -- -e json -d .`', async () => { + const executeCommandSpy = jest + .spyOn(yarn1Proxy, 'executeCommand') + .mockResolvedValueOnce('7.1.0'); - yarn1Proxy.runPackageCommand('compodoc', ['-e', 'json', '-d', '.']); + await yarn1Proxy.runPackageCommand('compodoc', ['-e', 'json', '-d', '.']); expect(executeCommandSpy).toHaveBeenLastCalledWith( - 'yarn', - ['compodoc', '-e', 'json', '-d', '.'], - undefined, - undefined + expect.objectContaining({ command: 'yarn', args: ['compodoc', '-e', 'json', '-d', '.'] }) ); }); }); describe('addDependencies', () => { - it('with devDep it should run `yarn install -D --ignore-workspace-root-check @storybook/preview-api`', () => { - const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockReturnValue(''); + it('with devDep it should run `yarn install -D --ignore-workspace-root-check @storybook/preview-api`', async () => { + const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockResolvedValueOnce(''); - yarn1Proxy.addDependencies({ installAsDevDependencies: true }, ['@storybook/preview-api']); + await yarn1Proxy.addDependencies({ installAsDevDependencies: true }, [ + '@storybook/preview-api', + ]); expect(executeCommandSpy).toHaveBeenCalledWith( - 'yarn', - ['add', '--ignore-workspace-root-check', '-D', '@storybook/preview-api'], - expect.any(String) + expect.objectContaining({ + command: 'yarn', + args: ['add', '--ignore-workspace-root-check', '-D', '@storybook/preview-api'], + }) ); }); }); describe('removeDependencies', () => { - it('should run `yarn remove --ignore-workspace-root-check @storybook/preview-api`', () => { - const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockReturnValue(''); + it('should run `yarn remove --ignore-workspace-root-check @storybook/preview-api`', async () => { + const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockResolvedValueOnce(''); yarn1Proxy.removeDependencies({}, ['@storybook/preview-api']); expect(executeCommandSpy).toHaveBeenCalledWith( - 'yarn', - ['remove', '--ignore-workspace-root-check', '@storybook/preview-api'], - expect.any(String) + expect.objectContaining({ + command: 'yarn', + args: ['remove', '--ignore-workspace-root-check', '@storybook/preview-api'], + }) ); }); - it('skipInstall should only change package.json without running install', () => { - const executeCommandSpy = jest.spyOn(yarn1Proxy, 'executeCommand').mockReturnValue('7.0.0'); + it('skipInstall should only change package.json without running install', async () => { + const executeCommandSpy = jest + .spyOn(yarn1Proxy, 'executeCommand') + .mockResolvedValueOnce('7.0.0'); const writePackageSpy = jest .spyOn(yarn1Proxy, 'writePackageJson') - .mockImplementation(jest.fn); + .mockImplementation(jest.fn()); - yarn1Proxy.removeDependencies( + await yarn1Proxy.removeDependencies( { skipInstall: true, packageJson: { @@ -124,50 +132,50 @@ describe('Yarn 1 Proxy', () => { it('without constraint it returns the latest version', async () => { const executeCommandSpy = jest .spyOn(yarn1Proxy, 'executeCommand') - .mockReturnValue('{"type":"inspect","data":"5.3.19"}'); + .mockResolvedValueOnce('{"type":"inspect","data":"5.3.19"}'); const version = await yarn1Proxy.latestVersion('@storybook/preview-api'); - expect(executeCommandSpy).toHaveBeenCalledWith('yarn', [ - 'info', - '@storybook/preview-api', - 'version', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'yarn', + args: ['info', '@storybook/preview-api', 'version', '--json'], + }) + ); expect(version).toEqual('5.3.19'); }); it('with constraint it returns the latest version satisfying the constraint', async () => { const executeCommandSpy = jest .spyOn(yarn1Proxy, 'executeCommand') - .mockReturnValue('{"type":"inspect","data":["4.25.3","5.3.19","6.0.0-beta.23"]}'); + .mockResolvedValueOnce('{"type":"inspect","data":["4.25.3","5.3.19","6.0.0-beta.23"]}'); const version = await yarn1Proxy.latestVersion('@storybook/preview-api', '5.X'); - expect(executeCommandSpy).toHaveBeenCalledWith('yarn', [ - 'info', - '@storybook/preview-api', - 'versions', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'yarn', + args: ['info', '@storybook/preview-api', 'versions', '--json'], + }) + ); expect(version).toEqual('5.3.19'); }); it('throws an error if command output is not a valid JSON', async () => { - jest.spyOn(yarn1Proxy, 'executeCommand').mockReturnValue('NOT A JSON'); + jest.spyOn(yarn1Proxy, 'executeCommand').mockResolvedValueOnce('NOT A JSON'); await expect(yarn1Proxy.latestVersion('@storybook/preview-api')).rejects.toThrow(); }); }); describe('addPackageResolutions', () => { - it('adds resolutions to package.json and account for existing resolutions', () => { + it('adds resolutions to package.json and account for existing resolutions', async () => { const writePackageSpy = jest .spyOn(yarn1Proxy, 'writePackageJson') - .mockImplementation(jest.fn); + .mockImplementation(jest.fn()); jest.spyOn(yarn1Proxy, 'retrievePackageJson').mockImplementation( - jest.fn(() => ({ + jest.fn(async () => ({ dependencies: {}, devDependencies: {}, resolutions: { @@ -179,7 +187,7 @@ describe('Yarn 1 Proxy', () => { const versions = { foo: 'x.x.x', }; - yarn1Proxy.addPackageResolutions(versions); + await yarn1Proxy.addPackageResolutions(versions); expect(writePackageSpy).toHaveBeenCalledWith({ dependencies: {}, @@ -195,7 +203,7 @@ describe('Yarn 1 Proxy', () => { describe('mapDependencies', () => { it('should display duplicated dependencies based on yarn output', async () => { // yarn list --pattern "@storybook/*" "@storybook/react" --recursive --json - jest.spyOn(yarn1Proxy, 'executeCommand').mockReturnValue(` + jest.spyOn(yarn1Proxy, 'executeCommand').mockResolvedValueOnce(` { "type": "tree", "data": { diff --git a/code/lib/cli/src/js-package-manager/Yarn1Proxy.ts b/code/lib/cli/src/js-package-manager/Yarn1Proxy.ts index 46d811aaa579..ad85c1f5452b 100644 --- a/code/lib/cli/src/js-package-manager/Yarn1Proxy.ts +++ b/code/lib/cli/src/js-package-manager/Yarn1Proxy.ts @@ -30,8 +30,8 @@ export class Yarn1Proxy extends JsPackageManager { return this.installArgs; } - initPackageJson() { - return this.executeCommand('yarn', ['init', '-y']); + async initPackageJson() { + await this.executeCommand({ command: 'yarn', args: ['init', '-y'] }); } getRunStorybookCommand(): string { @@ -42,18 +42,19 @@ export class Yarn1Proxy extends JsPackageManager { return `yarn ${command}`; } - runPackageCommand(command: string, args: string[], cwd?: string): string { - return this.executeCommand(`yarn`, [command, ...args], undefined, cwd); + public runPackageCommandSync(command: string, args: string[], cwd?: string): string { + return this.executeCommandSync({ command: `yarn`, args: [command, ...args], cwd }); } - public findInstallations(pattern: string[]) { - const commandResult = this.executeCommand('yarn', [ - 'list', - '--pattern', - pattern.map((p) => `"${p}"`).join(' '), - '--recursive', - '--json', - ]); + async runPackageCommand(command: string, args: string[], cwd?: string): Promise { + return this.executeCommand({ command: `yarn`, args: [command, ...args], cwd }); + } + + public async findInstallations(pattern: string[]) { + const commandResult = await this.executeCommand({ + command: 'yarn', + args: ['list', '--pattern', pattern.map((p) => `"${p}"`).join(' '), '--recursive', '--json'], + }); try { const parsedOutput = JSON.parse(commandResult); @@ -72,33 +73,48 @@ export class Yarn1Proxy extends JsPackageManager { }; } - protected runInstall(): void { - this.executeCommand('yarn', ['install', ...this.getInstallArgs()], 'inherit'); + protected async runInstall() { + await this.executeCommand({ + command: 'yarn', + args: ['install', ...this.getInstallArgs()], + stdio: 'inherit', + }); } - protected runAddDeps(dependencies: string[], installAsDevDependencies: boolean): void { + protected async runAddDeps(dependencies: string[], installAsDevDependencies: boolean) { let args = [...dependencies]; if (installAsDevDependencies) { args = ['-D', ...args]; } - this.executeCommand('yarn', ['add', ...this.getInstallArgs(), ...args], 'inherit'); + await this.executeCommand({ + command: 'yarn', + args: ['add', ...this.getInstallArgs(), ...args], + stdio: 'inherit', + }); } - protected runRemoveDeps(dependencies: string[]): void { + protected async runRemoveDeps(dependencies: string[]) { const args = [...dependencies]; - this.executeCommand('yarn', ['remove', ...this.getInstallArgs(), ...args], 'inherit'); + await this.executeCommand({ + command: 'yarn', + args: ['remove', ...this.getInstallArgs(), ...args], + stdio: 'inherit', + }); } - protected runGetVersions( + protected async runGetVersions( packageName: string, fetchAllVersions: T ): Promise { const args = [fetchAllVersions ? 'versions' : 'version', '--json']; - const commandResult = this.executeCommand('yarn', ['info', packageName, ...args]); + const commandResult = await this.executeCommand({ + command: 'yarn', + args: ['info', packageName, ...args], + }); try { const parsedOutput = JSON.parse(commandResult); diff --git a/code/lib/cli/src/js-package-manager/Yarn2Proxy.test.ts b/code/lib/cli/src/js-package-manager/Yarn2Proxy.test.ts index 7ae7aae5675b..f875254a6858 100644 --- a/code/lib/cli/src/js-package-manager/Yarn2Proxy.test.ts +++ b/code/lib/cli/src/js-package-manager/Yarn2Proxy.test.ts @@ -12,89 +12,98 @@ describe('Yarn 2 Proxy', () => { }); describe('initPackageJson', () => { - it('should run `yarn init`', () => { - const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockReturnValue(''); + it('should run `yarn init`', async () => { + const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockResolvedValueOnce(''); - yarn2Proxy.initPackageJson(); + await yarn2Proxy.initPackageJson(); - expect(executeCommandSpy).toHaveBeenCalledWith('yarn', ['init']); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ command: 'yarn', args: ['init'] }) + ); }); }); describe('installDependencies', () => { - it('should run `yarn`', () => { - const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockReturnValue(''); + it('should run `yarn`', async () => { + const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockResolvedValueOnce(''); - yarn2Proxy.installDependencies(); + await yarn2Proxy.installDependencies(); - expect(executeCommandSpy).toHaveBeenCalledWith('yarn', ['install'], expect.any(String)); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ command: 'yarn', args: ['install'] }) + ); }); }); describe('runScript', () => { - it('should execute script `yarn compodoc -- -e json -d .`', () => { - const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockReturnValue('7.1.0'); + it('should execute script `yarn compodoc -- -e json -d .`', async () => { + const executeCommandSpy = jest + .spyOn(yarn2Proxy, 'executeCommand') + .mockResolvedValueOnce('7.1.0'); - yarn2Proxy.runPackageCommand('compodoc', ['-e', 'json', '-d', '.']); + await yarn2Proxy.runPackageCommand('compodoc', ['-e', 'json', '-d', '.']); expect(executeCommandSpy).toHaveBeenLastCalledWith( - 'yarn', - ['compodoc', '-e', 'json', '-d', '.'], - undefined, - undefined + expect.objectContaining({ + command: 'yarn', + args: ['compodoc', '-e', 'json', '-d', '.'], + }) ); }); }); describe('setRegistryUrl', () => { - it('should run `yarn config set npmRegistryServer https://foo.bar`', () => { - const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockReturnValue(''); + it('should run `yarn config set npmRegistryServer https://foo.bar`', async () => { + const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockResolvedValueOnce(''); - yarn2Proxy.setRegistryURL('https://foo.bar'); + await yarn2Proxy.setRegistryURL('https://foo.bar'); - expect(executeCommandSpy).toHaveBeenCalledWith('npm', [ - 'config', - 'set', - 'registry', - 'https://foo.bar', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'npm', + args: ['config', 'set', 'registry', 'https://foo.bar'], + }) + ); }); }); describe('addDependencies', () => { - it('with devDep it should run `yarn install -D @storybook/preview-api`', () => { - const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockReturnValue(''); + it('with devDep it should run `yarn install -D @storybook/preview-api`', async () => { + const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockResolvedValueOnce(''); - yarn2Proxy.addDependencies({ installAsDevDependencies: true }, ['@storybook/preview-api']); + await yarn2Proxy.addDependencies({ installAsDevDependencies: true }, [ + '@storybook/preview-api', + ]); expect(executeCommandSpy).toHaveBeenCalledWith( - 'yarn', - ['add', '-D', '@storybook/preview-api'], - expect.any(String) + expect.objectContaining({ command: 'yarn', args: ['add', '-D', '@storybook/preview-api'] }) ); }); }); describe('removeDependencies', () => { - it('should run `yarn remove @storybook/preview-api`', () => { - const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockReturnValue(''); + it('should run `yarn remove @storybook/preview-api`', async () => { + const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockResolvedValueOnce(''); - yarn2Proxy.removeDependencies({}, ['@storybook/preview-api']); + await yarn2Proxy.removeDependencies({}, ['@storybook/preview-api']); expect(executeCommandSpy).toHaveBeenCalledWith( - 'yarn', - ['remove', '@storybook/preview-api'], - expect.any(String) + expect.objectContaining({ + command: 'yarn', + args: ['remove', '@storybook/preview-api'], + }) ); }); - it('skipInstall should only change package.json without running install', () => { - const executeCommandSpy = jest.spyOn(yarn2Proxy, 'executeCommand').mockReturnValue('7.0.0'); + it('skipInstall should only change package.json without running install', async () => { + const executeCommandSpy = jest + .spyOn(yarn2Proxy, 'executeCommand') + .mockResolvedValueOnce('7.0.0'); const writePackageSpy = jest .spyOn(yarn2Proxy, 'writePackageJson') - .mockImplementation(jest.fn); + .mockImplementation(jest.fn()); - yarn2Proxy.removeDependencies( + await yarn2Proxy.removeDependencies( { skipInstall: true, packageJson: { @@ -120,56 +129,52 @@ describe('Yarn 2 Proxy', () => { it('without constraint it returns the latest version', async () => { const executeCommandSpy = jest .spyOn(yarn2Proxy, 'executeCommand') - .mockReturnValue('{"name":"@storybook/preview-api","version":"5.3.19"}'); + .mockResolvedValueOnce('{"name":"@storybook/preview-api","version":"5.3.19"}'); const version = await yarn2Proxy.latestVersion('@storybook/preview-api'); - expect(executeCommandSpy).toHaveBeenCalledWith('yarn', [ - 'npm', - 'info', - '@storybook/preview-api', - '--fields', - 'version', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'yarn', + args: ['npm', 'info', '@storybook/preview-api', '--fields', 'version', '--json'], + }) + ); expect(version).toEqual('5.3.19'); }); it('with constraint it returns the latest version satisfying the constraint', async () => { const executeCommandSpy = jest .spyOn(yarn2Proxy, 'executeCommand') - .mockReturnValue( + .mockResolvedValueOnce( '{"name":"@storybook/preview-api","versions":["4.25.3","5.3.19","6.0.0-beta.23"]}' ); const version = await yarn2Proxy.latestVersion('@storybook/preview-api', '5.X'); - expect(executeCommandSpy).toHaveBeenCalledWith('yarn', [ - 'npm', - 'info', - '@storybook/preview-api', - '--fields', - 'versions', - '--json', - ]); + expect(executeCommandSpy).toHaveBeenCalledWith( + expect.objectContaining({ + command: 'yarn', + args: ['npm', 'info', '@storybook/preview-api', '--fields', 'versions', '--json'], + }) + ); expect(version).toEqual('5.3.19'); }); it('throws an error if command output is not a valid JSON', async () => { - jest.spyOn(yarn2Proxy, 'executeCommand').mockReturnValue('NOT A JSON'); + jest.spyOn(yarn2Proxy, 'executeCommand').mockResolvedValueOnce('NOT A JSON'); await expect(yarn2Proxy.latestVersion('@storybook/preview-api')).rejects.toThrow(); }); }); describe('addPackageResolutions', () => { - it('adds resolutions to package.json and account for existing resolutions', () => { + it('adds resolutions to package.json and account for existing resolutions', async () => { const writePackageSpy = jest .spyOn(yarn2Proxy, 'writePackageJson') - .mockImplementation(jest.fn); + .mockImplementation(jest.fn()); jest.spyOn(yarn2Proxy, 'retrievePackageJson').mockImplementation( - jest.fn(() => ({ + jest.fn(async () => ({ dependencies: {}, devDependencies: {}, resolutions: { @@ -181,7 +186,8 @@ describe('Yarn 2 Proxy', () => { const versions = { foo: 'x.x.x', }; - yarn2Proxy.addPackageResolutions(versions); + + await yarn2Proxy.addPackageResolutions(versions); expect(writePackageSpy).toHaveBeenCalledWith({ dependencies: {}, @@ -197,7 +203,7 @@ describe('Yarn 2 Proxy', () => { describe('mapDependencies', () => { it('should display duplicated dependencies based on yarn2 output', async () => { // yarn info --name-only --recursive "@storybook/*" "storybook" - jest.spyOn(yarn2Proxy, 'executeCommand').mockReturnValue(` + jest.spyOn(yarn2Proxy, 'executeCommand').mockResolvedValueOnce(` "unrelated-and-should-be-filtered@npm:1.0.0" "@storybook/global@npm:5.0.0" "@storybook/instrumenter@npm:7.0.0-beta.12" diff --git a/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts b/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts index d5ffc42c08fa..e565e7f12ee2 100644 --- a/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts +++ b/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts @@ -16,8 +16,8 @@ export class Yarn2Proxy extends JsPackageManager { return this.installArgs; } - initPackageJson() { - return this.executeCommand('yarn', ['init']); + async initPackageJson() { + await this.executeCommand({ command: 'yarn', args: ['init'] }); } getRunStorybookCommand(): string { @@ -28,18 +28,25 @@ export class Yarn2Proxy extends JsPackageManager { return `yarn ${command}`; } - runPackageCommand(command: string, args: string[], cwd?: string): string { - return this.executeCommand(`yarn`, [command, ...args], undefined, cwd); + public runPackageCommandSync(command: string, args: string[], cwd?: string) { + return this.executeCommandSync({ command: 'yarn', args: [command, ...args], cwd }); } - public findInstallations(pattern: string[]) { - const commandResult = this.executeCommand('yarn', [ - 'info', - '--name-only', - '--recursive', - pattern.map((p) => `"${p}"`).join(' '), - `"${pattern}"`, - ]); + async runPackageCommand(command: string, args: string[], cwd?: string) { + return this.executeCommand({ command: 'yarn', args: [command, ...args], cwd }); + } + + public async findInstallations(pattern: string[]) { + const commandResult = await this.executeCommand({ + command: 'yarn', + args: [ + 'info', + '--name-only', + '--recursive', + pattern.map((p) => `"${p}"`).join(' '), + `"${pattern}"`, + ], + }); try { return this.mapDependencies(commandResult); @@ -57,34 +64,49 @@ export class Yarn2Proxy extends JsPackageManager { }; } - protected runInstall(): void { - this.executeCommand('yarn', ['install', ...this.getInstallArgs()], 'inherit'); + protected async runInstall() { + await this.executeCommand({ + command: 'yarn', + args: ['install', ...this.getInstallArgs()], + stdio: 'inherit', + }); } - protected runAddDeps(dependencies: string[], installAsDevDependencies: boolean): void { + protected async runAddDeps(dependencies: string[], installAsDevDependencies: boolean) { let args = [...dependencies]; if (installAsDevDependencies) { args = ['-D', ...args]; } - this.executeCommand('yarn', ['add', ...this.getInstallArgs(), ...args], 'inherit'); + await this.executeCommand({ + command: 'yarn', + args: ['add', ...this.getInstallArgs(), ...args], + stdio: 'inherit', + }); } - protected runRemoveDeps(dependencies: string[]): void { + protected async runRemoveDeps(dependencies: string[]) { const args = [...dependencies]; - this.executeCommand('yarn', ['remove', ...this.getInstallArgs(), ...args], 'inherit'); + await this.executeCommand({ + command: 'yarn', + args: ['remove', ...this.getInstallArgs(), ...args], + stdio: 'inherit', + }); } - protected runGetVersions( + protected async runGetVersions( packageName: string, fetchAllVersions: T ): Promise { const field = fetchAllVersions ? 'versions' : 'version'; const args = ['--fields', field, '--json']; - const commandResult = this.executeCommand('yarn', ['npm', 'info', packageName, ...args]); + const commandResult = await this.executeCommand({ + command: 'yarn', + args: ['npm', 'info', packageName, ...args], + }); try { const parsedOutput = JSON.parse(commandResult); diff --git a/code/lib/cli/src/migrate.ts b/code/lib/cli/src/migrate.ts index 7162e205b1f5..2d0a3b6af16d 100644 --- a/code/lib/cli/src/migrate.ts +++ b/code/lib/cli/src/migrate.ts @@ -22,8 +22,8 @@ export async function migrate(migration: any, { glob, dryRun, list, rename, pars export async function addStorybookBlocksPackage() { const packageManager = JsPackageManagerFactory.getPackageManager(); - const packageJson = packageManager.retrievePackageJson(); - const versionToInstall = getStorybookVersionSpecifier(packageManager.retrievePackageJson()); + const packageJson = await packageManager.retrievePackageJson(); + const versionToInstall = getStorybookVersionSpecifier(await packageManager.retrievePackageJson()); logger.info(`✅ Adding "@storybook/blocks" package`); await packageManager.addDependencies({ installAsDevDependencies: true, packageJson }, [ `@storybook/blocks@${versionToInstall}`, diff --git a/code/lib/cli/src/upgrade.ts b/code/lib/cli/src/upgrade.ts index 6d25ed46c138..72fbab8545dd 100644 --- a/code/lib/cli/src/upgrade.ts +++ b/code/lib/cli/src/upgrade.ts @@ -189,7 +189,7 @@ export const doUpgrade = async ({ if (!dryRun) flags.push('--upgrade'); flags.push('--target'); flags.push(target); - flags = addExtraFlags(EXTRA_FLAGS, flags, packageManager.retrievePackageJson()); + flags = addExtraFlags(EXTRA_FLAGS, flags, await packageManager.retrievePackageJson()); const check = spawnSync('npx', ['npm-check-updates@latest', '/storybook/', ...flags], { stdio: 'pipe', shell: true, @@ -204,7 +204,7 @@ export const doUpgrade = async ({ if (!dryRun) { commandLog(`Installing upgrades`); - packageManager.installDependencies(); + await packageManager.installDependencies(); } let automigrationResults; diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index 8e3d1d0c3ad9..ce4d72f0001f 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -38,7 +38,7 @@ const sbInit = async (cwd: string, flags?: string[], debug?: boolean) => { }; const withLocalRegistry = async (packageManager: JsPackageManager, action: () => Promise) => { - const prevUrl = packageManager.getRegistryURL(); + const prevUrl = await packageManager.getRegistryURL(); let error; try { console.log(`📦 Configuring local registry: ${LOCAL_REGISTRY_URL}`); @@ -48,7 +48,7 @@ const withLocalRegistry = async (packageManager: JsPackageManager, action: () => error = e; } finally { console.log(`📦 Restoring registry: ${prevUrl}`); - packageManager.setRegistryURL(prevUrl); + await packageManager.setRegistryURL(prevUrl); if (error) { // eslint-disable-next-line no-unsafe-finally @@ -80,7 +80,7 @@ const addStorybook = async ({ const packageManager = JsPackageManagerFactory.getPackageManager({}, tmpDir); if (localRegistry) { await withLocalRegistry(packageManager, async () => { - packageManager.addPackageResolutions(storybookVersions); + await packageManager.addPackageResolutions(storybookVersions); await sbInit(tmpDir, flags, debug); }); diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index c26a6f24b8c7..f20a6fe17b31 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -332,7 +332,7 @@ async function linkPackageStories( ); } -function addExtraDependencies({ +async function addExtraDependencies({ cwd, dryRun, debug, @@ -350,7 +350,7 @@ function addExtraDependencies({ if (debug) logger.log('🎁 Adding extra deps', extraDeps); if (!dryRun) { const packageManager = JsPackageManagerFactory.getPackageManager({}, cwd); - packageManager.addDependencies({ installAsDevDependencies: true }, extraDeps); + await packageManager.addDependencies({ installAsDevDependencies: true }, extraDeps); } } @@ -481,7 +481,7 @@ export const addStories: Task['run'] = async ( } // Some addon stories require extra dependencies - addExtraDependencies({ cwd, dryRun, debug }); + await addExtraDependencies({ cwd, dryRun, debug }); await writeConfig(mainConfig); };