From c11170fabba30719ddeec737778398e6a05c8696 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Wed, 27 Sep 2023 14:29:07 +0200 Subject: [PATCH] feat(npm)!: drop explicit lerna support (#24542) --- docs/usage/self-hosted-configuration.md | 2 +- lib/config/options/index.ts | 2 +- .../inputs/workspaces-simple.json | 8 - .../extract/__snapshots__/index.spec.ts.snap | 492 ------------------ lib/modules/manager/npm/extract/index.spec.ts | 107 ---- lib/modules/manager/npm/extract/index.ts | 29 -- .../manager/npm/extract/post/monorepo.spec.ts | 144 +---- .../manager/npm/extract/post/monorepo.ts | 32 +- .../__snapshots__/lerna.spec.ts.snap | 260 --------- .../manager/npm/post-update/index.spec.ts | 129 ----- lib/modules/manager/npm/post-update/index.ts | 179 +------ .../manager/npm/post-update/lerna.spec.ts | 243 --------- lib/modules/manager/npm/post-update/lerna.ts | 154 ------ lib/modules/manager/npm/post-update/types.ts | 1 - lib/modules/manager/npm/types.ts | 3 - lib/util/exec/containerbase.ts | 5 - .../update/branch/lock-files/index.spec.ts | 2 - 17 files changed, 10 insertions(+), 1782 deletions(-) delete mode 100644 lib/modules/manager/npm/__fixtures__/inputs/workspaces-simple.json delete mode 100644 lib/modules/manager/npm/post-update/__snapshots__/lerna.spec.ts.snap delete mode 100644 lib/modules/manager/npm/post-update/lerna.spec.ts delete mode 100644 lib/modules/manager/npm/post-update/lerna.ts diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md index d7d5608aa085c0..c92325ff76b991 100644 --- a/docs/usage/self-hosted-configuration.md +++ b/docs/usage/self-hosted-configuration.md @@ -857,7 +857,7 @@ Secret names must start with an upper or lower case character and can have only By default, Renovate will use the most efficient approach to updating package files and lock files, which in most cases skips the need to perform a full module install by the bot. If this is set to false, then a full install of modules will be done. -This is currently applicable to `npm` and `lerna`/`npm` only, and only used in cases where bugs in `npm` result in incorrect lock files being updated. +This is currently applicable to `npm` only, and only used in cases where bugs in `npm` result in incorrect lock files being updated. ## token diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index d1b107a81db3d3..096433b21e8945 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -1025,7 +1025,7 @@ const options: RenovateOptions[] = [ { name: 'updateInternalDeps', description: - 'Whether to update internal dep versions in a monorepo. Works on Lerna or Yarn Workspaces.', + 'Whether to update internal dep versions in a monorepo. Works on Yarn Workspaces.', type: 'boolean', default: false, stage: 'package', diff --git a/lib/modules/manager/npm/__fixtures__/inputs/workspaces-simple.json b/lib/modules/manager/npm/__fixtures__/inputs/workspaces-simple.json deleted file mode 100644 index 919fe6cd3d93f4..00000000000000 --- a/lib/modules/manager/npm/__fixtures__/inputs/workspaces-simple.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@a/b", - "version": "0.0.8", - "private": true, - "workspaces": ["packages/*"], - "license": "MIT", - "dependencies": {} -} 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 5d4c0f17c8bfb6..863cb69ff262db 100644 --- a/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap +++ b/lib/modules/manager/npm/extract/__snapshots__/index.spec.ts.snap @@ -13,9 +13,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() catches invalid "extractedConstraints": {}, "managerData": { "hasPackageManager": false, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": undefined, "packageJsonName": undefined, "pnpmShrinkwrap": undefined, @@ -134,9 +131,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts engine }, "managerData": { "hasPackageManager": false, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": undefined, "packageJsonName": undefined, "pnpmShrinkwrap": undefined, @@ -314,9 +308,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts non-np "extractedConstraints": {}, "managerData": { "hasPackageManager": false, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": undefined, "packageJsonName": undefined, "pnpmShrinkwrap": undefined, @@ -399,9 +390,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts npm pa "extractedConstraints": {}, "managerData": { "hasPackageManager": false, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": "package-lock.json", "packageJsonName": undefined, "pnpmShrinkwrap": undefined, @@ -433,9 +421,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts packag }, "managerData": { "hasPackageManager": true, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": undefined, "packageJsonName": undefined, "pnpmShrinkwrap": undefined, @@ -508,9 +493,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta }, "managerData": { "hasPackageManager": false, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": undefined, "packageJsonName": undefined, "pnpmShrinkwrap": undefined, @@ -562,9 +544,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta }, "managerData": { "hasPackageManager": false, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": undefined, "packageJsonName": undefined, "pnpmShrinkwrap": undefined, @@ -578,278 +557,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() extracts volta } `; -exports[`modules/manager/npm/extract/index .extractPackageFile() finds "npmClient":"npm" in lerna.json 1`] = ` -{ - "deps": [ - { - "currentValue": "6.5.0", - "datasource": "npm", - "depName": "autoprefixer", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "~1.6.0", - "datasource": "npm", - "depName": "bower", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "13.1.0", - "datasource": "npm", - "depName": "browserify", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "0.9.2", - "datasource": "npm", - "depName": "browserify-css", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "=0.22.0", - "datasource": "npm", - "depName": "cheerio", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "1.21.0", - "datasource": "npm", - "depName": "config", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "depName": "enabled", - "depType": "devDependencies", - "prettyDepType": "devDependency", - "skipReason": "invalid-value", - }, - { - "currentValue": "^1.5.8", - "datasource": "npm", - "depName": "angular", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "1.5.8", - "datasource": "npm", - "depName": "angular-touch", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "1.5.8", - "datasource": "npm", - "depName": "angular-sanitize", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "4.0.0-beta.1", - "datasource": "npm", - "depName": "@angular/core", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "1.21.0", - "datasource": "npm", - "depName": "config", - "depType": "resolutions", - "prettyDepType": "resolutions", - }, - { - "currentValue": "8.0.0", - "datasource": "npm", - "depName": "@angular/cli", - "depType": "resolutions", - "managerData": { - "key": "**/@angular/cli", - }, - "prettyDepType": "resolutions", - }, - { - "currentValue": "1.33.0", - "datasource": "npm", - "depName": "angular", - "depType": "resolutions", - "managerData": { - "key": "**/angular", - }, - "prettyDepType": "resolutions", - }, - { - "currentValue": "1.0.0", - "datasource": "npm", - "depName": "glob", - "depType": "resolutions", - "managerData": { - "key": "config/glob", - }, - "prettyDepType": "resolutions", - }, - ], - "extractedConstraints": {}, - "managerData": { - "hasPackageManager": false, - "lernaClient": "npm", - "lernaJsonFile": "lerna.json", - "lernaPackages": undefined, - "npmLock": undefined, - "packageJsonName": "renovate", - "pnpmShrinkwrap": undefined, - "workspacesPackages": undefined, - "yarnLock": undefined, - "yarnZeroInstall": false, - }, - "npmrc": undefined, - "packageFileVersion": "1.0.0", - "skipInstalls": true, -} -`; - -exports[`modules/manager/npm/extract/index .extractPackageFile() finds "npmClient":"yarn" in lerna.json 1`] = ` -{ - "deps": [ - { - "currentValue": "6.5.0", - "datasource": "npm", - "depName": "autoprefixer", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "~1.6.0", - "datasource": "npm", - "depName": "bower", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "13.1.0", - "datasource": "npm", - "depName": "browserify", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "0.9.2", - "datasource": "npm", - "depName": "browserify-css", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "=0.22.0", - "datasource": "npm", - "depName": "cheerio", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "1.21.0", - "datasource": "npm", - "depName": "config", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "depName": "enabled", - "depType": "devDependencies", - "prettyDepType": "devDependency", - "skipReason": "invalid-value", - }, - { - "currentValue": "^1.5.8", - "datasource": "npm", - "depName": "angular", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "1.5.8", - "datasource": "npm", - "depName": "angular-touch", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "1.5.8", - "datasource": "npm", - "depName": "angular-sanitize", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "4.0.0-beta.1", - "datasource": "npm", - "depName": "@angular/core", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "1.21.0", - "datasource": "npm", - "depName": "config", - "depType": "resolutions", - "prettyDepType": "resolutions", - }, - { - "currentValue": "8.0.0", - "datasource": "npm", - "depName": "@angular/cli", - "depType": "resolutions", - "managerData": { - "key": "**/@angular/cli", - }, - "prettyDepType": "resolutions", - }, - { - "currentValue": "1.33.0", - "datasource": "npm", - "depName": "angular", - "depType": "resolutions", - "managerData": { - "key": "**/angular", - }, - "prettyDepType": "resolutions", - }, - { - "currentValue": "1.0.0", - "datasource": "npm", - "depName": "glob", - "depType": "resolutions", - "managerData": { - "key": "config/glob", - }, - "prettyDepType": "resolutions", - }, - ], - "extractedConstraints": {}, - "managerData": { - "hasPackageManager": false, - "lernaClient": "yarn", - "lernaJsonFile": "lerna.json", - "lernaPackages": undefined, - "npmLock": undefined, - "packageJsonName": "renovate", - "pnpmShrinkwrap": undefined, - "workspacesPackages": undefined, - "yarnLock": undefined, - "yarnZeroInstall": false, - }, - "npmrc": undefined, - "packageFileVersion": "1.0.0", - "skipInstalls": true, -} -`; - exports[`modules/manager/npm/extract/index .extractPackageFile() finds a lock file 1`] = ` { "deps": [ @@ -970,9 +677,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() finds a lock fi "extractedConstraints": {}, "managerData": { "hasPackageManager": false, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": undefined, "packageJsonName": "renovate", "pnpmShrinkwrap": undefined, @@ -992,193 +696,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() finds complex y "extractedConstraints": {}, "managerData": { "hasPackageManager": false, - "lernaClient": "npm", - "lernaJsonFile": "lerna.json", - "lernaPackages": undefined, - "npmLock": undefined, - "packageJsonName": "@a/b", - "pnpmShrinkwrap": undefined, - "workspacesPackages": [ - "packages/*", - ], - "yarnLock": undefined, - "yarnZeroInstall": false, - }, - "npmrc": undefined, - "packageFileVersion": "0.0.8", - "skipInstalls": true, -} -`; - -exports[`modules/manager/npm/extract/index .extractPackageFile() finds lerna 1`] = ` -{ - "deps": [ - { - "currentValue": "6.5.0", - "datasource": "npm", - "depName": "autoprefixer", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "~1.6.0", - "datasource": "npm", - "depName": "bower", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "13.1.0", - "datasource": "npm", - "depName": "browserify", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "0.9.2", - "datasource": "npm", - "depName": "browserify-css", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "=0.22.0", - "datasource": "npm", - "depName": "cheerio", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "currentValue": "1.21.0", - "datasource": "npm", - "depName": "config", - "depType": "dependencies", - "prettyDepType": "dependency", - }, - { - "depName": "enabled", - "depType": "devDependencies", - "prettyDepType": "devDependency", - "skipReason": "invalid-value", - }, - { - "currentValue": "^1.5.8", - "datasource": "npm", - "depName": "angular", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "1.5.8", - "datasource": "npm", - "depName": "angular-touch", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "1.5.8", - "datasource": "npm", - "depName": "angular-sanitize", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "4.0.0-beta.1", - "datasource": "npm", - "depName": "@angular/core", - "depType": "devDependencies", - "prettyDepType": "devDependency", - }, - { - "currentValue": "1.21.0", - "datasource": "npm", - "depName": "config", - "depType": "resolutions", - "prettyDepType": "resolutions", - }, - { - "currentValue": "8.0.0", - "datasource": "npm", - "depName": "@angular/cli", - "depType": "resolutions", - "managerData": { - "key": "**/@angular/cli", - }, - "prettyDepType": "resolutions", - }, - { - "currentValue": "1.33.0", - "datasource": "npm", - "depName": "angular", - "depType": "resolutions", - "managerData": { - "key": "**/angular", - }, - "prettyDepType": "resolutions", - }, - { - "currentValue": "1.0.0", - "datasource": "npm", - "depName": "glob", - "depType": "resolutions", - "managerData": { - "key": "config/glob", - }, - "prettyDepType": "resolutions", - }, - ], - "extractedConstraints": {}, - "managerData": { - "hasPackageManager": false, - "lernaClient": "npm", - "lernaJsonFile": "lerna.json", - "lernaPackages": undefined, - "npmLock": undefined, - "packageJsonName": "renovate", - "pnpmShrinkwrap": undefined, - "workspacesPackages": undefined, - "yarnLock": undefined, - "yarnZeroInstall": false, - }, - "npmrc": undefined, - "packageFileVersion": "1.0.0", - "skipInstalls": true, -} -`; - -exports[`modules/manager/npm/extract/index .extractPackageFile() finds simple yarn workspaces 1`] = ` -{ - "deps": [], - "extractedConstraints": {}, - "managerData": { - "hasPackageManager": false, - "lernaClient": "npm", - "lernaJsonFile": "lerna.json", - "lernaPackages": undefined, - "npmLock": undefined, - "packageJsonName": "@a/b", - "pnpmShrinkwrap": undefined, - "workspacesPackages": [ - "packages/*", - ], - "yarnLock": undefined, - "yarnZeroInstall": false, - }, - "npmrc": undefined, - "packageFileVersion": "0.0.8", - "skipInstalls": true, -} -`; - -exports[`modules/manager/npm/extract/index .extractPackageFile() finds simple yarn workspaces with lerna.json and useWorkspaces: true 1`] = ` -{ - "deps": [], - "extractedConstraints": {}, - "managerData": { - "hasPackageManager": false, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": undefined, "packageJsonName": "@a/b", "pnpmShrinkwrap": undefined, @@ -1314,9 +831,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() returns an arra "extractedConstraints": {}, "managerData": { "hasPackageManager": false, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": undefined, "packageJsonName": "renovate", "pnpmShrinkwrap": undefined, @@ -1432,9 +946,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() returns an arra "extractedConstraints": {}, "managerData": { "hasPackageManager": false, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": undefined, "packageJsonName": "renovate", "pnpmShrinkwrap": undefined, @@ -1568,9 +1079,6 @@ exports[`modules/manager/npm/extract/index .extractPackageFile() sets skipInstal "extractedConstraints": {}, "managerData": { "hasPackageManager": false, - "lernaClient": undefined, - "lernaJsonFile": undefined, - "lernaPackages": undefined, "npmLock": undefined, "packageJsonName": "renovate", "pnpmShrinkwrap": undefined, diff --git a/lib/modules/manager/npm/extract/index.spec.ts b/lib/modules/manager/npm/extract/index.spec.ts index 9c722b0e61a11c..f89aa82caaa8aa 100644 --- a/lib/modules/manager/npm/extract/index.spec.ts +++ b/lib/modules/manager/npm/extract/index.spec.ts @@ -15,10 +15,6 @@ const input01Content = Fixtures.get('inputs/01.json', '..'); const input02Content = Fixtures.get('inputs/02.json', '..'); const input01GlobContent = Fixtures.get('inputs/01-glob.json', '..'); const workspacesContent = Fixtures.get('inputs/workspaces.json', '..'); -const workspacesSimpleContent = Fixtures.get( - 'inputs/workspaces-simple.json', - '..' -); const vendorisedContent = Fixtures.get('is-object.json', '..'); const invalidNameContent = Fixtures.get('invalid-name.json', '..'); @@ -297,108 +293,8 @@ describe('modules/manager/npm/extract/index', () => { ).toBeArrayIncludingOnly(['https://registry.example.com']); }); - it('finds lerna', async () => { - fs.readLocalFile.mockImplementation((fileName): Promise => { - if (fileName === 'lerna.json') { - return Promise.resolve('{}'); - } - return Promise.resolve(null); - }); - const res = await npmExtract.extractPackageFile( - input01Content, - 'package.json', - defaultExtractConfig - ); - expect(res).toMatchSnapshot({ - managerData: { - lernaClient: 'npm', - lernaJsonFile: 'lerna.json', - lernaPackages: undefined, - }, - }); - }); - - it('finds "npmClient":"npm" in lerna.json', async () => { - fs.readLocalFile.mockImplementation((fileName): Promise => { - if (fileName === 'lerna.json') { - return Promise.resolve('{ "npmClient": "npm" }'); - } - return Promise.resolve(null); - }); - const res = await npmExtract.extractPackageFile( - input01Content, - 'package.json', - defaultExtractConfig - ); - expect(res).toMatchSnapshot({ - managerData: { - lernaClient: 'npm', - lernaJsonFile: 'lerna.json', - lernaPackages: undefined, - }, - }); - }); - - it('finds "npmClient":"yarn" in lerna.json', async () => { - fs.readLocalFile.mockImplementation((fileName): Promise => { - if (fileName === 'lerna.json') { - return Promise.resolve('{ "npmClient": "yarn" }'); - } - return Promise.resolve(null); - }); - const res = await npmExtract.extractPackageFile( - input01Content, - 'package.json', - defaultExtractConfig - ); - expect(res).toMatchSnapshot({ - managerData: { - lernaClient: 'yarn', - lernaJsonFile: 'lerna.json', - lernaPackages: undefined, - }, - }); - }); - - it('finds simple yarn workspaces', async () => { - fs.readLocalFile.mockImplementation((fileName): Promise => { - if (fileName === 'lerna.json') { - return Promise.resolve('{}'); - } - return Promise.resolve(null); - }); - const res = await npmExtract.extractPackageFile( - workspacesSimpleContent, - 'package.json', - defaultExtractConfig - ); - expect(res).toMatchSnapshot({ - managerData: { workspacesPackages: ['packages/*'] }, - }); - }); - - it('finds simple yarn workspaces with lerna.json and useWorkspaces: true', async () => { - fs.readLocalFile.mockImplementation((fileName): Promise => { - if (fileName === 'lerna.json') { - return Promise.resolve('{"useWorkspaces": true}'); - } - return Promise.resolve(null); - }); - const res = await npmExtract.extractPackageFile( - workspacesSimpleContent, - 'package.json', - defaultExtractConfig - ); - expect(res).toMatchSnapshot({ - managerData: { workspacesPackages: ['packages/*'] }, - }); - }); - it('finds complex yarn workspaces', async () => { fs.readLocalFile.mockImplementation((fileName): Promise => { - if (fileName === 'lerna.json') { - return Promise.resolve('{}'); - } return Promise.resolve(null); }); const res = await npmExtract.extractPackageFile( @@ -953,9 +849,6 @@ describe('modules/manager/npm/extract/index', () => { extractedConstraints: {}, managerData: { hasPackageManager: false, - lernaClient: undefined, - lernaJsonFile: undefined, - lernaPackages: undefined, npmLock: undefined, packageJsonName: 'renovate', pnpmShrinkwrap: undefined, diff --git a/lib/modules/manager/npm/extract/index.ts b/lib/modules/manager/npm/extract/index.ts index eaa69695a66b79..c24dd78923c849 100644 --- a/lib/modules/manager/npm/extract/index.ts +++ b/lib/modules/manager/npm/extract/index.ts @@ -136,31 +136,6 @@ export async function extractPackageFile( yarnConfig = loadConfigFromLegacyYarnrc(repoLegacyYarnrc); } - let lernaJsonFile: string | undefined; - let lernaPackages: string[] | undefined; - let lernaClient: 'yarn' | 'npm' | undefined; - let lernaJson: - | { - packages: string[]; - npmClient: string; - useWorkspaces?: boolean; - } - | undefined; - try { - lernaJsonFile = getSiblingFileName(packageFile, 'lerna.json'); - // TODO #22198 - lernaJson = JSON.parse((await readLocalFile(lernaJsonFile, 'utf8'))!); - } catch (err) /* istanbul ignore next */ { - logger.debug({ err, lernaJsonFile }, 'Could not parse lerna.json'); - } - if (lernaJson && !lernaJson.useWorkspaces) { - lernaPackages = lernaJson.packages; - lernaClient = - lernaJson.npmClient === 'yarn' || lockFiles.yarnLock ? 'yarn' : 'npm'; - } else { - lernaJsonFile = undefined; - } - if (res.deps.length === 0) { logger.debug('Package file has no deps'); if ( @@ -168,7 +143,6 @@ export async function extractPackageFile( !!res.managerData?.packageJsonName || !!res.packageFileVersion || !!npmrc || - !!lernaJsonFile || workspacesPackages ) ) { @@ -218,9 +192,6 @@ export async function extractPackageFile( managerData: { ...res.managerData, ...lockFiles, - lernaClient, - lernaJsonFile, - lernaPackages, yarnZeroInstall, hasPackageManager: is.nonEmptyStringAndNotWhitespace( packageJson.packageManager diff --git a/lib/modules/manager/npm/extract/post/monorepo.spec.ts b/lib/modules/manager/npm/extract/post/monorepo.spec.ts index 789e7ab97b53d5..ca861fbf817d20 100644 --- a/lib/modules/manager/npm/extract/post/monorepo.spec.ts +++ b/lib/modules/manager/npm/extract/post/monorepo.spec.ts @@ -16,119 +16,12 @@ describe('modules/manager/npm/extract/post/monorepo', () => { expect(packageFiles).toHaveLength(1); }); - it('uses lerna package settings', async () => { - const packageFiles: Partial[] = [ - { - packageFile: 'package.json', - managerData: { - lernaJsonFile: 'lerna.json', - lernaPackages: ['packages/*'], - }, - deps: [ - { - depName: '@org/a', - }, - { - depName: '@org/b', - }, - { - depName: '@org/c', - }, - { - depName: 'lerna', - currentValue: '^6.0.0', - }, - ], - }, - { - packageFile: 'packages/a/package.json', - managerData: { packageJsonName: '@org/a' }, - deps: [ - { - depName: '@org/b', - }, - { - depName: '@org/c', - }, - { - depName: 'bar', - }, - ], - }, - { - packageFile: 'packages/b/package.json', - managerData: { packageJsonName: '@org/b' }, - }, - ]; - await detectMonorepos(packageFiles); - expect(packageFiles[1].managerData?.lernaJsonFile).toBe('lerna.json'); - expect( - packageFiles.some((packageFile) => - packageFile.deps?.some((dep) => dep.isInternal) - ) - ).toBeTrue(); - }); - - it('skips lerna package settings if v7 or later', async () => { - const packageFiles: Partial[] = [ - { - packageFile: 'package.json', - managerData: { - lernaJsonFile: 'lerna.json', - lernaPackages: ['packages/*'], - }, - deps: [ - { - depName: '@org/a', - }, - { - depName: '@org/b', - }, - { - depName: '@org/c', - }, - { - depName: 'lerna', - currentValue: '^7.0.0', - }, - ], - }, - { - packageFile: 'packages/a/package.json', - managerData: { packageJsonName: '@org/a' }, - deps: [ - { - depName: '@org/b', - }, - { - depName: '@org/c', - }, - { - depName: 'bar', - }, - ], - }, - { - packageFile: 'packages/b/package.json', - managerData: { packageJsonName: '@org/b' }, - }, - ]; - await detectMonorepos(packageFiles); - expect(packageFiles[1].managerData?.lernaJsonFile).toBeUndefined(); - expect( - packageFiles.some((packageFile) => - packageFile.deps?.some((dep) => dep.isInternal) - ) - ).toBeFalse(); - }); - it('updates internal packages', async () => { const packageFiles: Partial[] = [ { packageFile: 'package.json', managerData: { - lernaJsonFile: 'lerna.json', - lernaPackages: ['packages/*'], + workspacesPackages: ['packages/*'], }, deps: [ { @@ -141,7 +34,7 @@ describe('modules/manager/npm/extract/post/monorepo', () => { depName: '@org/c', }, { - depName: 'lerna', + depName: 'foo', currentValue: '6.1.0', }, ], @@ -171,7 +64,6 @@ describe('modules/manager/npm/extract/post/monorepo', () => { }, ]; await detectMonorepos(packageFiles); - expect(packageFiles[1].managerData?.lernaJsonFile).toBe('lerna.json'); expect( packageFiles.some((packageFile) => packageFile.deps?.some((dep) => dep.isInternal) @@ -179,37 +71,7 @@ describe('modules/manager/npm/extract/post/monorepo', () => { ).toBeTrue(); }); - it('uses yarn workspaces package settings with lerna', async () => { - const packageFiles: Partial[] = [ - { - packageFile: 'package.json', - managerData: { - lernaClient: 'yarn', - lernaJsonFile: 'lerna.json', - lernaPackages: ['oldpackages/*'], - workspacesPackages: ['packages/*'], - }, - deps: [ - { - depName: 'lerna', - currentValue: '^6.0.0', - }, - ], - }, - { - packageFile: 'packages/a/package.json', - managerData: { packageJsonName: '@org/a' }, - }, - { - packageFile: 'packages/b/package.json', - managerData: { packageJsonName: '@org/b' }, - }, - ]; - await detectMonorepos(packageFiles); - expect(packageFiles[1].managerData?.lernaJsonFile).toBe('lerna.json'); - }); - - it('uses yarn workspaces package settings without lerna', async () => { + it('uses yarn workspaces package settings', async () => { const packageFiles: Partial[] = [ { packageFile: 'package.json', diff --git a/lib/modules/manager/npm/extract/post/monorepo.ts b/lib/modules/manager/npm/extract/post/monorepo.ts index 3b99073f7bac8f..9e9eb18cf7011a 100644 --- a/lib/modules/manager/npm/extract/post/monorepo.ts +++ b/lib/modules/manager/npm/extract/post/monorepo.ts @@ -1,5 +1,4 @@ import is from '@sindresorhus/is'; -import semver from 'semver'; import { logger } from '../../../../../logger'; import { getParentDir, getSiblingFileName } from '../../../../../util/fs'; import type { PackageFile } from '../../../types'; @@ -12,34 +11,9 @@ export async function detectMonorepos( ): Promise { await detectPnpmWorkspaces(packageFiles); logger.debug('Detecting workspaces'); - // ignore lerna if using v7 or later by deleting all metadata - for (const p of packageFiles) { - if (p.managerData?.lernaJsonFile) { - const lernaConstraint = p.deps?.find( - (dep) => dep.depName === 'lerna' - )?.currentValue; - if ( - !lernaConstraint || - !semver.validRange(lernaConstraint) || - semver.intersects(lernaConstraint, '>=7.0.0') - ) { - logger.debug('Deleting lerna metadata as v7 or later is in use'); - delete p.managerData.lernaJsonFile; - delete p.managerData.lernaPackages; - delete p.managerData.lernaClient; - } else { - logger.warn( - 'Support for lerna <7 is now deprecated, please prioritize updating to v7' - ); - } - } - } for (const p of packageFiles) { const { packageFile, npmrc, managerData = {}, skipInstalls } = p; const { - lernaClient, - lernaJsonFile, - lernaPackages, npmLock, yarnZeroInstall, hasPackageManager, @@ -47,9 +21,7 @@ export async function detectMonorepos( yarnLock, } = managerData; - const packages = (workspacesPackages ?? lernaPackages) as - | string[] - | undefined; + const packages = workspacesPackages as string[] | undefined; if (packages?.length) { const internalPackagePatterns = ( is.array(packages) ? packages : [packages] @@ -75,10 +47,8 @@ export async function detectMonorepos( for (const subPackage of internalPackageFiles) { subPackage.managerData = subPackage.managerData ?? {}; - subPackage.managerData.lernaJsonFile = lernaJsonFile; subPackage.managerData.yarnZeroInstall = yarnZeroInstall; subPackage.managerData.hasPackageManager = hasPackageManager; - subPackage.managerData.lernaClient = lernaClient; subPackage.managerData.yarnLock ??= yarnLock; subPackage.managerData.npmLock ??= npmLock; subPackage.skipInstalls = skipInstalls && subPackage.skipInstalls; // skip if both are true diff --git a/lib/modules/manager/npm/post-update/__snapshots__/lerna.spec.ts.snap b/lib/modules/manager/npm/post-update/__snapshots__/lerna.spec.ts.snap deleted file mode 100644 index 342c3a66ed9f5c..00000000000000 --- a/lib/modules/manager/npm/post-update/__snapshots__/lerna.spec.ts.snap +++ /dev/null @@ -1,260 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`modules/manager/npm/post-update/lerna generateLockFiles() allows scripts for trust level high 1`] = ` -[ - { - "cmd": "lerna info || echo "Ignoring lerna info failure"", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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, - }, - }, - { - "cmd": "npm install --no-audit --package-lock-only", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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, - }, - }, - { - "cmd": "lerna bootstrap --no-ci -- --no-audit --package-lock-only", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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/lerna generateLockFiles() defaults to latest and skips bootstrap if lerna version unspecified 1`] = ` -[ - { - "cmd": "npm install --ignore-scripts --no-audit --package-lock-only", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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/lerna generateLockFiles() generates package-lock.json files 1`] = ` -[ - { - "cmd": "lerna info || echo "Ignoring lerna info failure"", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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, - }, - }, - { - "cmd": "npm install --ignore-scripts --no-audit --package-lock-only", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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, - }, - }, - { - "cmd": "lerna bootstrap --no-ci --ignore-scripts -- --ignore-scripts --no-audit --package-lock-only", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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/lerna generateLockFiles() generates yarn.lock files 1`] = ` -[ - { - "cmd": "lerna info || echo "Ignoring lerna info failure"", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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, - }, - }, - { - "cmd": "yarn install --ignore-scripts --ignore-engines --ignore-platform", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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, - }, - }, - { - "cmd": "lerna bootstrap --no-ci --ignore-scripts -- --ignore-scripts --ignore-engines --ignore-platform", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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/lerna generateLockFiles() performs full npm install 1`] = ` -[ - { - "cmd": "lerna info || echo "Ignoring lerna info failure"", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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, - }, - }, - { - "cmd": "npm install --ignore-scripts --no-audit", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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, - }, - }, - { - "cmd": "lerna bootstrap --no-ci --ignore-scripts -- --ignore-scripts --no-audit", - "options": { - "cwd": "some-dir", - "encoding": "utf-8", - "env": { - "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, - }, - }, -] -`; diff --git a/lib/modules/manager/npm/post-update/index.spec.ts b/lib/modules/manager/npm/post-update/index.spec.ts index c6eaaacc1497d1..274b9d883462ec 100644 --- a/lib/modules/manager/npm/post-update/index.spec.ts +++ b/lib/modules/manager/npm/post-update/index.spec.ts @@ -5,7 +5,6 @@ import { fs, git, logger, partial, scm } from '../../../../../test/util'; import { GlobalConfig } from '../../../../config/global'; import type { FileChange } from '../../../../util/git/types'; import type { PostUpdateConfig } from '../../types'; -import * as lerna from './lerna'; import * as npm from './npm'; import * as pnpm from './pnpm'; import type { AdditionalPackageFiles } from './types'; @@ -20,7 +19,6 @@ import { jest.mock('../../../../util/fs'); jest.mock('../../../../util/git'); -jest.mock('./lerna'); jest.mock('./npm'); jest.mock('./yarn'); jest.mock('./pnpm'); @@ -34,7 +32,6 @@ describe('modules/manager/npm/post-update/index', () => { { packageFile: 'packages/core/package.json', managerData: { - lernaJsonFile: 'lerna.json', npmLock: 'package-lock.json', }, npmrc: '#dummy', @@ -42,7 +39,6 @@ describe('modules/manager/npm/post-update/index', () => { { packageFile: 'packages/cli/package.json', managerData: { - lernaJsonFile: 'lerna.json', yarnLock: 'yarn.lock', }, }, @@ -76,7 +72,6 @@ describe('modules/manager/npm/post-update/index', () => { depName: 'postcss', isRemediation: true, managerData: { - lernaJsonFile: 'lerna.json', npmLock: 'package-lock.json', }, rangeStrategy: 'widen', @@ -85,7 +80,6 @@ describe('modules/manager/npm/post-update/index', () => { depName: 'core-js', isRemediation: true, managerData: { - lernaJsonFile: 'lerna.json', npmLock: 'randomFolder/package-lock.json', }, lockFiles: ['randomFolder/package-lock.json'], @@ -165,7 +159,6 @@ describe('modules/manager/npm/post-update/index', () => { additionalFiles ) ).toStrictEqual({ - lernaJsonFiles: ['lerna.json'], npmLockDirs: ['package-lock.json'], pnpmShrinkwrapDirs: ['packages/pnpm/pnpm-lock.yaml'], yarnLockDirs: ['yarn.lock'], @@ -189,7 +182,6 @@ describe('modules/manager/npm/post-update/index', () => { {} ) ).toStrictEqual({ - lernaJsonFiles: [], npmLockDirs: [], pnpmShrinkwrapDirs: [], yarnLockDirs: ['yarn.lock'], @@ -399,13 +391,11 @@ describe('modules/manager/npm/post-update/index', () => { describe('getAdditionalFiles()', () => { const spyNpm = jest.spyOn(npm, 'generateLockFile'); - const spyLerna = jest.spyOn(lerna, 'generateLockFiles'); const spyYarn = jest.spyOn(yarn, 'generateLockFile'); const spyPnpm = jest.spyOn(pnpm, 'generateLockFile'); beforeEach(() => { spyNpm.mockResolvedValue({}); - spyLerna.mockResolvedValue({}); spyPnpm.mockResolvedValue({}); spyYarn.mockResolvedValue({}); }); @@ -565,91 +555,6 @@ describe('modules/manager/npm/post-update/index', () => { expect(fs.deleteLocalFile).toHaveBeenCalled(); }); - it('works for lerna (yarn)', async () => { - git.getFile.mockImplementation((f) => { - if (f === 'yarn.lock') { - return Promise.resolve('# some contents'); - } - return Promise.resolve(null); - }); - expect( - await getAdditionalFiles( - { - ...updateConfig, - updateLockFiles: true, - reuseExistingBranch: true, - upgrades: [ - { - isRemediation: true, - packageFile: 'packages/core/package.json', - }, - ], - }, - additionalFiles - ) - ).toStrictEqual({ - artifactErrors: [], - updatedArtifacts: [ - { - type: 'addition', - path: 'packages/pnpm/pnpm-lock.yaml', - contents: undefined, - }, - { - type: 'addition', - path: 'yarn.lock', - contents: undefined, - }, - { - type: 'addition', - path: 'yarn.lock', - contents: undefined, - }, - ], - }); - expect(fs.deleteLocalFile).toHaveBeenCalled(); - }); - - it('works for lerna (npm)', async () => { - git.getFile.mockImplementation((f) => { - if (f === 'package-lock.json') { - return Promise.resolve('{}'); - } - return Promise.resolve(null); - }); - expect( - await getAdditionalFiles( - { - ...updateConfig, - updateLockFiles: true, - upgrades: [{}], - }, - { - npm: [ - { - packageFile: 'package.json', - managerData: { - lernaClient: 'npm', - lernaJsonFile: 'lerna.json', - npmLock: 'package-lock.json', - }, - }, - ], - } - ) - ).toStrictEqual({ - artifactErrors: [], - updatedArtifacts: [ - { - type: 'addition', - path: 'package-lock.json', - contents: undefined, - }, - ], - }); - expect(fs.deleteLocalFile).toHaveBeenCalled(); - }); - it('no npm files', async () => { expect(await getAdditionalFiles(baseConfig, {})).toStrictEqual({ artifactErrors: [], @@ -771,39 +676,5 @@ describe('modules/manager/npm/post-update/index', () => { updatedArtifacts: [], }); }); - - it('fails for lerna', async () => { - spyLerna.mockResolvedValueOnce({ stderr: 'some-error' }); - spyLerna.mockResolvedValueOnce({ stderr: 'some-error' }); - expect( - await getAdditionalFiles( - { - ...updateConfig, - managerData: { - npmLock: 'npm-shrinkwrap.json', - }, - updateLockFiles: true, - upgrades: [{}], - }, - { - npm: [ - { - packageFile: 'package.json', - managerData: { - lernaClient: 'npm', - lernaJsonFile: 'lerna.json', - npmLock: 'npm-shrinkwrap.json', - }, - }, - ], - } - ) - ).toStrictEqual({ - artifactErrors: [ - { lockFile: 'npm-shrinkwrap.json', stderr: 'some-error' }, - ], - updatedArtifacts: [], - }); - }); }); }); diff --git a/lib/modules/manager/npm/post-update/index.ts b/lib/modules/manager/npm/post-update/index.ts index 479e4593a9da8c..2a7578d37a01de 100644 --- a/lib/modules/manager/npm/post-update/index.ts +++ b/lib/modules/manager/npm/post-update/index.ts @@ -3,14 +3,12 @@ import is from '@sindresorhus/is'; import deepmerge from 'deepmerge'; import { dump, load } from 'js-yaml'; import upath from 'upath'; -import { SYSTEM_INSUFFICIENT_DISK_SPACE } from '../../../../constants/error-messages'; import { logger } from '../../../../logger'; import { ExternalHostError } from '../../../../types/errors/external-host-error'; import { getChildProcessEnv } from '../../../../util/exec/env'; import { deleteLocalFile, ensureCacheDir, - getParentDir, getSiblingFileName, readLocalFile, writeLocalFile, @@ -26,7 +24,6 @@ import type { PackageFile, PostUpdateConfig, Upgrade } from '../../types'; import { getZeroInstallPaths } from '../extract/yarn'; import type { NpmManagerData } from '../types'; import { composeLockFile, parseLockFile } from '../utils'; -import * as lerna from './lerna'; import * as npm from './npm'; import * as pnpm from './pnpm'; import { processHostRules } from './rules'; @@ -50,18 +47,9 @@ export function determineLockFileDirs( const npmLockDirs: (string | undefined)[] = []; const yarnLockDirs: (string | undefined)[] = []; const pnpmShrinkwrapDirs: (string | undefined)[] = []; - const lernaJsonFiles: (string | undefined)[] = []; for (const upgrade of config.upgrades) { if (upgrade.updateType === 'lockFileMaintenance' || upgrade.isRemediation) { - // Return every directory that contains a lockfile - if (upgrade.managerData?.lernaJsonFile && upgrade.managerData.npmLock) { - lernaJsonFiles.push(upgrade.managerData.lernaJsonFile); - } else { - yarnLockDirs.push(upgrade.managerData?.yarnLock); - npmLockDirs.push(upgrade.managerData?.npmLock); - pnpmShrinkwrapDirs.push(upgrade.managerData?.pnpmShrinkwrap); - } continue; } if (upgrade.isLockfileUpdate) { @@ -80,7 +68,6 @@ export function determineLockFileDirs( yarnLockDirs: getDirs(yarnLockDirs), npmLockDirs: getDirs(npmLockDirs), pnpmShrinkwrapDirs: getDirs(pnpmShrinkwrapDirs), - lernaJsonFiles: getDirs(lernaJsonFiles), }; } @@ -107,32 +94,16 @@ export function determineLockFileDirs( if (!packageFile.managerData) { continue; } - // lerna first - if ( - packageFile.managerData?.lernaJsonFile && - packageFile.managerData.npmLock - ) { - logger.debug(`${packageFile.packageFile} has lerna lock file`); - lernaJsonFiles.push(packageFile.managerData.lernaJsonFile); - } else if ( - packageFile.managerData?.lernaJsonFile && - packageFile.managerData.yarnLock && - !packageFile.managerData.workspacesPackages?.length - ) { - lernaJsonFiles.push(packageFile.managerData.lernaJsonFile); - } else { - // push full lock file names and convert them later - yarnLockDirs.push(packageFile.managerData.yarnLock); - npmLockDirs.push(packageFile.managerData.npmLock); - pnpmShrinkwrapDirs.push(packageFile.managerData.pnpmShrinkwrap); - } + // push full lock file names and convert them later + yarnLockDirs.push(packageFile.managerData.yarnLock); + npmLockDirs.push(packageFile.managerData.npmLock); + pnpmShrinkwrapDirs.push(packageFile.managerData.pnpmShrinkwrap); } return { yarnLockDirs: getDirs(yarnLockDirs), npmLockDirs: getDirs(npmLockDirs), pnpmShrinkwrapDirs: getDirs(pnpmShrinkwrapDirs), - lernaJsonFiles: getDirs(lernaJsonFiles), }; } @@ -734,147 +705,5 @@ export async function getAdditionalFiles( await resetNpmrcContent(lockFileDir, npmrcContent); } - for (const lernaJsonFile of dirs.lernaJsonFiles) { - let lockFile: string; - logger.debug(`Finding package.json for lerna location "${lernaJsonFile}"`); - const lernaPackageFile = packageFiles.npm.find( - // TODO #22198 - (p) => getParentDir(p.packageFile!) === getParentDir(lernaJsonFile) - ); - // istanbul ignore if: not sure how to test - if (!lernaPackageFile) { - logger.debug('No matching package.json found'); - throw new Error('lerna-no-lockfile'); - } - if (lernaPackageFile.managerData?.lernaClient === 'npm') { - lockFile = config.managerData?.npmLock ?? 'package-lock.json'; - } else { - lockFile = config.managerData?.yarnLock ?? 'yarn.lock'; - } - const skipInstalls = - lockFile === 'npm-shrinkwrap.json' ? false : config.skipInstalls; - const learnaFileDir = getParentDir(lernaJsonFile); - const npmrcContent = await getNpmrcContent(learnaFileDir); - await updateNpmrcContent( - learnaFileDir, - npmrcContent, - additionalNpmrcContent - ); - const res = await lerna.generateLockFiles( - lernaPackageFile, - getParentDir(lernaJsonFile), - config, - env, - skipInstalls - ); - if (res.stderr) { - // istanbul ignore if - if (res.stderr.includes('ENOSPC: no space left on device')) { - throw new Error(SYSTEM_INSUFFICIENT_DISK_SPACE); - } - for (const upgrade of config.upgrades) { - /* eslint-disable no-useless-escape */ - // istanbul ignore if: needs test - if ( - res.stderr.includes( - `Couldn't find any versions for \\\"${upgrade.depName}\\\"` - ) - ) { - logger.debug( - { dependency: upgrade.depName, type: 'yarn' }, - 'lock file failed for the dependency being updated - skipping branch creation' - ); - throw new ExternalHostError( - Error( - 'lock file failed for the dependency being updated - skipping branch creation' - ), - NpmDatasource.id - ); - } - /* eslint-enable no-useless-escape */ - // istanbul ignore if: needs test - if ( - res.stderr.includes( - `No matching version found for ${upgrade.depName}` - ) - ) { - logger.debug( - { dependency: upgrade.depName, type: 'npm' }, - 'lock file failed for the dependency being updated - skipping branch creation' - ); - throw new ExternalHostError( - Error( - 'lock file failed for the dependency being updated - skipping branch creation' - ), - NpmDatasource.id - ); - } - } - artifactErrors.push({ - lockFile, - stderr: res.stderr, - }); - } else { - for (const packageFile of packageFiles.npm) { - const filename = - packageFile.managerData?.npmLock ?? packageFile.managerData?.yarnLock; - // istanbul ignore if - if (!is.nonEmptyString(filename)) { - continue; - } - logger.trace(`Checking for ${filename}`); - const existingContent = await getFile( - // TODO #22198 - filename, - config.reuseExistingBranch ? config.branchName : config.baseBranch - ); - if (existingContent) { - logger.trace('Found lock file'); - // TODO #22198 - const lockFilePath = filename; - logger.trace('Checking against ' + lockFilePath); - try { - const newContent = - (await readLocalFile(lockFilePath, 'utf8')) ?? - (await readLocalFile( - lockFilePath.replace( - 'npm-shrinkwrap.json', - 'package-lock.json' - ), - 'utf8' - )); - // istanbul ignore if: needs test - if (newContent === existingContent) { - logger.trace('File is unchanged'); - } else { - logger.debug('File is updated: ' + lockFilePath); - updatedArtifacts.push({ - type: 'addition', - // TODO #22198 - path: filename, - contents: newContent, - }); - } - } catch (err) /* istanbul ignore next */ { - if (config.updateType === 'lockFileMaintenance') { - logger.debug( - { packageFile, lockFilePath }, - 'No lock file found after lerna lockFileMaintenance' - ); - } else { - logger.warn( - { packageFile, lockFilePath }, - 'No lock file found after lerna bootstrap' - ); - } - } - } else { - logger.trace('No lock file found'); - } - } - } - await resetNpmrcContent(learnaFileDir, npmrcContent); - } - return { artifactErrors, updatedArtifacts }; } diff --git a/lib/modules/manager/npm/post-update/lerna.spec.ts b/lib/modules/manager/npm/post-update/lerna.spec.ts deleted file mode 100644 index f81d5e535432eb..00000000000000 --- a/lib/modules/manager/npm/post-update/lerna.spec.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { mockDeep } from 'jest-mock-extended'; -import { envMock, mockExecAll } from '../../../../../test/exec-util'; -import { env, fs, mockedFunction, partial } from '../../../../../test/util'; -import { GlobalConfig } from '../../../../config/global'; -import type { RepoGlobalConfig } from '../../../../config/types'; -import type { PackageFileContent, PostUpdateConfig } from '../../types'; -import * as lernaHelper from './lerna'; -import { getNodeToolConstraint } from './node-version'; - -jest.mock('../../../../util/exec/env'); -jest.mock('../../../../util/fs'); -jest.mock('./node-version'); -jest.mock('../../../datasource', () => mockDeep()); - -process.env.CONTAINERBASE = 'true'; - -function lernaPkgFile(lernaClient: string): Partial { - return { - managerData: { lernaClient }, - }; -} - -const config = partial({ constraints: { lerna: '2.0.0' } }); - -describe('modules/manager/npm/post-update/lerna', () => { - const globalConfig: RepoGlobalConfig = { - localDir: '', - cacheDir: '/tmp/cache', - }; - - describe('generateLockFiles()', () => { - beforeEach(() => { - env.getChildProcessEnv.mockReturnValue(envMock.basic); - GlobalConfig.set(globalConfig); - mockedFunction(getNodeToolConstraint).mockResolvedValueOnce({ - toolName: 'node', - constraint: '16.16.0', - }); - }); - - it('returns if no lernaClient', async () => { - const res = await lernaHelper.generateLockFiles( - {}, - 'some-dir', - config, - {} - ); - expect(res.error).toBeFalse(); - }); - - it('returns if invalid lernaClient', async () => { - const res = await lernaHelper.generateLockFiles( - lernaPkgFile('foo'), - 'some-dir', - config, - {} - ); - expect(res.error).toBeFalse(); - }); - - it('generates package-lock.json files', async () => { - const execSnapshots = mockExecAll(); - const skipInstalls = true; - const res = await lernaHelper.generateLockFiles( - lernaPkgFile('npm'), - 'some-dir', - config, - {}, - skipInstalls - ); - expect(res.error).toBeFalse(); - expect(execSnapshots).toMatchSnapshot(); - }); - - it('performs full npm install', async () => { - const execSnapshots = mockExecAll(); - const skipInstalls = false; - const res = await lernaHelper.generateLockFiles( - lernaPkgFile('npm'), - 'some-dir', - config, - {}, - skipInstalls - ); - expect(res.error).toBeFalse(); - expect(execSnapshots).toMatchSnapshot(); - }); - - it('generates yarn.lock files', async () => { - const execSnapshots = mockExecAll(); - fs.readLocalFile.mockResolvedValueOnce( - '{"packageManager":"yarn@^1.10.0"}' - ); - const res = await lernaHelper.generateLockFiles( - lernaPkgFile('yarn'), - 'some-dir', - { ...config }, - {} - ); - expect(execSnapshots).toMatchSnapshot(); - expect(res.error).toBeFalse(); - }); - - it('defaults to latest and skips bootstrap if lerna version unspecified', async () => { - const execSnapshots = mockExecAll(); - const res = await lernaHelper.generateLockFiles( - lernaPkgFile('npm'), - 'some-dir', - { ...config, constraints: null }, - {} - ); - expect(res.error).toBeFalse(); - expect(execSnapshots).toMatchSnapshot(); - }); - - it('allows scripts for trust level high', async () => { - const execSnapshots = mockExecAll(); - GlobalConfig.set({ ...globalConfig, allowScripts: true }); - const res = await lernaHelper.generateLockFiles( - lernaPkgFile('npm'), - 'some-dir', - { ...config, constraints: { ...config.constraints, npm: '^6.0.0' } }, - {} - ); - expect(res.error).toBeFalse(); - expect(execSnapshots).toMatchSnapshot(); - }); - - it('suppports docker', async () => { - const execSnapshots = mockExecAll(); - GlobalConfig.set({ - ...globalConfig, - binarySource: 'docker', - dockerSidecarImage: 'ghcr.io/containerbase/sidecar', - }); - - const res = await lernaHelper.generateLockFiles( - lernaPkgFile('npm'), - 'some-dir', - { ...config, constraints: { ...config.constraints, npm: '6.0.0' } }, - {} - ); - expect(execSnapshots).toMatchObject([ - { - cmd: 'docker pull ghcr.io/containerbase/sidecar', - }, - { - cmd: 'docker ps --filter name=renovate_sidecar -aq', - }, - { - cmd: - 'docker run --rm --name=renovate_sidecar --label=renovate_child ' + - '-v "/tmp/cache":"/tmp/cache" ' + - '-e CONTAINERBASE_CACHE_DIR ' + - '-w "some-dir" ghcr.io/containerbase/sidecar ' + - 'bash -l -c "' + - 'install-tool node 16.16.0 ' + - '&& ' + - 'install-tool npm 6.0.0 ' + - '&& ' + - 'hash -d npm 2>/dev/null || true ' + - '&& ' + - 'install-tool lerna 2.0.0 ' + - '&& ' + - 'lerna info || echo \\"Ignoring lerna info failure\\" ' + - '&& ' + - 'npm install --ignore-scripts --no-audit --package-lock-only ' + - '&& ' + - 'lerna bootstrap --no-ci --ignore-scripts -- --ignore-scripts --no-audit --package-lock-only' + - '"', - options: { - cwd: 'some-dir', - }, - }, - ]); - expect(res.error).toBeFalse(); - }); - - it('suppports binarySource=install', async () => { - const execSnapshots = mockExecAll(); - GlobalConfig.set({ ...globalConfig, binarySource: 'install' }); - - const res = await lernaHelper.generateLockFiles( - lernaPkgFile('npm'), - 'some-dir', - { - ...config, - constraints: { ...config.constraints, lerna: '^7.1.4', npm: '6.0.0' }, - }, - {} - ); - expect(res.error).toBeFalse(); - expect(execSnapshots).toMatchObject([ - { cmd: 'install-tool node 16.16.0' }, - { cmd: 'install-tool npm 6.0.0' }, - { cmd: 'hash -d npm 2>/dev/null || true' }, - { - cmd: 'npm install --ignore-scripts --no-audit --package-lock-only', - options: { - cwd: 'some-dir', - }, - }, - ]); - }); - }); - - describe('getLernaVersion()', () => { - it('returns specified version', () => { - const pkg = {}; - expect( - lernaHelper.getLernaConstraint(pkg, { - devDependencies: { lerna: '2.0.0' }, - }) - ).toBe('2.0.0'); - }); - - it('returns specified range', () => { - const pkg = {}; - expect( - lernaHelper.getLernaConstraint(pkg, { - dependencies: { lerna: '1.x || >=2.5.0 || 5.0.0 - 7.2.3' }, - }) - ).toBe('1.x || >=2.5.0 || 5.0.0 - 7.2.3'); - }); - - it('returns latest if no lerna dep is specified', () => { - const pkg = {}; - expect(lernaHelper.getLernaConstraint(pkg, {})).toBeNull(); - }); - - it('returns latest if pkg has no deps at all', () => { - const pkg = {}; - expect(lernaHelper.getLernaConstraint(pkg, {})).toBeNull(); - }); - - it('returns latest if specified lerna version is not a valid semVer range', () => { - const pkg = {}; - expect( - lernaHelper.getLernaConstraint(pkg, { engines: { lerna: '[a.b.c;' } }) - ).toBeNull(); - }); - }); -}); diff --git a/lib/modules/manager/npm/post-update/lerna.ts b/lib/modules/manager/npm/post-update/lerna.ts deleted file mode 100644 index 89e825e0daf69e..00000000000000 --- a/lib/modules/manager/npm/post-update/lerna.ts +++ /dev/null @@ -1,154 +0,0 @@ -import is from '@sindresorhus/is'; -import semver from 'semver'; -import upath from 'upath'; -import { GlobalConfig } from '../../../../config/global'; -import { TEMPORARY_ERROR } from '../../../../constants/error-messages'; -import { logger } from '../../../../logger'; -import { exec } from '../../../../util/exec'; -import type { - ExecOptions, - ExtraEnv, - ToolConstraint, -} from '../../../../util/exec/types'; -import type { - PackageFile, - PackageFileContent, - PostUpdateConfig, -} from '../../types'; -import type { PackageJsonSchema } from '../schema'; -import type { NpmManagerData } from '../types'; -import { getNodeToolConstraint } from './node-version'; -import type { GenerateLockFileResult } from './types'; -import { getPackageManagerVersion, lazyLoadPackageJson } from './utils'; - -// Exported for testability -export function getLernaConstraint( - lernaPackageFile: Partial>, - lazyPkgJson: PackageJsonSchema -): string | null { - const constraint = - lazyPkgJson.dependencies?.lerna ?? lazyPkgJson.devDependencies?.lerna; - if (!constraint || !semver.validRange(constraint)) { - logger.warn( - // TODO: types (#22198) - `Could not detect lerna version in ${lernaPackageFile.packageFile}, using 'latest'` - ); - return null; - } - return constraint; -} - -export async function generateLockFiles( - lernaPackageFile: Partial>, - lockFileDir: string, - config: PostUpdateConfig, - env: NodeJS.ProcessEnv, - skipInstalls?: boolean | null -): Promise { - const lernaClient = lernaPackageFile.managerData?.lernaClient; - if (!is.nonEmptyString(lernaClient)) { - logger.warn('No lernaClient specified - returning'); - return { error: false }; - } - logger.debug(`Spawning lerna with ${lernaClient} to create lock files`); - - const cmd: string[] = []; - let cmdOptions = ''; - try { - const lazyPgkJson = lazyLoadPackageJson(lockFileDir); - const toolConstraints: ToolConstraint[] = [ - await getNodeToolConstraint(config, [], lockFileDir, lazyPgkJson), - ]; - if (lernaClient === 'yarn') { - const yarnTool: ToolConstraint = { - toolName: 'yarn', - constraint: '^1.22.18', // needs to be a v1 yarn, otherwise v2 will be installed - }; - const yarnCompatibility = - config.constraints?.yarn ?? - getPackageManagerVersion('yarn', await lazyPgkJson.getValue()); - if (semver.validRange(yarnCompatibility)) { - yarnTool.constraint = yarnCompatibility; - } - toolConstraints.push(yarnTool); - if (skipInstalls !== false) { - // The following change causes Yarn 1.x to exit gracefully after updating the lock file but without installing node_modules - yarnTool.toolName = 'yarn-slim'; - } - cmdOptions = '--ignore-scripts --ignore-engines --ignore-platform'; - } else if (lernaClient === 'npm') { - const npmTool: ToolConstraint = { toolName: 'npm' }; - const npmCompatibility = - config.constraints?.npm ?? - getPackageManagerVersion('npm', await lazyPgkJson.getValue()); - if (semver.validRange(npmCompatibility)) { - npmTool.constraint = npmCompatibility; - } - toolConstraints.push(npmTool); - cmdOptions = '--ignore-scripts --no-audit'; - if (skipInstalls !== false) { - cmdOptions += ' --package-lock-only'; - } - } else { - logger.warn({ lernaClient }, 'Unknown lernaClient'); - return { error: false }; - } - let lernaCommand = `lerna bootstrap --no-ci --ignore-scripts -- `; - if (GlobalConfig.get('allowScripts') && !config.ignoreScripts) { - cmdOptions = cmdOptions.replace('--ignore-scripts ', ''); - lernaCommand = lernaCommand.replace('--ignore-scripts ', ''); - } - lernaCommand += cmdOptions; - const extraEnv: ExtraEnv = { - NPM_CONFIG_CACHE: env.NPM_CONFIG_CACHE, - npm_config_store: env.npm_config_store, - }; - const execOptions: ExecOptions = { - cwdFile: upath.join(lockFileDir, 'package.json'), - extraEnv, - docker: {}, - toolConstraints, - }; - // istanbul ignore if - if (GlobalConfig.get('exposeAllEnv')) { - extraEnv.NPM_AUTH = env.NPM_AUTH; - extraEnv.NPM_EMAIL = env.NPM_EMAIL; - } - const lernaConstraint = - config.constraints?.lerna ?? - getLernaConstraint(lernaPackageFile, await lazyPgkJson.getValue()); - if ( - !is.string(lernaConstraint) || - (semver.valid(lernaConstraint) && - semver.gte(lernaConstraint, '7.0.0')) === true || - (semver.validRange(lernaConstraint) && - (semver.satisfies('7.0.0', lernaConstraint) || - semver.satisfies('7.999.999', lernaConstraint))) - ) { - logger.debug('Skipping lerna bootstrap for lerna >= 7.0.0'); - cmd.push(`${lernaClient} install ${cmdOptions}`); - } else { - logger.debug(`Using lerna version ${lernaConstraint}`); - toolConstraints.push({ toolName: 'lerna', constraint: lernaConstraint }); - cmd.push('lerna info || echo "Ignoring lerna info failure"'); - cmd.push(`${lernaClient} install ${cmdOptions}`); - cmd.push(lernaCommand); - } - await exec(cmd, execOptions); - } catch (err) /* istanbul ignore next */ { - if (err.message === TEMPORARY_ERROR) { - throw err; - } - logger.debug( - { - cmd, - err, - type: 'lerna', - lernaClient, - }, - 'lock file error' - ); - return { error: true, stderr: err.stderr }; - } - return { error: false }; -} diff --git a/lib/modules/manager/npm/post-update/types.ts b/lib/modules/manager/npm/post-update/types.ts index 58e687d48c9dc2..ed00f0967ffcd7 100644 --- a/lib/modules/manager/npm/post-update/types.ts +++ b/lib/modules/manager/npm/post-update/types.ts @@ -6,7 +6,6 @@ export interface DetermineLockFileDirsResult { yarnLockDirs: string[]; npmLockDirs: string[]; pnpmShrinkwrapDirs: string[]; - lernaJsonFiles: string[]; } export interface AdditionalPackageFiles { diff --git a/lib/modules/manager/npm/types.ts b/lib/modules/manager/npm/types.ts index 526afafbf17382..90cd5c91fa1e8a 100644 --- a/lib/modules/manager/npm/types.ts +++ b/lib/modules/manager/npm/types.ts @@ -81,9 +81,6 @@ export interface NpmLockFiles { export interface NpmManagerData extends NpmLockFiles, Record { hasPackageManager?: boolean; - lernaClient?: string; - lernaJsonFile?: string; - lernaPackages?: string[]; packageJsonName?: string; parents?: string[]; yarnZeroInstall?: boolean; diff --git a/lib/util/exec/containerbase.ts b/lib/util/exec/containerbase.ts index c643536b3df27f..e8528aaadca01f 100644 --- a/lib/util/exec/containerbase.ts +++ b/lib/util/exec/containerbase.ts @@ -110,11 +110,6 @@ const allToolConfig: Record = { extractVersion: '^kustomize/v(?.*)$', versioning: semverVersioningId, }, - lerna: { - datasource: 'npm', - packageName: 'lerna', - versioning: npmVersioningId, - }, maven: { datasource: 'maven', packageName: 'org.apache.maven:maven', diff --git a/lib/workers/repository/update/branch/lock-files/index.spec.ts b/lib/workers/repository/update/branch/lock-files/index.spec.ts index a5c3ea93a1b326..509b5f4609dbcc 100644 --- a/lib/workers/repository/update/branch/lock-files/index.spec.ts +++ b/lib/workers/repository/update/branch/lock-files/index.spec.ts @@ -1,7 +1,6 @@ import { fs, git, mocked } from '../../../../../../test/util'; import { GlobalConfig } from '../../../../../config/global'; import * as lockFiles from '../../../../../modules/manager/npm/post-update'; -import * as lerna from '../../../../../modules/manager/npm/post-update/lerna'; import * as npm from '../../../../../modules/manager/npm/post-update/npm'; import * as pnpm from '../../../../../modules/manager/npm/post-update/pnpm'; import * as yarn from '../../../../../modules/manager/npm/post-update/yarn'; @@ -89,7 +88,6 @@ describe('workers/repository/update/branch/lock-files/index', () => { jest.spyOn(pnpm, 'generateLockFile').mockResolvedValueOnce({ lockFile: 'some lock file contents', }); - jest.spyOn(lerna, 'generateLockFiles'); jest.spyOn(lockFiles, 'determineLockFileDirs'); });