From b79c82e2065d6ce4ed589f0853c10f811d684f18 Mon Sep 17 00:00:00 2001 From: StinkyLord <42116482+PhilipAbed@users.noreply.github.com> Date: Fri, 8 Apr 2022 10:14:25 +0300 Subject: [PATCH] fix(manager/npm): use root pnpm constraints for workspaces (#14660) Co-authored-by: Michael Kriese <michael.kriese@visualon.de> --- .../extract/__snapshots__/index.spec.ts.snap | 1 - lib/modules/manager/npm/extract/index.spec.ts | 1 - lib/modules/manager/npm/extract/index.ts | 1 - lib/modules/manager/npm/extract/types.ts | 1 + .../__fixtures__/manager-field/package.json | 9 ++ .../__fixtures__/parent/package.json | 7 ++ .../__snapshots__/pnpm.spec.ts.snap | 46 ++++++++++ .../manager/npm/post-update/pnpm.spec.ts | 87 +++++++++++++++++++ lib/modules/manager/npm/post-update/pnpm.ts | 30 +++++-- 9 files changed, 175 insertions(+), 8 deletions(-) create mode 100644 lib/modules/manager/npm/post-update/__fixtures__/manager-field/package.json create mode 100644 lib/modules/manager/npm/post-update/__fixtures__/parent/package.json diff --git a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap index 085721749d..780b7acd94 100644 --- a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap +++ b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap @@ -34,7 +34,6 @@ Object { "constraints": Object { "node": ">= 8.9.2", "npm": "^8.0.0", - "pnpm": "^1.2.0", "vscode": ">=1.49.3", "yarn": "disabled", }, diff --git a/lib/modules/manager/npm/extract/index.spec.ts b/lib/modules/manager/npm/extract/index.spec.ts index 8772fc9bbc..734463dfe6 100644 --- a/lib/modules/manager/npm/extract/index.spec.ts +++ b/lib/modules/manager/npm/extract/index.spec.ts @@ -327,7 +327,6 @@ describe('modules/manager/npm/extract/index', () => { constraints: { node: '>= 8.9.2', npm: '^8.0.0', - pnpm: '^1.2.0', vscode: '>=1.49.3', yarn: 'disabled', }, diff --git a/lib/modules/manager/npm/extract/index.ts b/lib/modules/manager/npm/extract/index.ts index 180c5e9eb9..7d9dcc4d61 100644 --- a/lib/modules/manager/npm/extract/index.ts +++ b/lib/modules/manager/npm/extract/index.ts @@ -209,7 +209,6 @@ export async function extractPackageFile( } else if (depName === 'pnpm') { dep.datasource = NpmDatasource.id; dep.commitMessageTopic = 'pnpm'; - constraints.pnpm = dep.currentValue; } else if (depName === 'vscode') { dep.datasource = GithubTagsDatasource.id; dep.packageName = 'microsoft/vscode'; diff --git a/lib/modules/manager/npm/extract/types.ts b/lib/modules/manager/npm/extract/types.ts index cbdba5428f..8d01d3d18d 100644 --- a/lib/modules/manager/npm/extract/types.ts +++ b/lib/modules/manager/npm/extract/types.ts @@ -12,6 +12,7 @@ export interface NpmPackage extends PackageJson { _args?: any; _id?: any; dependenciesMeta?: DependenciesMeta; + packageManager?: string; } export type LockFileEntry = Record< diff --git a/lib/modules/manager/npm/post-update/__fixtures__/manager-field/package.json b/lib/modules/manager/npm/post-update/__fixtures__/manager-field/package.json new file mode 100644 index 0000000000..c4623f972e --- /dev/null +++ b/lib/modules/manager/npm/post-update/__fixtures__/manager-field/package.json @@ -0,0 +1,9 @@ +{ + "name": "parent", + "version": "1.0.0", + "engines": { + "pnpm": "=6.15.0" + }, + "engine-strict": true, + "packageManager": "pnpm@6.15.0" +} diff --git a/lib/modules/manager/npm/post-update/__fixtures__/parent/package.json b/lib/modules/manager/npm/post-update/__fixtures__/parent/package.json new file mode 100644 index 0000000000..f990d3e58f --- /dev/null +++ b/lib/modules/manager/npm/post-update/__fixtures__/parent/package.json @@ -0,0 +1,7 @@ +{ + "name": "parent", + "version": "1.0.0", + "engines": { + "pnpm": "=6.16.0" + } +} diff --git a/lib/modules/manager/npm/post-update/__snapshots__/pnpm.spec.ts.snap b/lib/modules/manager/npm/post-update/__snapshots__/pnpm.spec.ts.snap index 5ae51b636a..d35d6ff76a 100644 --- a/lib/modules/manager/npm/post-update/__snapshots__/pnpm.spec.ts.snap +++ b/lib/modules/manager/npm/post-update/__snapshots__/pnpm.spec.ts.snap @@ -92,6 +92,52 @@ Array [ ] `; +exports[`modules/manager/npm/post-update/pnpm uses constraint version if parent json has constraints 1`] = ` +Array [ + Object { + "cmd": "pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile", + "options": Object { + "cwd": "some-folder", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "LANG": "en_US.UTF-8", + "LC_ALL": "en_US", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + "maxBuffer": 10485760, + "timeout": 900000, + }, + }, +] +`; + +exports[`modules/manager/npm/post-update/pnpm uses packageManager version and puts it into constraint 1`] = ` +Array [ + Object { + "cmd": "pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile", + "options": Object { + "cwd": "some-folder", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "LANG": "en_US.UTF-8", + "LC_ALL": "en_US", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + "maxBuffer": 10485760, + "timeout": 900000, + }, + }, +] +`; + exports[`modules/manager/npm/post-update/pnpm uses the new version if packageManager is updated 1`] = ` Array [ Object { diff --git a/lib/modules/manager/npm/post-update/pnpm.spec.ts b/lib/modules/manager/npm/post-update/pnpm.spec.ts index 35222dc255..d5dba94c8a 100644 --- a/lib/modules/manager/npm/post-update/pnpm.spec.ts +++ b/lib/modules/manager/npm/post-update/pnpm.spec.ts @@ -1,5 +1,6 @@ import { exec as _exec } from 'child_process'; import { envMock, mockExecAll } from '../../../../../test/exec-util'; +import { Fixtures } from '../../../../../test/fixtures'; import { mocked } from '../../../../../test/util'; import * as _env from '../../../../util/exec/env'; import * as _fs from '../../../../util/fs/proxies'; @@ -77,4 +78,90 @@ describe('modules/manager/npm/post-update/pnpm', () => { expect(execSnapshots).toMatchSnapshot(); // TODO: check docker preCommands }); + + it('uses constraint version if parent json has constraints', async () => { + const execSnapshots = mockExecAll(exec); + const configTemp = { cacheDir: 'some-cache-dir' }; + const fileContent = Fixtures.get('parent/package.json'); + fs.readFile = jest + .fn() + .mockReturnValueOnce(fileContent) + .mockReturnValue('package-lock-contents'); + const res = await pnpmHelper.generateLockFile( + 'some-folder', + {}, + configTemp, + [ + { + depType: 'packageManager', + depName: 'pnpm', + }, + ] + ); + expect(fs.readFile).toHaveBeenCalledTimes(2); + expect(res.lockFile).toBe('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot([ + { + cmd: 'pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile', + options: { + cwd: 'some-folder', + encoding: 'utf-8', + env: { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + LANG: 'en_US.UTF-8', + LC_ALL: 'en_US', + }, + maxBuffer: 10485760, + timeout: 900000, + }, + }, + ]); + }); + + it('uses packageManager version and puts it into constraint', async () => { + const execSnapshots = mockExecAll(exec); + const configTemp = { cacheDir: 'some-cache-dir' }; + const fileContent = Fixtures.get('manager-field/package.json'); + fs.readFile = jest + .fn() + .mockReturnValueOnce(fileContent) + .mockReturnValue('package-lock-contents'); + const res = await pnpmHelper.generateLockFile( + 'some-folder', + {}, + configTemp, + [ + { + depType: 'packageManager', + depName: 'pnpm', + }, + ] + ); + expect(fs.readFile).toHaveBeenCalledTimes(2); + expect(res.lockFile).toBe('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot([ + { + cmd: 'pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile', + options: { + cwd: 'some-folder', + encoding: 'utf-8', + env: { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + LANG: 'en_US.UTF-8', + LC_ALL: 'en_US', + }, + maxBuffer: 10485760, + timeout: 900000, + }, + }, + ]); + }); }); diff --git a/lib/modules/manager/npm/post-update/pnpm.ts b/lib/modules/manager/npm/post-update/pnpm.ts index 3f821ec37a..0b46c381b8 100644 --- a/lib/modules/manager/npm/post-update/pnpm.ts +++ b/lib/modules/manager/npm/post-update/pnpm.ts @@ -6,6 +6,7 @@ import { exec } from '../../../../util/exec'; import type { ExecOptions, ToolConstraint } from '../../../../util/exec/types'; import { readFile, remove } from '../../../../util/fs'; import type { PostUpdateConfig, Upgrade } from '../../types'; +import type { NpmPackage } from '../extract/types'; import { getNodeConstraint } from './node-version'; import type { GenerateLockFileResult } from './types'; @@ -22,13 +23,9 @@ export async function generateLockFile( let stderr: string; let cmd = 'pnpm'; try { - const pnpmUpdate = upgrades.find( - (upgrade) => - upgrade.depType === 'packageManager' && upgrade.depName === 'pnpm' - ); const pnpmToolConstraint: ToolConstraint = { toolName: 'pnpm', - constraint: pnpmUpdate ? pnpmUpdate.newValue : config.constraints?.pnpm, + constraint: config.constraints?.pnpm ?? (await getPnpmContraint(cwd)), }; const tagConstraint = await getNodeConstraint(config); const execOptions: ExecOptions = { @@ -91,3 +88,26 @@ export async function generateLockFile( } return { lockFile }; } + +async function getPnpmContraint(cwd: string): Promise<string> { + let result; + const rootPackageJson = upath.join(cwd, 'package.json'); + const content = await readFile(rootPackageJson, 'utf8'); + if (content) { + const packageJson: NpmPackage = JSON.parse(content); + const packageManager = packageJson?.packageManager; + if (packageManager?.includes('@')) { + const nameAndVersion = packageManager.split('@'); + const name = nameAndVersion[0]; + if (name === 'pnpm') { + result = nameAndVersion[1]; + } + } else { + const engines = packageJson?.engines; + if (engines) { + result = engines['pnpm']; + } + } + } + return result; +} -- GitLab