UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

216 lines (215 loc) • 9.38 kB
import { SYSTEM_INSUFFICIENT_DISK_SPACE } from "../../../../constants/error-messages.js"; import { getEnv } from "../../../../util/env.js"; import { newlineRegex, regEx } from "../../../../util/regex.js"; import { GlobalConfig } from "../../../../config/global.js"; import { uniqueStrings } from "../../../../util/string.js"; import { logger } from "../../../../logger/index.js"; import { ExternalHostError } from "../../../../types/errors/external-host-error.js"; import { localPathIsFile, readLocalFile, writeLocalFile } from "../../../../util/fs/index.js"; import { exec, getToolSettingsOptions } from "../../../../util/exec/index.js"; import { NpmDatasource } from "../../../datasource/npm/index.js"; import { getNodeToolConstraint } from "./node-version.js"; import { getNodeOptions, getPackageManagerVersion, lazyLoadPackageJson } from "./utils.js"; import { getYarnLock, getYarnVersionFromLock } from "../extract/yarn.js"; import { isString } from "@sindresorhus/is"; import { quote } from "shlex"; import upath from "upath"; import semver from "semver"; //#region lib/modules/manager/npm/post-update/yarn.ts async function checkYarnrc(lockFileDir) { let offlineMirror = false; let yarnPath = null; try { const yarnrc = await readLocalFile(upath.join(lockFileDir, ".yarnrc"), "utf8"); if (isString(yarnrc)) { offlineMirror = !!yarnrc.split(newlineRegex).find((line) => line.startsWith("yarn-offline-mirror ")); const pathLine = yarnrc.split(newlineRegex).find((line) => line.startsWith("yarn-path ")); if (pathLine) yarnPath = pathLine.replace(regEx(/^yarn-path\s+"?(.+?)"?$/), "$1"); if (yarnPath) yarnPath = upath.join(lockFileDir, yarnPath); const yarnBinaryExists = yarnPath ? await localPathIsFile(yarnPath) : false; let scrubbedYarnrc = yarnrc.replace("--install.pure-lockfile true", "").replace("--install.frozen-lockfile true", ""); if (!yarnBinaryExists) { scrubbedYarnrc = scrubbedYarnrc.replace(regEx(/^yarn-path\s+"?.+?"?$/gm), ""); yarnPath = null; } if (yarnrc !== scrubbedYarnrc) { logger.debug(`Writing scrubbed .yarnrc to ${lockFileDir}`); await writeLocalFile(upath.join(lockFileDir, ".yarnrc"), scrubbedYarnrc); } } } catch {} return { offlineMirror, yarnPath }; } function getOptimizeCommand(fileName) { return [ "sed", "-i", "s/ steps,/ steps.slice(0,1),/", fileName ]; } function isYarnUpdate(upgrade) { return upgrade.depType === "packageManager" && upgrade.depName === "yarn"; } async function generateLockFile(lockFileDir, env, config = {}, upgrades = []) { const lockFileName = upath.join(lockFileDir, "yarn.lock"); logger.debug(`Spawning yarn install to create ${lockFileName}`); let lockFile = null; try { const lazyPgkJson = lazyLoadPackageJson(lockFileDir); const toolConstraints = [await getNodeToolConstraint(config, upgrades, lockFileDir, lazyPgkJson)]; const yarnUpdate = upgrades.find(isYarnUpdate); const yarnCompatibility = (yarnUpdate ? yarnUpdate.newValue : config.constraints?.yarn) ?? getPackageManagerVersion("yarn", await lazyPgkJson.getValue()) ?? getYarnVersionFromLock(await getYarnLock(lockFileName)); const minYarnVersion = semver.validRange(yarnCompatibility) && semver.minVersion(yarnCompatibility); const isYarn1 = !minYarnVersion || minYarnVersion.major === 1; const isYarnDedupeAvailable = minYarnVersion && semver.gte(minYarnVersion, "2.2.0"); const isYarnModeAvailable = minYarnVersion && semver.gte(minYarnVersion, "3.0.0"); const yarnTool = { toolName: "yarn", constraint: "^1.22.18" }; const hasPackageManager = !!config.managerData?.hasPackageManager || !!upgrades[0]?.managerData?.hasPackageManager; if (!isYarn1 && hasPackageManager) toolConstraints.push({ toolName: "corepack", constraint: config.constraints?.corepack }); else { toolConstraints.push(yarnTool); if (isYarn1 && minYarnVersion) yarnTool.constraint = yarnCompatibility; } const extraEnv = { NPM_CONFIG_CACHE: env.NPM_CONFIG_CACHE, npm_config_store: env.npm_config_store, CI: "true" }; const commands = []; let cmdOptions = ""; if (config.skipInstalls !== false) { if (isYarn1) { const { offlineMirror, yarnPath } = await checkYarnrc(lockFileDir); // v8 ignore else -- TODO: add test #40625 if (!offlineMirror) { logger.debug("Updating yarn.lock only - skipping node_modules"); yarnTool.toolName = "yarn-slim"; if (yarnPath) commands.push({ command: getOptimizeCommand(yarnPath), ignoreFailure: true }); } } else if (isYarnModeAvailable) cmdOptions += " --mode=update-lockfile"; } if (isYarn1) { cmdOptions += " --ignore-engines --ignore-platform --network-timeout 100000"; extraEnv.YARN_CACHE_FOLDER = env.YARN_CACHE_FOLDER; } else { extraEnv.YARN_ENABLE_IMMUTABLE_INSTALLS = "false"; extraEnv.YARN_HTTP_TIMEOUT = "100000"; extraEnv.YARN_GLOBAL_FOLDER = env.YARN_GLOBAL_FOLDER; if (!config.managerData?.yarnZeroInstall) { logger.debug("Enabling global cache as zero-install is not detected"); extraEnv.YARN_ENABLE_GLOBAL_CACHE = "1"; } } if (!GlobalConfig.get("allowScripts") || config.ignoreScripts) if (isYarn1) cmdOptions += " --ignore-scripts"; else if (isYarnModeAvailable) { if (config.skipInstalls === false) cmdOptions += " --mode=skip-build"; } else extraEnv.YARN_ENABLE_SCRIPTS = "0"; const { nodeMaxMemory } = getToolSettingsOptions(config.toolSettings); if (nodeMaxMemory) extraEnv.NODE_OPTIONS = getNodeOptions(nodeMaxMemory); const execOptions = { cwdFile: lockFileName, extraEnv, docker: {}, toolConstraints }; /* v8 ignore next 4 -- needs test */ if (GlobalConfig.get("exposeAllEnv")) { extraEnv.NPM_AUTH = env.NPM_AUTH; extraEnv.NPM_EMAIL = env.NPM_EMAIL; } if (yarnUpdate && !isYarn1) { logger.debug("Updating Yarn binary"); commands.push(`yarn set version ${quote(yarnUpdate.newValue)}`); } const allEnv = getEnv(); if (allEnv.RENOVATE_X_YARN_PROXY) { // v8 ignore else -- TODO: add test #40625 if (allEnv.HTTP_PROXY && !isYarn1) { commands.push("yarn config unset --home httpProxy"); commands.push(`yarn config set --home httpProxy ${quote(allEnv.HTTP_PROXY)}`); } // v8 ignore else -- TODO: add test #40625 if (allEnv.HTTPS_PROXY && !isYarn1) { commands.push("yarn config unset --home httpsProxy"); commands.push(`yarn config set --home httpsProxy ${quote(allEnv.HTTPS_PROXY)}`); } } commands.push(`yarn install${cmdOptions}`); const lockUpdates = upgrades.filter((upgrade) => upgrade.isLockfileUpdate); if (lockUpdates.length) { logger.debug("Performing lockfileUpdate (yarn)"); if (isYarn1) commands.push(`yarn upgrade ${lockUpdates.map((update) => update.depName).filter(isString).filter(uniqueStrings).map(quote).join(" ")}${cmdOptions}`); else commands.push(`yarn up -R ${lockUpdates.map((update) => `${update.depName}`).filter(uniqueStrings).map(quote).join(" ")}${cmdOptions}`); } ["fewer", "highest"].forEach((s) => { if (config.postUpdateOptions?.includes(`yarnDedupe${s.charAt(0).toUpperCase()}${s.slice(1)}`)) { logger.debug(`Performing yarn dedupe ${s}`); if (isYarn1) { commands.push(`npx yarn-deduplicate --strategy ${s}`); commands.push(`yarn install${cmdOptions}`); } else if (isYarnDedupeAvailable && s === "highest") commands.push(`yarn dedupe --strategy ${s}${cmdOptions}`); else logger.debug(`yarn dedupe ${s} not available`); } }); if (upgrades.find((upgrade) => upgrade.isLockFileMaintenance)) { logger.debug(`Removing ${lockFileName} first due to lock file maintenance upgrade`); try { await writeLocalFile(lockFileName, ""); } catch (err) { // v8 ignore next -- TODO: add test #40625 logger.debug({ err, lockFileName }, "Error clearing `yarn.lock` for lock file maintenance"); } } await exec(commands, execOptions); lockFile = await readLocalFile(lockFileName, "utf8"); } catch (err) { // v8 ignore if -- TODO: add test #40625 if (err.message === "temporary-error") throw err; logger.debug({ err, type: "yarn" }, "lock file error"); const stdouterr = String(err.stdout) + String(err.stderr); // v8 ignore if -- TODO: add test #40625 if (stdouterr.includes("ENOSPC: no space left on device") || stdouterr.includes("Out of diskspace")) throw new Error(SYSTEM_INSUFFICIENT_DISK_SPACE); // v8 ignore if -- TODO: add test #40625 if (stdouterr.includes("The registry may be down.") || stdouterr.includes("getaddrinfo ENOTFOUND registry.yarnpkg.com") || stdouterr.includes("getaddrinfo ENOTFOUND registry.npmjs.org")) throw new ExternalHostError(err, NpmDatasource.id); return { error: true, stderr: err.stderr, stdout: err.stdout }; } return { lockFile }; } function fuzzyMatchAdditionalYarnrcYml(additionalYarnRcYml, existingYarnrRcYml) { const keys = new Map(Object.keys(existingYarnrRcYml.npmRegistries ?? {}).map((x) => [x.replace(/\/$/, "").replace(/^https?:/, ""), x])); return { ...additionalYarnRcYml, npmRegistries: Object.entries(additionalYarnRcYml.npmRegistries ?? {}).map(([k, v]) => { return { [keys.get(k.replace(/\/$/, "")) ?? k]: v }; }).reduce((acc, cur) => ({ ...acc, ...cur }), {}) }; } //#endregion export { fuzzyMatchAdditionalYarnrcYml, generateLockFile, isYarnUpdate }; //# sourceMappingURL=yarn.js.map