From 68191f1ccf525db08dbc89ec9689ab7b107c0c44 Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@arkins.net> Date: Sun, 7 Mar 2021 17:38:42 +0100 Subject: [PATCH] feat(yarn): optimize yarn binary when binarySource=docker (#9013) --- .../__snapshots__/yarn.spec.ts.snap | 14 +++++++ lib/manager/npm/post-update/lerna.ts | 4 +- lib/manager/npm/post-update/yarn.spec.ts | 30 +++++++++++++- lib/manager/npm/post-update/yarn.ts | 41 ++++++++++++------- 4 files changed, 72 insertions(+), 17 deletions(-) diff --git a/lib/manager/npm/post-update/__snapshots__/yarn.spec.ts.snap b/lib/manager/npm/post-update/__snapshots__/yarn.spec.ts.snap index e6f1928aff..67beb2e582 100644 --- a/lib/manager/npm/post-update/__snapshots__/yarn.spec.ts.snap +++ b/lib/manager/npm/post-update/__snapshots__/yarn.spec.ts.snap @@ -24,6 +24,20 @@ Array [ ] `; +exports[`manager/npm/post-update/yarn checkYarnrc() returns no offline mirror and unquoted yarn path 1`] = ` +Object { + "offlineMirror": false, + "yarnPath": "./.yarn/cli.js", +} +`; + +exports[`manager/npm/post-update/yarn checkYarnrc() returns offline mirror and yarn path 1`] = ` +Object { + "offlineMirror": true, + "yarnPath": "./.yarn/cli.js", +} +`; + exports[`manager/npm/post-update/yarn generates lock files using yarn v1.22.0 1`] = ` Array [ Object { diff --git a/lib/manager/npm/post-update/lerna.ts b/lib/manager/npm/post-update/lerna.ts index 3517e25afc..4e15adbf78 100644 --- a/lib/manager/npm/post-update/lerna.ts +++ b/lib/manager/npm/post-update/lerna.ts @@ -7,7 +7,7 @@ import { logger } from '../../../logger'; import { ExecOptions, exec } from '../../../util/exec'; import type { PackageFile, PostUpdateConfig } from '../../types'; import { getNodeConstraint } from './node-version'; -import { optimizeCommand } from './yarn'; +import { getOptimizeCommand } from './yarn'; export interface GenerateLockFileResult { error?: boolean; @@ -53,7 +53,7 @@ export async function generateLockFiles( } preCommands.push(installYarn); if (skipInstalls !== false) { - preCommands.push(optimizeCommand); + preCommands.push(getOptimizeCommand()); } cmdOptions = '--ignore-scripts --ignore-engines --ignore-platform'; } else if (lernaClient === 'npm') { diff --git a/lib/manager/npm/post-update/yarn.spec.ts b/lib/manager/npm/post-update/yarn.spec.ts index 5b2dd6afd5..0274362190 100644 --- a/lib/manager/npm/post-update/yarn.spec.ts +++ b/lib/manager/npm/post-update/yarn.spec.ts @@ -45,7 +45,9 @@ describe(getName(__filename), () => { }); fs.readFile.mockImplementation((filename, encoding) => { if (filename.endsWith('.yarnrc')) { - return new Promise<string>((resolve) => resolve(null)); + return new Promise<string>((resolve) => + resolve('yarn-path ./.yarn/cli.js\n') + ); } return new Promise<string>((resolve) => resolve('package-lock-contents') @@ -167,4 +169,30 @@ describe(getName(__filename), () => { expect(res.lockFile).not.toBeDefined(); expect(fixSnapshots(execSnapshots)).toMatchSnapshot(); }); + describe('checkYarnrc()', () => { + it('returns offline mirror and yarn path', async () => { + fs.readFile.mockImplementation((filename, encoding) => { + if (filename.endsWith('.yarnrc')) { + return new Promise<string>((resolve) => + resolve( + 'yarn-offline-mirror "./packages-cache"\nyarn-path "./.yarn/cli.js"\n' + ) + ); + } + return new Promise<string>((resolve) => resolve('')); + }); + expect(await _yarnHelper.checkYarnrc('/tmp/renovate')).toMatchSnapshot(); + }); + it('returns no offline mirror and unquoted yarn path', async () => { + fs.readFile.mockImplementation((filename, encoding) => { + if (filename.endsWith('.yarnrc')) { + return new Promise<string>((resolve) => + resolve('yarn-path ./.yarn/cli.js\n') + ); + } + return new Promise<string>((resolve) => resolve('')); + }); + expect(await _yarnHelper.checkYarnrc('/tmp/renovate')).toMatchSnapshot(); + }); + }); }); diff --git a/lib/manager/npm/post-update/yarn.ts b/lib/manager/npm/post-update/yarn.ts index 6a1b8e3dbd..861759cff4 100644 --- a/lib/manager/npm/post-update/yarn.ts +++ b/lib/manager/npm/post-update/yarn.ts @@ -21,25 +21,36 @@ export interface GenerateLockFileResult { stderr?: string; } -export async function hasYarnOfflineMirror(cwd: string): Promise<boolean> { +export async function checkYarnrc( + cwd: string +): Promise<{ offlineMirror: boolean; yarnPath: string | null }> { + let offlineMirror = false; + let yarnPath: string = null; try { const yarnrc = await readFile(`${cwd}/.yarnrc`, 'utf8'); if (is.string(yarnrc)) { const mirrorLine = yarnrc .split('\n') .find((line) => line.startsWith('yarn-offline-mirror ')); - if (mirrorLine) { - return true; + offlineMirror = !!mirrorLine; + const pathLine = yarnrc + .split('\n') + .find((line) => line.startsWith('yarn-path ')); + if (pathLine) { + yarnPath = pathLine.replace(/^yarn-path\s+"?(.+?)"?$/, '$1'); } } } catch (err) /* istanbul ignore next */ { // not found } - return false; + return { offlineMirror, yarnPath }; } -export const optimizeCommand = - "sed -i 's/ steps,/ steps.slice(0,1),/' /home/ubuntu/.npm-global/lib/node_modules/yarn/lib/cli.js"; +export function getOptimizeCommand( + fileName = '/home/ubuntu/.npm-global/lib/node_modules/yarn/lib/cli.js' +): string { + return `sed -i 's/ steps,/ steps.slice(0,1),/' ${quote(fileName)}`; +} export async function generateLockFile( cwd: string, @@ -71,14 +82,16 @@ export async function generateLockFile( CI: 'true', }; - if ( - isYarn1 && - config.skipInstalls !== false && - (await hasYarnOfflineMirror(cwd)) === false - ) { - logger.debug('Updating yarn.lock only - skipping node_modules'); - // The following change causes Yarn 1.x to exit gracefully after updating the lock file but without installing node_modules - preCommands.push(optimizeCommand); + if (isYarn1 && config.skipInstalls !== false) { + const { offlineMirror, yarnPath } = await checkYarnrc(cwd); + if (!offlineMirror) { + logger.debug('Updating yarn.lock only - skipping node_modules'); + // The following change causes Yarn 1.x to exit gracefully after updating the lock file but without installing node_modules + preCommands.push(getOptimizeCommand()); + if (yarnPath) { + preCommands.push(getOptimizeCommand(yarnPath) + ' || true'); + } + } } const commands = []; let cmdOptions = ''; -- GitLab