diff --git a/lib/manager/npm/__fixtures__/yarn2.2/package.json b/lib/manager/npm/__fixtures__/yarn2.2/package.json new file mode 100644 index 0000000000000000000000000000000000000000..fe06a5d1e852eee8f38af265e9be12e704feb7e5 --- /dev/null +++ b/lib/manager/npm/__fixtures__/yarn2.2/package.json @@ -0,0 +1,15 @@ +{ + "name": "yarn2", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "chalk": "^2.4.1" + } +} diff --git a/lib/manager/npm/__fixtures__/yarn2.2/yarn.lock b/lib/manager/npm/__fixtures__/yarn2.2/yarn.lock new file mode 100644 index 0000000000000000000000000000000000000000..c9ae3cf3631972ffac0a41f52ac485eea19cf4d5 --- /dev/null +++ b/lib/manager/npm/__fixtures__/yarn2.2/yarn.lock @@ -0,0 +1,73 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 4 + cacheKey: 6 + +"ansi-styles@npm:^3.2.1": + version: 3.2.1 + resolution: "ansi-styles@npm:3.2.1" + dependencies: + color-convert: ^1.9.0 + checksum: 456e1c23d9277512a47718da75e7fbb0a5ee215ef893c2f76d6b3efe8fceabc861121b80b0362146f5f995d21a1633f05a19bbf6283ae66ac11dc3b9c0bed779 + languageName: node + linkType: hard + +"chalk@npm:^2.4.1": + version: 2.4.2 + resolution: "chalk@npm:2.4.2" + dependencies: + ansi-styles: ^3.2.1 + escape-string-regexp: ^1.0.5 + supports-color: ^5.3.0 + checksum: 22c7b7b5bc761c882bb6516454a1a671923f1c53ff972860065aa0b28a195f230163c1d46ee88bcc7a03e5539177d896457d8bc727de7f244c6e87032743038e + languageName: node + linkType: hard + +"color-convert@npm:^1.9.0": + version: 1.9.3 + resolution: "color-convert@npm:1.9.3" + dependencies: + color-name: 1.1.3 + checksum: 5f244daa3d1fe1f216d48878c550465067d15268688308554e613b7640a068f96588096d51f0b98b68f15d6ff6bb8ad24e172582ac8c0ad43fa4d3da60fd1b79 + languageName: node + linkType: hard + +"color-name@npm:1.1.3": + version: 1.1.3 + resolution: "color-name@npm:1.1.3" + checksum: d8b91bb90aefc05b6ff568cf8889566dcc6269824df6f3c9b8ca842b18d7f4d089c07dc166808d33f22092d4a79167aa56a96a5ff0d21efab548bf44614db43b + languageName: node + linkType: hard + +"escape-string-regexp@npm:^1.0.5": + version: 1.0.5 + resolution: "escape-string-regexp@npm:1.0.5" + checksum: f9484b8b4c8827d816e0fd905c25ed4b561376a9c220e1430403ea84619bf680c76a883a48cff8b8e091daf55d6a497e37479f9787b9f15f3c421b6054289744 + languageName: node + linkType: hard + +"has-flag@npm:^3.0.0": + version: 3.0.0 + resolution: "has-flag@npm:3.0.0" + checksum: 63aade480d27aeedb3b5b63a2e069d47d0006bf182338d662e7941cdc024e68a28418e0efa8dc5df30db9c4ee2407f39e6ea3f16cfbc6b83848b450826a28aa0 + languageName: node + linkType: hard + +"supports-color@npm:^5.3.0": + version: 5.5.0 + resolution: "supports-color@npm:5.5.0" + dependencies: + has-flag: ^3.0.0 + checksum: edacee6425498440744c418be94b0660181aad2a1828bcf2be85c42bd385da2fd8b2b358d9b62b0c5b03ff5cd3e992458d7b8f879d9fb42f2201fe05a4848a29 + languageName: node + linkType: hard + +"yarn2@workspace:.": + version: 0.0.0-use.local + resolution: "yarn2@workspace:." + dependencies: + chalk: ^2.4.1 + languageName: unknown + linkType: soft diff --git a/lib/manager/npm/extract/__snapshots__/locked-versions.spec.ts.snap b/lib/manager/npm/extract/__snapshots__/locked-versions.spec.ts.snap index d1c684366e4a49b1f671ca77d12bf0ae0ba53ed0..31c43a6bc787507c69fa33530a999e61791baeec 100644 --- a/lib/manager/npm/extract/__snapshots__/locked-versions.spec.ts.snap +++ b/lib/manager/npm/extract/__snapshots__/locked-versions.spec.ts.snap @@ -83,3 +83,27 @@ Array [ }, ] `; + +exports[`manager/npm/extract/locked-versions .getLockedVersions() uses yarn.lock with yarn v2.2.0 1`] = ` +Array [ + Object { + "compatibility": Object { + "yarn": ">= 2.2.0", + }, + "deps": Array [ + Object { + "currentValue": "1.0.0", + "depName": "a", + "lockedVersion": "1.0.0", + }, + Object { + "currentValue": "2.0.0", + "depName": "b", + "lockedVersion": "2.0.0", + }, + ], + "npmLock": "package-lock.json", + "yarnLock": "yarn.lock", + }, +] +`; diff --git a/lib/manager/npm/extract/__snapshots__/yarn.spec.ts.snap b/lib/manager/npm/extract/__snapshots__/yarn.spec.ts.snap index da4f1275fe59231e23dcc32ebe7d98b7abebb23f..048549ec1b2d4a02d11aca324f4f37c70640029d 100644 --- a/lib/manager/npm/extract/__snapshots__/yarn.spec.ts.snap +++ b/lib/manager/npm/extract/__snapshots__/yarn.spec.ts.snap @@ -24,3 +24,16 @@ Object { "yarn2@.": "0.0.0-use.local", } `; + +exports[`manager/npm/extract/yarn .getYarnLock() extracts yarn 2 cache version 1`] = ` +Object { + "ansi-styles@^3.2.1": "3.2.1", + "chalk@^2.4.1": "2.4.2", + "color-convert@^1.9.0": "1.9.3", + "color-name@1.1.3": "1.1.3", + "escape-string-regexp@^1.0.5": "1.0.5", + "has-flag@^3.0.0": "3.0.0", + "supports-color@^5.3.0": "5.5.0", + "yarn2@.": "0.0.0-use.local", +} +`; diff --git a/lib/manager/npm/extract/locked-versions.spec.ts b/lib/manager/npm/extract/locked-versions.spec.ts index 9d78351766bb4179f2255994270713d2c420833b..35de12dcc7c873ceaf91fa86ad64f150d78f0b84 100644 --- a/lib/manager/npm/extract/locked-versions.spec.ts +++ b/lib/manager/npm/extract/locked-versions.spec.ts @@ -10,11 +10,12 @@ jest.mock('./yarn'); describe('manager/npm/extract/locked-versions', () => { describe('.getLockedVersions()', () => { - it.each([['1.22.0'], ['2.1.0']])( + it.each([['1.22.0'], ['2.1.0'], ['2.2.0']])( 'uses yarn.lock with yarn v%s', async (yarnVersion) => { yarn.getYarnLock.mockReturnValue({ isYarn1: yarnVersion === '1.22.0', + cacheVersion: yarnVersion === '2.2.0' ? 6 : NaN, lockedVersions: { 'a@1.0.0': '1.0.0', 'b@2.0.0': '2.0.0', diff --git a/lib/manager/npm/extract/locked-versions.ts b/lib/manager/npm/extract/locked-versions.ts index 7baab9f3a2c902a08fcaa144f622ff7e51fa450d..99c4c9edb06bed3f0b584cf3a5501f62988665d7 100644 --- a/lib/manager/npm/extract/locked-versions.ts +++ b/lib/manager/npm/extract/locked-versions.ts @@ -15,10 +15,17 @@ export async function getLockedVersions( logger.trace('Found yarnLock'); if (!lockFileCache[yarnLock]) { logger.trace('Retrieving/parsing ' + yarnLock); - const { lockedVersions, isYarn1 } = await getYarnLock(yarnLock); + const { lockedVersions, cacheVersion, isYarn1 } = await getYarnLock( + yarnLock + ); lockFileCache[yarnLock] = lockedVersions; if (!isYarn1) { - packageFile.compatibility.yarn = '>= 2.0.0'; + if (cacheVersion >= 6) { + // https://github.com/yarnpkg/berry/commit/f753790380cbda5b55d028ea84b199445129f9ba + packageFile.compatibility.yarn = '>= 2.2.0'; + } else { + packageFile.compatibility.yarn = '>= 2.0.0'; + } } } for (const dep of packageFile.deps) { diff --git a/lib/manager/npm/extract/yarn.spec.ts b/lib/manager/npm/extract/yarn.spec.ts index 63641132f1359421dd82f84fc2d88a7286779875..b94e68fb7051ab9de4a32e05b45b140dcc21b437 100644 --- a/lib/manager/npm/extract/yarn.spec.ts +++ b/lib/manager/npm/extract/yarn.spec.ts @@ -21,6 +21,7 @@ describe('manager/npm/extract/yarn', () => { fs.readLocalFile.mockResolvedValueOnce(plocktest1Lock); const res = await getYarnLock('package.json'); expect(res.isYarn1).toBe(true); + expect(res.cacheVersion).toBe(NaN); expect(res.lockedVersions).toMatchSnapshot(); expect(Object.keys(res.lockedVersions)).toHaveLength(7); }); @@ -33,6 +34,20 @@ describe('manager/npm/extract/yarn', () => { fs.readLocalFile.mockResolvedValueOnce(plocktest1Lock); const res = await getYarnLock('package.json'); expect(res.isYarn1).toBe(false); + expect(res.cacheVersion).toBe(NaN); + expect(res.lockedVersions).toMatchSnapshot(); + expect(Object.keys(res.lockedVersions)).toHaveLength(8); + }); + + it('extracts yarn 2 cache version', async () => { + const plocktest1Lock = readFileSync( + 'lib/manager/npm/__fixtures__/yarn2.2/yarn.lock', + 'utf8' + ); + fs.readLocalFile.mockResolvedValueOnce(plocktest1Lock); + const res = await getYarnLock('package.json'); + expect(res.isYarn1).toBe(false); + expect(res.cacheVersion).toBe(6); expect(res.lockedVersions).toMatchSnapshot(); expect(Object.keys(res.lockedVersions)).toHaveLength(8); }); diff --git a/lib/manager/npm/extract/yarn.ts b/lib/manager/npm/extract/yarn.ts index 0a2d138e4838af316c64805f0b40b2fe77aa7dbf..754bbffc9ac30f6a25071bea977ee52c46beae8a 100644 --- a/lib/manager/npm/extract/yarn.ts +++ b/lib/manager/npm/extract/yarn.ts @@ -5,15 +5,21 @@ import { readLocalFile } from '../../../util/fs'; export async function getYarnLock( filePath: string -): Promise<{ isYarn1: boolean; lockedVersions: Record<string, string> }> { +): Promise<{ + isYarn1: boolean; + cacheVersion: number; + lockedVersions: Record<string, string>; +}> { const yarnLockRaw = await readLocalFile(filePath, 'utf8'); try { const parsed = parseSyml(yarnLockRaw); const lockFile: Record<string, string> = {}; + let cacheVersion = NaN; for (const [key, val] of Object.entries(parsed)) { if (key === '__metadata') { // yarn 2 + cacheVersion = parseInt(val.cacheKey, 10); } else { for (const entry of key.split(', ')) { const { scope, name, range } = structUtils.parseDescriptor(entry); @@ -27,10 +33,11 @@ export async function getYarnLock( } return { isYarn1: !('__metadata' in parsed), + cacheVersion, lockedVersions: lockFile, }; } catch (err) { logger.debug({ filePath, err }, 'Warning: Exception parsing yarn.lock'); - return { isYarn1: true, lockedVersions: {} }; + return { isYarn1: true, cacheVersion: NaN, lockedVersions: {} }; } }