From 0d758a3d0e24727bd7a383b3ed98a7a7a9abe0f7 Mon Sep 17 00:00:00 2001
From: Bryan Lee <38807139+liby@users.noreply.github.com>
Date: Mon, 9 Oct 2023 17:49:05 +0800
Subject: [PATCH] feat(manager/npm): ignore scripts for `pnpmDedupe` (#24505)

Co-authored-by: Rhys Arkins <rhys@arkins.net>
---
 docs/usage/configuration-options.md           |  2 +-
 .../dedupe-ignore-scripts/package.json        |  9 +++++++
 .../manager/npm/post-update/pnpm.spec.ts      | 26 ++++++++++++++++++-
 lib/modules/manager/npm/post-update/pnpm.ts   | 17 ++++++++++--
 4 files changed, 50 insertions(+), 4 deletions(-)
 create mode 100644 lib/modules/manager/npm/post-update/__fixtures__/dedupe-ignore-scripts/package.json

diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index 10e321938d..2b20190736 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -2973,7 +2973,7 @@ Table with options:
 | `gomodUpdateImportPaths`     | Update source import paths on major module updates, using [mod](https://github.com/marwan-at-work/mod).                                                    |
 | `helmUpdateSubChartArchives` | Update subchart archives in the `/charts` folder.                                                                                                          |
 | `npmDedupe`                  | Run `npm dedupe` after `package-lock.json` updates.                                                                                                        |
-| `pnpmDedupe`                 | Run `pnpm dedupe` after `pnpm-lock.yaml` updates.                                                                                                          |
+| `pnpmDedupe`                 | Run `pnpm dedupe --ignore-scripts` 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/modules/manager/npm/post-update/__fixtures__/dedupe-ignore-scripts/package.json b/lib/modules/manager/npm/post-update/__fixtures__/dedupe-ignore-scripts/package.json
new file mode 100644
index 0000000000..0483434931
--- /dev/null
+++ b/lib/modules/manager/npm/post-update/__fixtures__/dedupe-ignore-scripts/package.json
@@ -0,0 +1,9 @@
+{
+  "name": "dedupe-ignore-scripts",
+  "version": "1.0.0",
+  "engines": {
+    "pnpm": ">=8.8.0"
+  },
+  "engine-strict": true,
+  "packageManager": "pnpm@8.8.0"
+}
diff --git a/lib/modules/manager/npm/post-update/pnpm.spec.ts b/lib/modules/manager/npm/post-update/pnpm.spec.ts
index 064af1bdae..2c21264cf2 100644
--- a/lib/modules/manager/npm/post-update/pnpm.spec.ts
+++ b/lib/modules/manager/npm/post-update/pnpm.spec.ts
@@ -77,7 +77,7 @@ describe('modules/manager/npm/post-update/pnpm', () => {
       {},
       { ...config, postUpdateOptions }
     );
-    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(fs.readLocalFile).toHaveBeenCalledTimes(2);
     expect(res.lockFile).toBe('package-lock-contents');
     expect(execSnapshots).toMatchObject([
       {
@@ -89,6 +89,30 @@ describe('modules/manager/npm/post-update/pnpm', () => {
     ]);
   });
 
+  it('performs dedupe --ignore-scripts for pnpm >= 8.8.0', async () => {
+    const execSnapshots = mockExecAll();
+    const fileContent = Fixtures.get('dedupe-ignore-scripts/package.json');
+    fs.readLocalFile
+      .mockResolvedValueOnce(fileContent)
+      .mockResolvedValue('package-lock-contents');
+    const postUpdateOptions = ['pnpmDedupe'];
+    const res = await pnpmHelper.generateLockFile(
+      'some-dir',
+      {},
+      { ...config, postUpdateOptions }
+    );
+    expect(fs.readLocalFile).toHaveBeenCalledTimes(2);
+    expect(res.lockFile).toBe('package-lock-contents');
+    expect(execSnapshots).toMatchObject([
+      {
+        cmd: 'pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile',
+      },
+      {
+        cmd: 'pnpm dedupe --ignore-scripts',
+      },
+    ]);
+  });
+
   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 15ff683596..4cf288caaa 100644
--- a/lib/modules/manager/npm/post-update/pnpm.ts
+++ b/lib/modules/manager/npm/post-update/pnpm.ts
@@ -1,5 +1,6 @@
 import is from '@sindresorhus/is';
 import { load } from 'js-yaml';
+import semver from 'semver';
 import upath from 'upath';
 import { GlobalConfig } from '../../../../config/global';
 import { TEMPORARY_ERROR } from '../../../../constants/error-messages';
@@ -39,6 +40,7 @@ export async function generateLockFile(
   let cmd = 'pnpm';
   try {
     const lazyPgkJson = lazyLoadPackageJson(lockFileDir);
+
     const pnpmToolConstraint: ToolConstraint = {
       toolName: 'pnpm',
       constraint:
@@ -79,8 +81,19 @@ export async function generateLockFile(
 
     // postUpdateOptions
     if (config.postUpdateOptions?.includes('pnpmDedupe')) {
-      logger.debug('Performing pnpm dedupe');
-      commands.push('pnpm dedupe');
+      const pnpmVersionFromPackageJson = getPackageManagerVersion(
+        'pnpm',
+        await lazyPgkJson.getValue()
+      );
+
+      if (
+        pnpmVersionFromPackageJson &&
+        semver.gte(pnpmVersionFromPackageJson, '8.8.0')
+      ) {
+        commands.push('pnpm dedupe --ignore-scripts');
+      } else {
+        commands.push('pnpm dedupe');
+      }
     }
 
     if (upgrades.find((upgrade) => upgrade.isLockFileMaintenance)) {
-- 
GitLab