diff --git a/lib/modules/manager/npm/extract/__snapshots__/monorepo.spec.ts.snap b/lib/modules/manager/npm/extract/__snapshots__/monorepo.spec.ts.snap index 2fd7c3706f5c4c787cbc62978902ee53acd1dc85..190c157e32019671762c870b89dcf6e952d64cf4 100644 --- a/lib/modules/manager/npm/extract/__snapshots__/monorepo.spec.ts.snap +++ b/lib/modules/manager/npm/extract/__snapshots__/monorepo.spec.ts.snap @@ -26,9 +26,6 @@ Array [ "lernaJsonFile": "lerna.json", }, "packageFile": "package.json", - "packages": Array [ - "packages/*", - ], }, Object { "deps": Array [ @@ -45,6 +42,7 @@ Array [ ], "lernaClient": undefined, "managerData": Object { + "hasPackageManager": undefined, "lernaJsonFile": "lerna.json", "yarnZeroInstall": undefined, }, @@ -57,6 +55,7 @@ Array [ Object { "lernaClient": undefined, "managerData": Object { + "hasPackageManager": undefined, "lernaJsonFile": "lerna.json", "yarnZeroInstall": undefined, }, @@ -95,9 +94,6 @@ Array [ "lernaJsonFile": "lerna.json", }, "packageFile": "package.json", - "packages": Array [ - "packages/*", - ], }, Object { "deps": Array [ @@ -114,6 +110,7 @@ Array [ ], "lernaClient": undefined, "managerData": Object { + "hasPackageManager": undefined, "lernaJsonFile": "lerna.json", "yarnZeroInstall": undefined, }, @@ -126,6 +123,7 @@ Array [ Object { "lernaClient": undefined, "managerData": Object { + "hasPackageManager": undefined, "lernaJsonFile": "lerna.json", "yarnZeroInstall": undefined, }, @@ -156,6 +154,7 @@ Array [ Object { "lernaClient": "yarn", "managerData": Object { + "hasPackageManager": undefined, "lernaJsonFile": "lerna.json", "yarnZeroInstall": undefined, }, @@ -168,6 +167,7 @@ Array [ Object { "lernaClient": "yarn", "managerData": Object { + "hasPackageManager": undefined, "lernaJsonFile": "lerna.json", "yarnZeroInstall": undefined, }, @@ -192,6 +192,7 @@ Array [ "hasYarnWorkspaces": true, "lernaClient": undefined, "managerData": Object { + "hasPackageManager": undefined, "lernaJsonFile": undefined, "yarnZeroInstall": undefined, }, @@ -206,6 +207,7 @@ Array [ Object { "lernaClient": undefined, "managerData": Object { + "hasPackageManager": undefined, "lernaJsonFile": undefined, "yarnZeroInstall": undefined, }, @@ -234,6 +236,7 @@ Array [ "hasYarnWorkspaces": true, "lernaClient": undefined, "managerData": Object { + "hasPackageManager": undefined, "lernaJsonFile": undefined, "yarnZeroInstall": true, }, @@ -248,6 +251,7 @@ Array [ Object { "lernaClient": undefined, "managerData": Object { + "hasPackageManager": undefined, "lernaJsonFile": undefined, "yarnZeroInstall": true, }, diff --git a/lib/modules/manager/npm/extract/locked-versions.spec.ts b/lib/modules/manager/npm/extract/locked-versions.spec.ts index 8b90657b7bb130bdbb8af1272fd1f1967ba6966f..d228834e482a91afde01e6cf691a3f4c6addacb3 100644 --- a/lib/modules/manager/npm/extract/locked-versions.spec.ts +++ b/lib/modules/manager/npm/extract/locked-versions.spec.ts @@ -211,6 +211,46 @@ describe('modules/manager/npm/extract/locked-versions', () => { ]); }); + it("uses yarn.lock but doesn't override contraints", async () => { + const yarnVersion = '3.2.0'; + const lockfileVersion = 8; + const isYarn1 = false; + yarn.getYarnLock.mockReturnValue({ + isYarn1, + lockfileVersion, + lockedVersions, + }); + const packageFiles = getPackageFiles(yarnVersion); + packageFiles[0].constraints = { yarn: '3.2.0' }; + await getLockedVersions(packageFiles); + expect(packageFiles).toEqual([ + { + constraints: { yarn: '3.2.0' }, + deps: [ + { currentValue: '1.0.0', depName: 'a', lockedVersion: '1.0.0' }, + { currentValue: '2.0.0', depName: 'b', lockedVersion: '2.0.0' }, + { + currentValue: '^3.2.0', + depName: 'yarn', + depType: 'engines', + lockedVersion: undefined, + packageName: '@yarnpkg/cli', + }, + { + currentValue: '3.2.0', + depName: 'yarn', + depType: 'packageManager', + lockedVersion: undefined, + packageName: '@yarnpkg/cli', + }, + ], + lockFiles: ['yarn.lock'], + npmLock: 'package-lock.json', + yarnLock: 'yarn.lock', + }, + ]); + }); + it('uses package-lock.json with npm v6.0.0', async () => { npm.getNpmLock.mockReturnValue({ lockedVersions: { a: '1.0.0', b: '2.0.0', c: '3.0.0' }, diff --git a/lib/modules/manager/npm/extract/locked-versions.ts b/lib/modules/manager/npm/extract/locked-versions.ts index 442ae37e2df2274cd03df655a12bc6be50e397e9..3c1d9f1cac671fae473d168ecbc9ef964a571710 100644 --- a/lib/modules/manager/npm/extract/locked-versions.ts +++ b/lib/modules/manager/npm/extract/locked-versions.ts @@ -21,7 +21,7 @@ export async function getLockedVersions( lockFileCache[yarnLock] = await getYarnLock(yarnLock); } const { lockfileVersion, isYarn1 } = lockFileCache[yarnLock]; - if (!isYarn1) { + if (!isYarn1 && !packageFile.constraints?.yarn) { if (lockfileVersion && lockfileVersion >= 8) { // https://github.com/yarnpkg/berry/commit/9bcd27ae34aee77a567dd104947407532fa179b3 // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion diff --git a/lib/modules/manager/npm/extract/monorepo.spec.ts b/lib/modules/manager/npm/extract/monorepo.spec.ts index 68c91a4717d7c2035687ef25d716c000acdb6843..c75bac3a2abaf1d0f928285df1c27f167222f1e7 100644 --- a/lib/modules/manager/npm/extract/monorepo.spec.ts +++ b/lib/modules/manager/npm/extract/monorepo.spec.ts @@ -1,3 +1,4 @@ +import type { PackageFile } from '../../types'; import { detectMonorepos } from './monorepo'; jest.mock('./pnpm'); @@ -5,14 +6,13 @@ jest.mock('./pnpm'); describe('modules/manager/npm/extract/monorepo', () => { describe('.extractPackageFile()', () => { it('uses lerna package settings', async () => { - const packageFiles = [ + const packageFiles: Partial<PackageFile>[] = [ { packageFile: 'package.json', managerData: { lernaJsonFile: 'lerna.json', }, lernaPackages: ['packages/*'], - packages: ['packages/*'], deps: [ { depName: '@org/a', @@ -47,10 +47,10 @@ describe('modules/manager/npm/extract/monorepo', () => { packageFile: 'packages/b/package.json', packageJsonName: '@org/b', }, - ] as any; + ]; await detectMonorepos(packageFiles); expect(packageFiles).toMatchSnapshot(); - expect(packageFiles[1].managerData.lernaJsonFile).toBe('lerna.json'); + expect(packageFiles[1].managerData?.lernaJsonFile).toBe('lerna.json'); expect( packageFiles.some((packageFile) => packageFile.deps?.some((dep) => dep.isInternal) @@ -59,14 +59,13 @@ describe('modules/manager/npm/extract/monorepo', () => { }); it('updates internal packages', async () => { - const packageFiles = [ + const packageFiles: Partial<PackageFile>[] = [ { packageFile: 'package.json', managerData: { lernaJsonFile: 'lerna.json', }, lernaPackages: ['packages/*'], - packages: ['packages/*'], deps: [ { depName: '@org/a', @@ -101,10 +100,10 @@ describe('modules/manager/npm/extract/monorepo', () => { packageFile: 'packages/b/package.json', packageJsonName: '@org/b', }, - ] as any; + ]; await detectMonorepos(packageFiles); expect(packageFiles).toMatchSnapshot(); - expect(packageFiles[1].managerData.lernaJsonFile).toBe('lerna.json'); + expect(packageFiles[1].managerData?.lernaJsonFile).toBe('lerna.json'); expect( packageFiles.some((packageFile) => packageFile.deps?.some((dep) => dep.isInternal) @@ -113,7 +112,7 @@ describe('modules/manager/npm/extract/monorepo', () => { }); it('uses yarn workspaces package settings with lerna', async () => { - const packageFiles = [ + const packageFiles: Partial<PackageFile>[] = [ { packageFile: 'package.json', managerData: { @@ -134,11 +133,11 @@ describe('modules/manager/npm/extract/monorepo', () => { ]; await detectMonorepos(packageFiles); expect(packageFiles).toMatchSnapshot(); - expect(packageFiles[1].managerData.lernaJsonFile).toBe('lerna.json'); + expect(packageFiles[1].managerData?.lernaJsonFile).toBe('lerna.json'); }); it('uses yarn workspaces package settings without lerna', async () => { - const packageFiles = [ + const packageFiles: Partial<PackageFile>[] = [ { packageFile: 'package.json', npmrc: '@org:registry=//registry.some.org\n', @@ -162,8 +161,53 @@ describe('modules/manager/npm/extract/monorepo', () => { ]); }); + it('uses yarn workspaces package settings with contraints', async () => { + const packageFiles: Partial<PackageFile>[] = [ + { + packageFile: 'package.json', + yarnWorkspacesPackages: ['docs'], + skipInstalls: true, // coverage + constraints: { + node: '^14.15.0 || >=16.13.0', + yarn: '3.2.1', + }, + yarnLock: 'yarn.lock', + managerData: { + hasPackageManager: true, + }, + }, + { + packageFile: 'docs/package.json', + packageJsonName: 'docs', + yarnLock: 'yarn.lock', + constraints: { yarn: '^3.2.0' }, + }, + ]; + await detectMonorepos(packageFiles); + expect(packageFiles).toMatchObject([ + { + constraints: { + node: '^14.15.0 || >=16.13.0', + yarn: '3.2.1', + }, + managerData: { + hasPackageManager: true, + }, + }, + { + constraints: { + node: '^14.15.0 || >=16.13.0', + yarn: '^3.2.0', + }, + managerData: { + hasPackageManager: true, + }, + }, + ]); + }); + it('uses yarnZeroInstall and skipInstalls from yarn workspaces package settings', async () => { - const packageFiles = [ + const packageFiles: Partial<PackageFile>[] = [ { packageFile: 'package.json', managerData: { diff --git a/lib/modules/manager/npm/extract/monorepo.ts b/lib/modules/manager/npm/extract/monorepo.ts index ea7aec797c1d7893f1a6ff466daea59cbd6dcb8e..31581102b35876ce716422d62a5a515587d3eb24 100644 --- a/lib/modules/manager/npm/extract/monorepo.ts +++ b/lib/modules/manager/npm/extract/monorepo.ts @@ -22,7 +22,8 @@ export async function detectMonorepos( yarnWorkspacesPackages, skipInstalls, } = p; - const { lernaJsonFile, yarnZeroInstall } = managerData; + const { lernaJsonFile, yarnZeroInstall, hasPackageManager } = managerData; + const packages = yarnWorkspacesPackages || lernaPackages; if (packages?.length) { const internalPackagePatterns = ( @@ -51,6 +52,7 @@ export async function detectMonorepos( subPackage.managerData = subPackage.managerData || {}; subPackage.managerData.lernaJsonFile = lernaJsonFile; subPackage.managerData.yarnZeroInstall = yarnZeroInstall; + subPackage.managerData.hasPackageManager = hasPackageManager; subPackage.lernaClient = lernaClient; subPackage.yarnLock = subPackage.yarnLock || yarnLock; subPackage.npmLock = subPackage.npmLock || npmLock; @@ -60,6 +62,13 @@ export async function detectMonorepos( subPackage.npmrc = subPackage.npmrc || npmrc; } + if (p.constraints) { + subPackage.constraints = { + ...p.constraints, + ...subPackage.constraints, + }; + } + subPackage.deps?.forEach((dep) => { if (internalPackageNames.includes(dep.depName)) { dep.isInternal = true;