UNPKG

renovate

Version:

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

289 lines • 13.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkYarnrc = checkYarnrc; exports.getOptimizeCommand = getOptimizeCommand; exports.isYarnUpdate = isYarnUpdate; exports.generateLockFile = generateLockFile; exports.fuzzyMatchAdditionalYarnrcYml = fuzzyMatchAdditionalYarnrcYml; const tslib_1 = require("tslib"); const is_1 = tslib_1.__importDefault(require("@sindresorhus/is")); const semver_1 = tslib_1.__importDefault(require("semver")); const shlex_1 = require("shlex"); const upath_1 = tslib_1.__importDefault(require("upath")); const global_1 = require("../../../../config/global"); const error_messages_1 = require("../../../../constants/error-messages"); const logger_1 = require("../../../../logger"); const external_host_error_1 = require("../../../../types/errors/external-host-error"); const env_1 = require("../../../../util/env"); const exec_1 = require("../../../../util/exec"); const fs_1 = require("../../../../util/fs"); const regex_1 = require("../../../../util/regex"); const string_1 = require("../../../../util/string"); const npm_1 = require("../../../datasource/npm"); const yarn_1 = require("../extract/yarn"); const node_version_1 = require("./node-version"); const utils_1 = require("./utils"); async function checkYarnrc(lockFileDir) { let offlineMirror = false; let yarnPath = null; try { const yarnrc = await (0, fs_1.readLocalFile)(upath_1.default.join(lockFileDir, '.yarnrc'), 'utf8'); if (is_1.default.string(yarnrc)) { const mirrorLine = yarnrc .split(regex_1.newlineRegex) .find((line) => line.startsWith('yarn-offline-mirror ')); offlineMirror = !!mirrorLine; const pathLine = yarnrc .split(regex_1.newlineRegex) .find((line) => line.startsWith('yarn-path ')); if (pathLine) { yarnPath = pathLine.replace((0, regex_1.regEx)(/^yarn-path\s+"?(.+?)"?$/), '$1'); } if (yarnPath) { // resolve binary relative to `yarnrc` yarnPath = upath_1.default.join(lockFileDir, yarnPath); } const yarnBinaryExists = yarnPath ? await (0, fs_1.localPathIsFile)(yarnPath) : false; let scrubbedYarnrc = yarnrc .replace('--install.pure-lockfile true', '') .replace('--install.frozen-lockfile true', ''); if (!yarnBinaryExists) { scrubbedYarnrc = scrubbedYarnrc.replace((0, regex_1.regEx)(/^yarn-path\s+"?.+?"?$/gm), ''); yarnPath = null; } if (yarnrc !== scrubbedYarnrc) { logger_1.logger.debug(`Writing scrubbed .yarnrc to ${lockFileDir}`); await (0, fs_1.writeLocalFile)(upath_1.default.join(lockFileDir, '.yarnrc'), scrubbedYarnrc); } } } catch /* istanbul ignore next */ { // not found } return { offlineMirror, yarnPath }; } function getOptimizeCommand(fileName) { return `sed -i 's/ steps,/ steps.slice(0,1),/' ${(0, shlex_1.quote)(fileName)}`; } function isYarnUpdate(upgrade) { return upgrade.depType === 'packageManager' && upgrade.depName === 'yarn'; } async function generateLockFile(lockFileDir, env, config = {}, upgrades = []) { const lockFileName = upath_1.default.join(lockFileDir, 'yarn.lock'); logger_1.logger.debug(`Spawning yarn install to create ${lockFileName}`); let lockFile = null; try { const lazyPgkJson = (0, utils_1.lazyLoadPackageJson)(lockFileDir); const toolConstraints = [ await (0, node_version_1.getNodeToolConstraint)(config, upgrades, lockFileDir, lazyPgkJson), ]; const yarnUpdate = upgrades.find(isYarnUpdate); const yarnCompatibility = (yarnUpdate ? yarnUpdate.newValue : config.constraints?.yarn) ?? (0, utils_1.getPackageManagerVersion)('yarn', await lazyPgkJson.getValue()) ?? (0, yarn_1.getYarnVersionFromLock)(await (0, yarn_1.getYarnLock)(lockFileName)); const minYarnVersion = semver_1.default.validRange(yarnCompatibility) && semver_1.default.minVersion(yarnCompatibility); const isYarn1 = !minYarnVersion || minYarnVersion.major === 1; const isYarnDedupeAvailable = minYarnVersion && semver_1.default.gte(minYarnVersion, '2.2.0'); const isYarnModeAvailable = minYarnVersion && semver_1.default.gte(minYarnVersion, '3.0.0'); const yarnTool = { toolName: 'yarn', constraint: '^1.22.18', // needs to be a v1 yarn, otherwise v2 will be installed }; // check first upgrade, see #17786 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 = ''; // should have a leading space if (config.skipInstalls !== false) { if (isYarn1) { const { offlineMirror, yarnPath } = await checkYarnrc(lockFileDir); if (!offlineMirror) { logger_1.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 yarnTool.toolName = 'yarn-slim'; if (yarnPath) { commands.push(getOptimizeCommand(yarnPath) + ' || true'); } } } else if (isYarnModeAvailable) { // Don't run the link step and only fetch what's necessary to compute an updated lockfile 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_1.logger.debug('Enabling global cache as zero-install is not detected'); extraEnv.YARN_ENABLE_GLOBAL_CACHE = '1'; } } if (!global_1.GlobalConfig.get('allowScripts') || config.ignoreScripts) { if (isYarn1) { cmdOptions += ' --ignore-scripts'; } else if (isYarnModeAvailable) { if (config.skipInstalls === false) { // Don't run the build scripts cmdOptions += ' --mode=skip-build'; } } else { extraEnv.YARN_ENABLE_SCRIPTS = '0'; } } const execOptions = { cwdFile: lockFileName, extraEnv, docker: {}, toolConstraints, }; // istanbul ignore if if (global_1.GlobalConfig.get('exposeAllEnv')) { extraEnv.NPM_AUTH = env.NPM_AUTH; extraEnv.NPM_EMAIL = env.NPM_EMAIL; } if (yarnUpdate && !isYarn1) { logger_1.logger.debug('Updating Yarn binary'); // TODO: types (#22198) commands.push(`yarn set version ${(0, shlex_1.quote)(yarnUpdate.newValue)}`); } const allEnv = (0, env_1.getEnv)(); if (allEnv.RENOVATE_X_YARN_PROXY) { if (allEnv.HTTP_PROXY && !isYarn1) { commands.push('yarn config unset --home httpProxy'); commands.push(`yarn config set --home httpProxy ${(0, shlex_1.quote)(allEnv.HTTP_PROXY)}`); } if (allEnv.HTTPS_PROXY && !isYarn1) { commands.push('yarn config unset --home httpsProxy'); commands.push(`yarn config set --home httpsProxy ${(0, shlex_1.quote)(allEnv.HTTPS_PROXY)}`); } } // This command updates the lock file based on package.json commands.push(`yarn install${cmdOptions}`); // rangeStrategy = update-lockfile const lockUpdates = upgrades.filter((upgrade) => upgrade.isLockfileUpdate); if (lockUpdates.length) { logger_1.logger.debug('Performing lockfileUpdate (yarn)'); if (isYarn1) { // `yarn upgrade` updates based on the version range specified in the package file // note - this can hit a yarn bug, see https://github.com/yarnpkg/yarn/issues/8236 commands.push(`yarn upgrade ${lockUpdates .map((update) => update.depName) .filter(is_1.default.string) .filter(string_1.uniqueStrings) .map(shlex_1.quote) .join(' ')}${cmdOptions}`); } else { // `yarn up -R` updates to the latest release in each range commands.push(`yarn up -R ${lockUpdates // TODO: types (#22198) .map((update) => `${update.depName}`) .filter(string_1.uniqueStrings) .map(shlex_1.quote) .join(' ')}${cmdOptions}`); } } // postUpdateOptions ['fewer', 'highest'].forEach((s) => { if (config.postUpdateOptions?.includes(`yarnDedupe${s.charAt(0).toUpperCase()}${s.slice(1)}`)) { logger_1.logger.debug(`Performing yarn dedupe ${s}`); if (isYarn1) { commands.push(`npx yarn-deduplicate --strategy ${s}`); // Run yarn again in case any changes are necessary commands.push(`yarn install${cmdOptions}`); } else if (isYarnDedupeAvailable && s === 'highest') { commands.push(`yarn dedupe --strategy ${s}${cmdOptions}`); } else { logger_1.logger.debug(`yarn dedupe ${s} not available`); } } }); if (upgrades.find((upgrade) => upgrade.isLockFileMaintenance)) { logger_1.logger.debug(`Removing ${lockFileName} first due to lock file maintenance upgrade`); // Note: Instead of just deleting the `yarn.lock` file, we just wipe it // and keep an empty lock file. Deleting the lock file could result in different // Yarn semantics. e.g. Yarn 2+ will error when `yarn install` is executed in // a subdirectory which is not part of a Yarn workspace. Yarn suggests to create // an empty lock file if a subdirectory should be treated as its own workspace. // https://github.com/yarnpkg/berry/blob/20612e82d26ead5928cc27bf482bb8d62dde87d3/packages/yarnpkg-core/sources/Project.ts#L284. try { await (0, fs_1.writeLocalFile)(lockFileName, ''); } catch (err) /* istanbul ignore next */ { logger_1.logger.debug({ err, lockFileName }, 'Error clearing `yarn.lock` for lock file maintenance'); } } // Run the commands await (0, exec_1.exec)(commands, execOptions); // Read the result lockFile = await (0, fs_1.readLocalFile)(lockFileName, 'utf8'); } catch (err) /* istanbul ignore next */ { if (err.message === error_messages_1.TEMPORARY_ERROR) { throw err; } logger_1.logger.debug({ err, type: 'yarn', }, 'lock file error'); const stdouterr = String(err.stdout) + String(err.stderr); if (stdouterr.includes('ENOSPC: no space left on device') || stdouterr.includes('Out of diskspace')) { throw new Error(error_messages_1.SYSTEM_INSUFFICIENT_DISK_SPACE); } if (stdouterr.includes('The registry may be down.') || stdouterr.includes('getaddrinfo ENOTFOUND registry.yarnpkg.com') || stdouterr.includes('getaddrinfo ENOTFOUND registry.npmjs.org')) { throw new external_host_error_1.ExternalHostError(err, npm_1.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]) => { const key = keys.get(k.replace(/\/$/, '')) ?? k; return { [key]: v }; }) .reduce((acc, cur) => ({ ...acc, ...cur }), {}), }; } //# sourceMappingURL=yarn.js.map