diff --git a/packages/cli-kit/src/public/node/node-package-manager.test.ts b/packages/cli-kit/src/public/node/node-package-manager.test.ts index cbd5b629c9..5c22f54ecd 100644 --- a/packages/cli-kit/src/public/node/node-package-manager.test.ts +++ b/packages/cli-kit/src/public/node/node-package-manager.test.ts @@ -846,11 +846,7 @@ describe('getPackageManager', () => { test('finds if npm is being used', async () => { await inTemporaryDirectory(async (tmpDir) => { // Given - const packageJSON = {name: 'mock name'} - - // When - await writePackageJSON(tmpDir, packageJSON) - mockedCaptureOutput.mockReturnValueOnce(Promise.resolve(tmpDir)) + await writePackageJSON(tmpDir, {name: 'mock name'}) // Then const packageManager = await getPackageManager(tmpDir) @@ -861,13 +857,8 @@ describe('getPackageManager', () => { test('finds if yarn is being used', async () => { await inTemporaryDirectory(async (tmpDir) => { // Given - const packageJSON = {name: 'mock name'} - const yarnLock = joinPath(tmpDir, 'yarn.lock') - - // When - await writePackageJSON(tmpDir, packageJSON) - await writeFile(yarnLock, '') - mockedCaptureOutput.mockReturnValueOnce(Promise.resolve(tmpDir)) + await writePackageJSON(tmpDir, {name: 'mock name'}) + await writeFile(joinPath(tmpDir, 'yarn.lock'), '') // Then const packageManager = await getPackageManager(tmpDir) @@ -878,13 +869,8 @@ describe('getPackageManager', () => { test('finds if pnpm is being used', async () => { await inTemporaryDirectory(async (tmpDir) => { // Given - const packageJSON = {name: 'mock name'} - const pnpmLock = joinPath(tmpDir, 'pnpm-lock.yaml') - - // When - await writePackageJSON(tmpDir, packageJSON) - await writeFile(pnpmLock, '') - mockedCaptureOutput.mockReturnValueOnce(Promise.resolve(tmpDir)) + await writePackageJSON(tmpDir, {name: 'mock name'}) + await writeFile(joinPath(tmpDir, 'pnpm-lock.yaml'), '') // Then const packageManager = await getPackageManager(tmpDir) @@ -892,34 +878,23 @@ describe('getPackageManager', () => { }) }) - test('falls back to packageManagerFromUserAgent when npm prefix fails', async () => { + test('falls back to packageManagerFromUserAgent when no package.json is found', async () => { await inTemporaryDirectory(async (tmpDir) => { - // Given + // Given — no package.json in tmpDir, stub user agent to yarn vi.stubEnv('npm_config_user_agent', 'yarn/1.22.0') - // Mock npm prefix to fail - mockedCaptureOutput.mockRejectedValueOnce(new Error('npm prefix failed')) - // When const packageManager = await getPackageManager(tmpDir) // Then - expect(mockedCaptureOutput).toHaveBeenCalledWith('npm', ['prefix'], expect.anything()) - expect(packageManager).toEqual('yarn') - - // Restore original implementation vi.unstubAllEnvs() + expect(packageManager).toEqual('yarn') }) }) test("tries to guess the package manager from the environment if it can't find a package.json", async () => { await inTemporaryDirectory(async (tmpDir) => { - // Given - const subDirectory = joinPath(tmpDir, 'subdir') - await mkdir(subDirectory) - mockedCaptureOutput.mockReturnValueOnce(Promise.resolve(tmpDir)) - - // When/Then + // When/Then — no package.json, falls back to user agent const packageManager = await getPackageManager(tmpDir) // pnpm is used locally and in CI expect(packageManager).toEqual('pnpm') diff --git a/packages/cli-kit/src/public/node/node-package-manager.ts b/packages/cli-kit/src/public/node/node-package-manager.ts index d59172bee6..bdbce5aff7 100644 --- a/packages/cli-kit/src/public/node/node-package-manager.ts +++ b/packages/cli-kit/src/public/node/node-package-manager.ts @@ -1,6 +1,6 @@ import {AbortError, BugError} from './error.js' import {AbortController, AbortSignal} from './abort.js' -import {captureOutput, exec} from './system.js' +import {exec} from './system.js' import {fileExists, readFile, writeFile, findPathUp, glob} from './fs.js' import {dirname, joinPath} from './path.js' import {runWithTimer} from './metadata.js' @@ -115,32 +115,18 @@ export function packageManagerFromUserAgent(env = process.env): PackageManager { * @returns The dependency manager */ export async function getPackageManager(fromDirectory: string): Promise { - let directory: string | undefined - let packageJson: string | undefined - try { - directory = await captureOutput('npm', ['prefix'], {cwd: fromDirectory}) - outputDebug(outputContent`Obtaining the dependency manager in directory ${outputToken.path(directory)}...`) - packageJson = joinPath(directory, 'package.json') - // eslint-disable-next-line no-catch-all/no-catch-all - } catch { - // if problems locating directoy/package file, we use user agent instead - } - - if (!directory || !packageJson || !(await fileExists(packageJson))) { + const packageJsonPath = await findPathUp('package.json', {cwd: fromDirectory, type: 'file'}) + if (!packageJsonPath) { return packageManagerFromUserAgent() } - const yarnLockPath = joinPath(directory, yarnLockfile) - const pnpmLockPath = joinPath(directory, pnpmLockfile) - const bunLockPath = joinPath(directory, bunLockfile) - if (await fileExists(yarnLockPath)) { - return 'yarn' - } else if (await fileExists(pnpmLockPath)) { - return 'pnpm' - } else if (await fileExists(bunLockPath)) { - return 'bun' - } else { - return 'npm' - } + + const directory = dirname(packageJsonPath) + outputDebug(outputContent`Obtaining the dependency manager in directory ${outputToken.path(directory)}...`) + + if (await fileExists(joinPath(directory, yarnLockfile))) return 'yarn' + if (await fileExists(joinPath(directory, pnpmLockfile))) return 'pnpm' + if (await fileExists(joinPath(directory, bunLockfile))) return 'bun' + return 'npm' } interface InstallNPMDependenciesRecursivelyOptions {