From 2235659b188051d7c536612c18d258268e061a59 Mon Sep 17 00:00:00 2001
From: ocavue <ocavue@users.noreply.github.com>
Date: Tue, 14 Feb 2023 17:10:50 +0800
Subject: [PATCH] feat(manager/npm): support pnpmDedupe (#20392)

Co-authored-by: Rhys Arkins <rhys@arkins.net>
---
 docs/usage/configuration-options.md           |  1 +
 lib/config/options/index.ts                   |  1 +
 .../manager/npm/post-update/pnpm.spec.ts      | 21 +++++++++++++++++++
 lib/modules/manager/npm/post-update/pnpm.ts   | 11 +++++++++-
 4 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index 9bb09058e7..89b984479b 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -2168,6 +2168,7 @@ Table with options:
 | `gomodTidyE`             | Run `go mod tidy -e` after Go module updates.                                                                                                              |
 | `gomodUpdateImportPaths` | Update source import paths on major module updates, using [mod](https://github.com/marwan-at-work/mod).                                                    |
 | `npmDedupe`              | Run `npm dedupe` after `package-lock.json` updates.                                                                                                        |
+| `pnpmDedupe`             | Run `pnpm dedupe` after `pnpm-lock.yaml` updates.                                                                                                          |
 | `yarnDedupeFewer`        | Run `yarn-deduplicate --strategy fewer` after `yarn.lock` updates.                                                                                         |
 | `yarnDedupeHighest`      | Run `yarn-deduplicate --strategy highest` (`yarn dedupe --strategy highest` for Yarn >=2.2.0) after `yarn.lock` updates.                                   |
 
diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts
index ec1f31ecd5..9d8f7c315c 100644
--- a/lib/config/options/index.ts
+++ b/lib/config/options/index.ts
@@ -1996,6 +1996,7 @@ const options: RenovateOptions[] = [
       'gomodTidy1.17',
       'gomodTidyE',
       'npmDedupe',
+      'pnpmDedupe',
       'yarnDedupeFewer',
       'yarnDedupeHighest',
     ],
diff --git a/lib/modules/manager/npm/post-update/pnpm.spec.ts b/lib/modules/manager/npm/post-update/pnpm.spec.ts
index cacdcbc3a7..8f5091329b 100644
--- a/lib/modules/manager/npm/post-update/pnpm.spec.ts
+++ b/lib/modules/manager/npm/post-update/pnpm.spec.ts
@@ -69,6 +69,27 @@ describe('modules/manager/npm/post-update/pnpm', () => {
     expect(execSnapshots).toMatchSnapshot();
   });
 
+  it('performs dedupe', async () => {
+    const execSnapshots = mockExecAll();
+    fs.readLocalFile.mockResolvedValue('package-lock-contents');
+    const postUpdateOptions = ['pnpmDedupe'];
+    const res = await pnpmHelper.generateLockFile(
+      'some-dir',
+      {},
+      { ...config, postUpdateOptions }
+    );
+    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(res.lockFile).toBe('package-lock-contents');
+    expect(execSnapshots).toMatchObject([
+      {
+        cmd: 'pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile',
+      },
+      {
+        cmd: 'pnpm dedupe',
+      },
+    ]);
+  });
+
   it('uses the new version if packageManager is updated', async () => {
     const execSnapshots = mockExecAll();
     fs.readLocalFile.mockResolvedValue('package-lock-contents');
diff --git a/lib/modules/manager/npm/post-update/pnpm.ts b/lib/modules/manager/npm/post-update/pnpm.ts
index 4cb2e7d19b..8f0845c705 100644
--- a/lib/modules/manager/npm/post-update/pnpm.ts
+++ b/lib/modules/manager/npm/post-update/pnpm.ts
@@ -53,6 +53,8 @@ export async function generateLockFile(
       extraEnv.NPM_AUTH = env.NPM_AUTH;
       extraEnv.NPM_EMAIL = env.NPM_EMAIL;
     }
+    const commands: string[] = [];
+
     cmd = 'pnpm';
     let args = 'install --recursive --lockfile-only';
     if (!GlobalConfig.get('allowScripts') || config.ignoreScripts) {
@@ -60,6 +62,13 @@ export async function generateLockFile(
       args += ' --ignore-pnpmfile';
     }
     logger.trace({ cmd, args }, 'pnpm command');
+    commands.push(`${cmd} ${args}`);
+
+    // postUpdateOptions
+    if (config.postUpdateOptions?.includes('pnpmDedupe')) {
+      logger.debug('Performing pnpm dedupe');
+      commands.push('pnpm dedupe');
+    }
 
     if (upgrades.find((upgrade) => upgrade.isLockFileMaintenance)) {
       logger.debug(
@@ -75,7 +84,7 @@ export async function generateLockFile(
       }
     }
 
-    await exec(`${cmd} ${args}`, execOptions);
+    await exec(commands, execOptions);
     lockFile = await readLocalFile(lockFileName, 'utf8');
   } catch (err) /* istanbul ignore next */ {
     if (err.message === TEMPORARY_ERROR) {
-- 
GitLab