From e765e72e7cfe8a2d3d4bd00055eafd7aada34f2c Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Mon, 15 May 2023 20:03:31 +0200 Subject: [PATCH] feat(yarn): handle yarn 3 lock file for updateLockedDependency (#21966) Co-authored-by: Michael Kriese --- .../yarn-lock/__fixtures__/3.yarn.lock | 49 +++++++++-- .../yarn-lock/get-locked.spec.ts | 41 ++------- .../locked-dependency/yarn-lock/get-locked.ts | 83 +++++++++++++++---- 3 files changed, 116 insertions(+), 57 deletions(-) diff --git a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/__fixtures__/3.yarn.lock b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/__fixtures__/3.yarn.lock index 15ed204e76c285..370eb3df7bd6a8 100644 --- a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/__fixtures__/3.yarn.lock +++ b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/__fixtures__/3.yarn.lock @@ -1,11 +1,46 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! +__metadata: + version: 7 + cacheKey: 9 -"@actions/core@1.6.0", "@actions/core@^1.2.0", "@actions/core@^1.2.6": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.6.0.tgz#0568e47039bfb6a9170393a73f3b7eb3b22462cb" - integrity sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw== +"@actions/core@npm:^1.2.6": + version: 1.2.6 + resolution: "@actions/core@npm:1.2.6" + checksum: 034e57fcb5f944d5fb0ef55be1b212dd88e23d1a50aaffda874cb94e8f4bfa633a66f108f26e81a7cce287cd2b349aa88c97d2023135c8879495326db37a7feb + languageName: node + linkType: hard + +"@algolia/autocomplete-core@npm:1.7.1": + version: 1.7.1 + resolution: "@algolia/autocomplete-core@npm:1.7.1" + dependencies: + "@algolia/autocomplete-shared": "npm:1.7.1" + checksum: db772275618c3844b411a66195403f2b118758b52b94fd292fef9569b3e1d90ee1bfdee7473a90e114e8ee58e867fa197f011721ebc704ed3cd253b2edcc78e4 + languageName: node + linkType: hard + +"@algolia/autocomplete-preset-algolia@npm:1.7.1": + version: 1.7.1 + resolution: "@algolia/autocomplete-preset-algolia@npm:1.7.1" dependencies: - "@actions/http-client" "^1.0.11" + "@algolia/autocomplete-shared": "npm:1.7.1" + peerDependencies: + "@algolia/client-search": ^4.9.1 + algoliasearch: ^4.9.1 + checksum: b110379b1bf49a230a35cbf167c858d480f196480474ef954a64e822c46e5e2a39eae2440a2c1c5f6beb96f51f8a5c75ba05586defa611a4cf32b4208ad29ce2 + languageName: node + linkType: hard +"@strictsoftware/typedoc-plugin-monorepo@patch:@strictsoftware/typedoc-plugin-monorepo@^0.2.2#./.patches/@strictsoftware/typedoc-plugin-monorepo.patch::locator=%40yarnpkg%2Fgatsby%40workspace%3Apackages%2Fgatsby": + version: 0.2.2 + resolution: "@strictsoftware/typedoc-plugin-monorepo@patch:@strictsoftware/typedoc-plugin-monorepo@npm%3A0.2.2#./.patches/@strictsoftware/typedoc-plugin-monorepo.patch::version=0.2.2&hash=dc07b1&locator=%40yarnpkg%2Fgatsby%40workspace%3Apackages%2Fgatsby" + dependencies: + highlight.js: "npm:^9.15.6" + marked: "npm:^0.8.0" + peerDependencies: + typedoc: ">=0.8 <1.0" + checksum: 25b9eb5ad9e5028c7cf320ab6c458af535ed2ec3e1bdfd7d71daf1f8cb33ae684823064a889a63695db4686c2830bd118f792282b82d31e579c4a1e495ce473a + languageName: node + linkType: hard diff --git a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.spec.ts b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.spec.ts index 3d6e8aa598037a..0995f696e188db 100644 --- a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.spec.ts +++ b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.spec.ts @@ -26,46 +26,19 @@ describe('modules/manager/npm/update/locked-dependency/yarn-lock/get-locked', () }); it('finds scoped', () => { - expect(getLockedDependencies(yarnLock3, '@actions/core', '1.6.0')) + expect(getLockedDependencies(yarnLock3, '@actions/core', '1.2.6')) .toMatchInlineSnapshot(` [ - { - "constraint": "1.6.0", - "depName": "@actions/core", - "depNameConstraint": "@actions/core@1.6.0", - "entry": { - "dependencies": { - "@actions/http-client": "^1.0.11", - }, - "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", - "resolved": "https://registry.yarnpkg.com/@actions/core/-/core-1.6.0.tgz#0568e47039bfb6a9170393a73f3b7eb3b22462cb", - "version": "1.6.0", - }, - }, - { - "constraint": "^1.2.0", - "depName": "@actions/core", - "depNameConstraint": "@actions/core@^1.2.0", - "entry": { - "dependencies": { - "@actions/http-client": "^1.0.11", - }, - "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", - "resolved": "https://registry.yarnpkg.com/@actions/core/-/core-1.6.0.tgz#0568e47039bfb6a9170393a73f3b7eb3b22462cb", - "version": "1.6.0", - }, - }, { "constraint": "^1.2.6", "depName": "@actions/core", - "depNameConstraint": "@actions/core@^1.2.6", + "depNameConstraint": "@actions/core@npm:^1.2.6", "entry": { - "dependencies": { - "@actions/http-client": "^1.0.11", - }, - "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", - "resolved": "https://registry.yarnpkg.com/@actions/core/-/core-1.6.0.tgz#0568e47039bfb6a9170393a73f3b7eb3b22462cb", - "version": "1.6.0", + "checksum": "034e57fcb5f944d5fb0ef55be1b212dd88e23d1a50aaffda874cb94e8f4bfa633a66f108f26e81a7cce287cd2b349aa88c97d2023135c8879495326db37a7feb", + "languageName": "node", + "linkType": "hard", + "resolution": "@actions/core@npm:1.2.6", + "version": "1.2.6", }, }, ] diff --git a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.ts b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.ts index 84da024089bd32..7f4f5fa73db189 100644 --- a/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.ts +++ b/lib/modules/manager/npm/update/locked-dependency/yarn-lock/get-locked.ts @@ -1,8 +1,26 @@ import { logger } from '../../../../../../logger'; import type { YarnLock, YarnLockEntrySummary } from './types'; -// Finds matching dependencies withing a package lock file of sub-entry -export function getLockedDependencies( +export function parseEntry(depNameConstraint: string): { + entryName: string; + constraint: string; +} | null { + let entryName: string; + let constraint: string; + const split = depNameConstraint.split('@'); + if (split.length === 2) { + [entryName, constraint] = split; + } else if (split.length === 3) { + entryName = '@' + split[1]; + constraint = split[2]; + } else { + logger.debug({ depNameConstraint }, 'Unexpected depNameConstraint'); + return null; + } + return { entryName, constraint }; +} + +export function getYarn1LockedDependencies( yarnLock: YarnLock, depName: string, currentVersion: string @@ -10,22 +28,12 @@ export function getLockedDependencies( const res: YarnLockEntrySummary[] = []; try { for (const [depNameConstraint, entry] of Object.entries(yarnLock)) { - let entryName: string; - let constraint: string; - const split = depNameConstraint.split('@'); - // istanbul ignore else - if (split.length === 2) { - [entryName, constraint] = split; - } else if (split.length === 3) { - entryName = '@' + split[1]; - constraint = split[2]; - } else { - logger.debug( - { depNameConstraint, entry }, - 'Unexpected depNameConstraint' - ); + const parsed = parseEntry(depNameConstraint); + // istanbul ignore if + if (!parsed) { continue; } + const { entryName, constraint } = parsed; if (entryName === depName && entry?.version === currentVersion) { res.push({ entry, depNameConstraint, depName, constraint }); } @@ -35,3 +43,46 @@ export function getLockedDependencies( } return res; } + +export function getYarn2LockedDependencies( + yarnLock: YarnLock, + depName: string, + currentVersion: string +): YarnLockEntrySummary[] { + const res: YarnLockEntrySummary[] = []; + try { + for (const [fullConstraint, entry] of Object.entries(yarnLock)) { + if (fullConstraint === '__metadata') { + continue; + } + for (const subConstraint of fullConstraint.split(', ')) { + const depNameConstraint = subConstraint; + const parsed = parseEntry(depNameConstraint); + // istanbul ignore if + if (!parsed) { + continue; + } + const { entryName } = parsed; + const constraint = parsed.constraint.replace(/^npm:/, ''); + if (entryName === depName && entry?.version === currentVersion) { + res.push({ entry, depNameConstraint, depName, constraint }); + } + } + } + } catch (err) /* istanbul ignore next */ { + logger.warn({ err }, 'getLockedDependencies() error'); + } + return res; +} + +// Finds matching dependencies withing a package lock file of sub-entry +export function getLockedDependencies( + yarnLock: YarnLock, + depName: string, + currentVersion: string +): YarnLockEntrySummary[] { + if ('__metadata' in yarnLock) { + return getYarn2LockedDependencies(yarnLock, depName, currentVersion); + } + return getYarn1LockedDependencies(yarnLock, depName, currentVersion); +}