From 46cba367f06a6354fe98fcb15e7771e819feeac0 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Fri, 6 Nov 2020 18:08:44 +0530 Subject: [PATCH] feat: add pnpm support for package installation (#2040) --- .../__tests__/get-package-manager.test.js | 21 ++++++++++++++++--- .../__tests__/prompt-installation.test.js | 16 ++++++++++++++ .../package-lock.json | 0 .../pnpm-lock.yaml} | 0 .../utils/__tests__/test-all-lock/yarn.lock | 0 .../test-npm-and-pnpm/package-lock.json | 0 .../test-npm-and-pnpm/pnpm-lock.yaml | 0 .../__tests__/test-pnpm-lock/pnpm-lock.yaml | 0 .../lib/utils/get-package-manager.js | 5 +++++ .../lib/utils/prompt-installation.js | 1 + 10 files changed, 40 insertions(+), 3 deletions(-) rename packages/webpack-cli/lib/utils/__tests__/{test-both => test-all-lock}/package-lock.json (100%) rename packages/webpack-cli/lib/utils/__tests__/{test-both/yarn.lock => test-all-lock/pnpm-lock.yaml} (100%) create mode 100644 packages/webpack-cli/lib/utils/__tests__/test-all-lock/yarn.lock create mode 100644 packages/webpack-cli/lib/utils/__tests__/test-npm-and-pnpm/package-lock.json create mode 100644 packages/webpack-cli/lib/utils/__tests__/test-npm-and-pnpm/pnpm-lock.yaml create mode 100644 packages/webpack-cli/lib/utils/__tests__/test-pnpm-lock/pnpm-lock.yaml diff --git a/packages/webpack-cli/lib/utils/__tests__/get-package-manager.test.js b/packages/webpack-cli/lib/utils/__tests__/get-package-manager.test.js index 61350f3e520..3abe09e9c46 100644 --- a/packages/webpack-cli/lib/utils/__tests__/get-package-manager.test.js +++ b/packages/webpack-cli/lib/utils/__tests__/get-package-manager.test.js @@ -22,7 +22,9 @@ describe('packageUtils', () => { describe('getPackageManager', () => { const testYarnLockPath = path.resolve(__dirname, 'test-yarn-lock'); const testNpmLockPath = path.resolve(__dirname, 'test-npm-lock'); - const testBothPath = path.resolve(__dirname, 'test-both'); + const testPnpmLockPath = path.resolve(__dirname, 'test-pnpm-lock'); + const testNpmAndPnpmPath = path.resolve(__dirname, 'test-npm-and-pnpm'); + const testAllPath = path.resolve(__dirname, 'test-all-lock'); const cwdSpy = jest.spyOn(process, 'cwd'); @@ -33,7 +35,8 @@ describe('packageUtils', () => { fs.mkdirSync(testNpmLockPath); } fs.writeFileSync(path.resolve(testNpmLockPath, 'package-lock.json'), ''); - fs.writeFileSync(path.resolve(testBothPath, 'package-lock.json'), ''); + fs.writeFileSync(path.resolve(testNpmAndPnpmPath, 'package-lock.json'), ''); + fs.writeFileSync(path.resolve(testAllPath, 'package-lock.json'), ''); }); beforeEach(() => { @@ -52,8 +55,20 @@ describe('packageUtils', () => { expect(syncMock.mock.calls.length).toEqual(0); }); + it('should find pnpm-lock.yaml', () => { + cwdSpy.mockReturnValue(testPnpmLockPath); + expect(getPackageManager()).toEqual('pnpm'); + expect(syncMock.mock.calls.length).toEqual(0); + }); + + it('should prioritize npm over pnpm', () => { + cwdSpy.mockReturnValue(testNpmAndPnpmPath); + expect(getPackageManager()).toEqual('npm'); + expect(syncMock.mock.calls.length).toEqual(0); + }); + it('should prioritize yarn with many lock files', () => { - cwdSpy.mockReturnValue(testBothPath); + cwdSpy.mockReturnValue(testAllPath); expect(getPackageManager()).toEqual('yarn'); expect(syncMock.mock.calls.length).toEqual(0); }); diff --git a/packages/webpack-cli/lib/utils/__tests__/prompt-installation.test.js b/packages/webpack-cli/lib/utils/__tests__/prompt-installation.test.js index e8b4e83b2bf..b31ce6c6746 100644 --- a/packages/webpack-cli/lib/utils/__tests__/prompt-installation.test.js +++ b/packages/webpack-cli/lib/utils/__tests__/prompt-installation.test.js @@ -60,6 +60,22 @@ describe('promptInstallation', () => { expect(runCommand.mock.calls[0][0]).toEqual('yarn add -D test-package'); }); + it('should prompt to install using pnpm if pnpm is package manager', async () => { + prompt.mockReturnValue({ + installConfirm: true, + }); + getPackageManager.mockReturnValue('pnpm'); + const preMessage = jest.fn(); + const promptResult = await promptInstallation('test-package', preMessage); + expect(promptResult).toBeTruthy(); + expect(preMessage.mock.calls.length).toEqual(1); + expect(prompt.mock.calls.length).toEqual(1); + expect(runCommand.mock.calls.length).toEqual(1); + expect(prompt.mock.calls[0][0][0].message).toMatch(/Would you like to install test-package\?/); + // install the package using npm + expect(runCommand.mock.calls[0][0]).toEqual('pnpm install -D test-package'); + }); + it('should not install if install is not confirmed', async () => { prompt.mockReturnValue({ installConfirm: false, diff --git a/packages/webpack-cli/lib/utils/__tests__/test-both/package-lock.json b/packages/webpack-cli/lib/utils/__tests__/test-all-lock/package-lock.json similarity index 100% rename from packages/webpack-cli/lib/utils/__tests__/test-both/package-lock.json rename to packages/webpack-cli/lib/utils/__tests__/test-all-lock/package-lock.json diff --git a/packages/webpack-cli/lib/utils/__tests__/test-both/yarn.lock b/packages/webpack-cli/lib/utils/__tests__/test-all-lock/pnpm-lock.yaml similarity index 100% rename from packages/webpack-cli/lib/utils/__tests__/test-both/yarn.lock rename to packages/webpack-cli/lib/utils/__tests__/test-all-lock/pnpm-lock.yaml diff --git a/packages/webpack-cli/lib/utils/__tests__/test-all-lock/yarn.lock b/packages/webpack-cli/lib/utils/__tests__/test-all-lock/yarn.lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/webpack-cli/lib/utils/__tests__/test-npm-and-pnpm/package-lock.json b/packages/webpack-cli/lib/utils/__tests__/test-npm-and-pnpm/package-lock.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/webpack-cli/lib/utils/__tests__/test-npm-and-pnpm/pnpm-lock.yaml b/packages/webpack-cli/lib/utils/__tests__/test-npm-and-pnpm/pnpm-lock.yaml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/webpack-cli/lib/utils/__tests__/test-pnpm-lock/pnpm-lock.yaml b/packages/webpack-cli/lib/utils/__tests__/test-pnpm-lock/pnpm-lock.yaml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/webpack-cli/lib/utils/get-package-manager.js b/packages/webpack-cli/lib/utils/get-package-manager.js index 9d6b4125604..4c165664f4b 100644 --- a/packages/webpack-cli/lib/utils/get-package-manager.js +++ b/packages/webpack-cli/lib/utils/get-package-manager.js @@ -12,11 +12,16 @@ const { sync } = require('execa'); function getPackageManager() { const hasLocalYarn = fs.existsSync(path.resolve(process.cwd(), 'yarn.lock')); const hasLocalNpm = fs.existsSync(path.resolve(process.cwd(), 'package-lock.json')); + const hasLocalPnpm = fs.existsSync(path.resolve(process.cwd(), 'pnpm-lock.yaml')); + if (hasLocalYarn) { return 'yarn'; } else if (hasLocalNpm) { return 'npm'; + } else if (hasLocalPnpm) { + return 'pnpm'; } + try { // if the sync function below fails because yarn is not installed, // an error will be thrown diff --git a/packages/webpack-cli/lib/utils/prompt-installation.js b/packages/webpack-cli/lib/utils/prompt-installation.js index 1acb49669cd..e9988943af5 100644 --- a/packages/webpack-cli/lib/utils/prompt-installation.js +++ b/packages/webpack-cli/lib/utils/prompt-installation.js @@ -11,6 +11,7 @@ const packageExists = require('./package-exists'); */ async function promptInstallation(packageName, preMessage) { const packageManager = getPackageManager(); + // yarn uses 'add' command, rest npm and pnpm both use 'install' const options = [packageManager === 'yarn' ? 'add' : 'install', '-D', packageName]; const commandToBeRun = `${packageManager} ${options.join(' ')}`;