renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
216 lines • 9.72 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateLockFile = generateLockFile;
exports.getConstraintFromLockFile = getConstraintFromLockFile;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
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 exec_1 = require("../../../../util/exec");
const fs_1 = require("../../../../util/fs");
const string_1 = require("../../../../util/string");
const yaml_1 = require("../../../../util/yaml");
const constants_1 = require("../constants");
const node_version_1 = require("./node-version");
const utils_1 = require("./utils");
function getPnpmConstraintFromUpgrades(upgrades) {
for (const upgrade of upgrades) {
if (upgrade.depName === 'pnpm' && upgrade.newVersion) {
return upgrade.newVersion;
}
}
return null;
}
async function generateLockFile(lockFileDir, env, config, upgrades = []) {
const lockFileName = upath_1.default.join(lockFileDir, 'pnpm-lock.yaml');
logger_1.logger.debug(`Spawning pnpm install to create ${lockFileName}`);
let lockFile = null;
let stdout;
let stderr;
const commands = [];
try {
const lazyPgkJson = (0, utils_1.lazyLoadPackageJson)(lockFileDir);
const pnpmToolConstraint = {
toolName: 'pnpm',
constraint: getPnpmConstraintFromUpgrades(upgrades) ?? // if pnpm is being upgraded, it comes first
config.constraints?.pnpm ?? // from user config or extraction
(0, utils_1.getPackageManagerVersion)('pnpm', await lazyPgkJson.getValue()) ?? // look in package.json > packageManager or engines
(await getConstraintFromLockFile(lockFileName)), // use lockfileVersion to find pnpm version range
};
const pnpmConfigCacheDir = await (0, fs_1.ensureCacheDir)(constants_1.PNPM_CACHE_DIR);
const pnpmConfigStoreDir = await (0, fs_1.ensureCacheDir)(constants_1.PNPM_STORE_DIR);
const extraEnv = {
// those arwe no longer working and it's unclear if they ever worked
NPM_CONFIG_CACHE: env.NPM_CONFIG_CACHE,
npm_config_store: env.npm_config_store,
// these are used by pnpm v5 to v10. Maybe earlier versions too
npm_config_cache_dir: pnpmConfigCacheDir,
npm_config_store_dir: pnpmConfigStoreDir,
// pnpm stops reading npm_config_* env vars since v11
pnpm_config_cache_dir: pnpmConfigCacheDir,
pnpm_config_store_dir: pnpmConfigStoreDir,
};
const execOptions = {
cwdFile: lockFileName,
extraEnv,
docker: {},
toolConstraints: [
await (0, node_version_1.getNodeToolConstraint)(config, upgrades, lockFileDir, lazyPgkJson),
pnpmToolConstraint,
],
};
/* v8 ignore next 4 -- needs test */
if (global_1.GlobalConfig.get('exposeAllEnv')) {
extraEnv.NPM_AUTH = env.NPM_AUTH;
extraEnv.NPM_EMAIL = env.NPM_EMAIL;
}
const pnpmWorkspaceFilePath = (0, fs_1.getSiblingFileName)(lockFileName, 'pnpm-workspace.yaml');
let args = '--lockfile-only';
// If it's not a workspaces project/monorepo, but single project with unrelated other npm project in source tree (for example, a git submodule),
// `--recursive` will install un-wanted project.
// we should avoid this.
if (await (0, fs_1.localPathExists)(pnpmWorkspaceFilePath)) {
const pnpmWorkspace = (0, yaml_1.parseSingleYaml)((await (0, fs_1.readLocalFile)(pnpmWorkspaceFilePath, 'utf8')));
if (pnpmWorkspace?.packages?.length) {
logger_1.logger.debug(`Found pnpm workspace with ${pnpmWorkspace.packages.length} package definitions`);
// we are in a monorepo, 'pnpm update' needs the '--recursive' flag contrary to 'pnpm install'
args += ' --recursive';
}
}
if (!global_1.GlobalConfig.get('allowScripts') || config.ignoreScripts) {
args += ' --ignore-scripts';
args += ' --ignore-pnpmfile';
}
logger_1.logger.trace({ args }, 'pnpm command options');
const lockUpdates = upgrades.filter((upgrade) => upgrade.isLockfileUpdate);
if (lockUpdates.length !== upgrades.length) {
// This command updates the lock file based on package.json
commands.push(`pnpm install ${args}`);
}
// rangeStrategy = update-lockfile
if (lockUpdates.length) {
logger_1.logger.debug('Performing lockfileUpdate (pnpm)');
commands.push(`pnpm update --no-save ${lockUpdates
// TODO: types (#22198)
.map((update) => `${update.packageName}@${update.newVersion}`)
.filter(string_1.uniqueStrings)
.map(shlex_1.quote)
.join(' ')} ${args}`);
}
// postUpdateOptions
if (config.postUpdateOptions?.includes('pnpmDedupe')) {
commands.push('pnpm dedupe --ignore-scripts');
}
if (upgrades.find((upgrade) => upgrade.isLockFileMaintenance)) {
logger_1.logger.debug(`Removing ${lockFileName} first due to lock file maintenance upgrade`);
try {
await (0, fs_1.deleteLocalFile)(lockFileName);
/* v8 ignore start -- needs test */
}
catch (err) {
logger_1.logger.debug({ err, lockFileName }, 'Error removing `pnpm-lock.yaml` for lock file maintenance');
} /* v8 ignore stop -- needs test */
}
await (0, exec_1.exec)(commands, execOptions);
lockFile = await (0, fs_1.readLocalFile)(lockFileName, 'utf8');
/* v8 ignore start -- needs test */
}
catch (err) {
if (err.message === error_messages_1.TEMPORARY_ERROR) {
throw err;
}
logger_1.logger.debug({
commands,
err,
stdout,
stderr,
type: 'pnpm',
}, 'lock file error');
return { error: true, stderr: err.stderr, stdout: err.stdout };
} /* v8 ignore stop -- needs test */
return { lockFile };
}
async function getConstraintFromLockFile(lockFileName) {
let constraint = null;
try {
const lockfileContent = await (0, fs_1.readLocalFile)(lockFileName, 'utf8');
if (!lockfileContent) {
logger_1.logger.trace(`Empty pnpm lock file: ${lockFileName}`);
return null;
}
// TODO: use schema (#9610)
const pnpmLock = (0, yaml_1.parseSingleYaml)(lockfileContent);
if (!is_1.default.number(pnpmLock?.lockfileVersion) &&
!is_1.default.numericString(pnpmLock?.lockfileVersion)) {
logger_1.logger.trace(`Invalid pnpm lockfile version: ${lockFileName}`);
return null;
}
// find matching lockfileVersion and use its constraints
// if no match found use lockfileVersion 5
// lockfileVersion 5 is the minimum version required to generate the pnpm-lock.yaml file
const { lowerConstraint, upperConstraint } = lockToPnpmVersionMapping.find((m) => m.lockfileVersion === pnpmLock.lockfileVersion) ?? {
lockfileVersion: 5.0,
lowerConstraint: '>=3',
upperConstraint: '<3.5.0',
};
constraint = lowerConstraint;
if (upperConstraint) {
constraint += ` ${upperConstraint}`;
}
}
catch (err) {
logger_1.logger.warn({ err }, 'Error getting pnpm constraints from lock file');
}
return constraint;
}
/**
* pnpm lockfiles have corresponding version numbers called "lockfileVersion"
* each lockfileVersion can only be generated by a certain pnpm version range
* eg. lockfileVersion: 5.4 can only be generated by pnpm version >=7 && <8
* official list can be found here : https://github.com/pnpm/spec/tree/master/lockfile
* we use the mapping present below to find the compatible pnpm version range for a given lockfileVersion
*
* the various terms used in the mapping are explained below:
* lowerConstraint : lowest pnpm version that can generate the lockfileVersion
* upperConstraint : highest pnpm version that can generate the lockfileVersion
* lowerBound : highest pnpm version that is less than the lowerConstraint
* upperBound : lowest pnpm version that is greater than the upperConstraint
*
* To handle future lockfileVersions, we need to:
* 1. add a upperBound and upperConstraint to the current latest lockfileVersion
* 2. add an object for the new lockfileVersion with lowerBound and lowerConstraint
*
* lockfileVersion from v6 on are strings
*/
const lockToPnpmVersionMapping = [
{ lockfileVersion: '9.0', lowerConstraint: '>=9' },
{
lockfileVersion: '6.0',
lowerConstraint: '>=7.24.2',
upperConstraint: '<9',
},
{
lockfileVersion: 5.4,
lowerConstraint: '>=7',
upperConstraint: '<8',
},
{
lockfileVersion: 5.3,
lowerConstraint: '>=6',
upperConstraint: '<7',
},
{
lockfileVersion: 5.2,
lowerConstraint: '>=5.10.0',
upperConstraint: '<6',
},
{
lockfileVersion: 5.1,
lowerConstraint: '>=3.5.0',
upperConstraint: '<5.9.3',
},
];
//# sourceMappingURL=pnpm.js.map