diff --git a/lib/manager/npm/post-update/yarn.spec.ts b/lib/manager/npm/post-update/yarn.spec.ts index 8383acc0ba01eb03a5a0dc7e74995c486070d4fc..9f6d1ec8f93acda6287bb329021164bc61a9ee7a 100644 --- a/lib/manager/npm/post-update/yarn.spec.ts +++ b/lib/manager/npm/post-update/yarn.spec.ts @@ -223,6 +223,12 @@ describe('manager/npm/post-update/yarn', () => { describe('checkYarnrc()', () => { it('returns offline mirror and yarn path', async () => { + fs.exists.mockImplementation((path) => { + if (path === './.yarn/cli.js') { + return new Promise<boolean>((resolve) => resolve(true)); + } + return new Promise<boolean>((resolve) => resolve(false)); + }); fs.readFile.mockImplementation((filename, encoding) => { if (filename.endsWith('.yarnrc')) { return new Promise<string>((resolve) => @@ -238,6 +244,12 @@ describe('manager/npm/post-update/yarn', () => { }); it('returns no offline mirror and unquoted yarn path', async () => { + fs.exists.mockImplementation((path) => { + if (path === './.yarn/cli.js') { + return new Promise<boolean>((resolve) => resolve(true)); + } + return new Promise<boolean>((resolve) => resolve(false)); + }); fs.readFile.mockImplementation((filename, encoding) => { if (filename.endsWith('.yarnrc')) { return new Promise<string>((resolve) => @@ -249,5 +261,27 @@ describe('manager/npm/post-update/yarn', () => { // FIXME: explicit assert condition expect(await _yarnHelper.checkYarnrc('/tmp/renovate')).toMatchSnapshot(); }); + + it('returns offline mirror and no yarn path for non-existant yarn-path binary', async () => { + let yarnrcContents = 'yarn-path ./.yarn/cli.js\n'; + fs.writeFile.mockImplementation((filename, fileContents) => { + if (filename.endsWith('.yarnrc')) { + yarnrcContents = fileContents; + } + return new Promise<void>((resolve) => resolve()); + }); + fs.readFile.mockImplementation((filename, encoding) => { + if (filename.endsWith('.yarnrc')) { + return new Promise<string>((resolve) => resolve(yarnrcContents)); + } + return new Promise<string>((resolve) => resolve('')); + }); + const { offlineMirror, yarnPath } = await _yarnHelper.checkYarnrc( + '/tmp/renovate' + ); + expect(offlineMirror).toBeFalse(); + expect(yarnPath).toBeNull(); + expect(yarnrcContents).not.toContain('yarn-path'); + }); }); }); diff --git a/lib/manager/npm/post-update/yarn.ts b/lib/manager/npm/post-update/yarn.ts index d6a517b1a3e5a0ff4db8922b47891da3dfbd3329..24120d57241087ef50cac7ba44f13052b179e2b0 100644 --- a/lib/manager/npm/post-update/yarn.ts +++ b/lib/manager/npm/post-update/yarn.ts @@ -11,7 +11,7 @@ import { id as npmId } from '../../../datasource/npm'; import { logger } from '../../../logger'; import { ExternalHostError } from '../../../types/errors/external-host-error'; import { ExecOptions, exec } from '../../../util/exec'; -import { readFile, remove } from '../../../util/fs'; +import { exists, readFile, remove, writeFile } from '../../../util/fs'; import { regEx } from '../../../util/regex'; import type { PostUpdateConfig, Upgrade } from '../../types'; import { getNodeConstraint } from './node-version'; @@ -35,6 +35,15 @@ export async function checkYarnrc( if (pathLine) { yarnPath = pathLine.replace(regEx(/^yarn-path\s+"?(.+?)"?$/), '$1'); } + const yarnBinaryExists = await exists(yarnPath); + if (!yarnBinaryExists) { + const scrubbedYarnrc = yarnrc.replace( + regEx(/^yarn-path\s+"?.+?"?$/gm), + '' + ); + await writeFile(`${cwd}/.yarnrc`, scrubbedYarnrc); + yarnPath = null; + } } } catch (err) /* istanbul ignore next */ { // not found