UNPKG

renovate

Version:

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

149 lines 6.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getMatchingHostRule = getMatchingHostRule; exports.extractEnvironmentVariableName = extractEnvironmentVariableName; exports.addExtraEnvVariable = addExtraEnvVariable; exports.updateArtifacts = updateArtifacts; const tslib_1 = require("tslib"); const detect_tools_1 = require("@renovatebot/detect-tools"); const is_1 = tslib_1.__importDefault(require("@sindresorhus/is")); 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 util_1 = require("../../../util/fs/util"); const git_1 = require("../../../util/git"); const host_rules_1 = require("../../../util/host-rules"); const regex_1 = require("../../../util/regex"); const url_1 = require("../../../util/url"); const pypi_1 = require("../../datasource/pypi"); const extract_1 = require("./extract"); function getMatchingHostRule(url) { const parsedUrl = (0, url_1.parseUrl)(url); if (parsedUrl) { parsedUrl.username = ''; parsedUrl.password = ''; const urlWithoutCredentials = parsedUrl.toString(); return (0, host_rules_1.find)({ hostType: pypi_1.PypiDatasource.id, url: urlWithoutCredentials }); } return null; } async function findPipfileSourceUrlsWithCredentials(pipfileContent, pipfileName) { const pipfile = await (0, extract_1.extractPackageFile)(pipfileContent, pipfileName); return (pipfile?.registryUrls ?.map(url_1.parseUrl) .filter(is_1.default.urlInstance) .filter((url) => is_1.default.nonEmptyStringAndNotWhitespace(url.username)) ?? []); } /** * This will extract the actual variable name from an environment-placeholder: * ${USERNAME:-defaultvalue} will yield 'USERNAME' */ function extractEnvironmentVariableName(credential) { const match = (0, regex_1.regEx)('([a-z0-9_]+)', 'i').exec(decodeURI(credential)); return match?.length ? match[0] : null; } function addExtraEnvVariable(extraEnv, environmentVariableName, environmentValue) { logger_1.logger.trace(`Adding ${environmentVariableName} environment variable for pipenv`); if (extraEnv[environmentVariableName] && extraEnv[environmentVariableName] !== environmentValue) { logger_1.logger.warn({ envVar: environmentVariableName }, 'Possible misconfiguration, environment variable already set to a different value'); } extraEnv[environmentVariableName] = environmentValue; } /** * Pipenv allows configuring source-urls for remote repositories with placeholders for credentials, i.e. http://$USER:$PASS@myprivate.repo * if a matching host rule exists for that repository, we need to set the corresponding variables. * Simply substituting them in the URL is not an option as it would impact the hash for the resulting Pipfile.lock * */ async function addCredentialsForSourceUrls(newPipfileContent, pipfileName, extraEnv) { const sourceUrls = await findPipfileSourceUrlsWithCredentials(newPipfileContent, pipfileName); for (const parsedSourceUrl of sourceUrls) { logger_1.logger.trace(`Trying to add credentials for ${parsedSourceUrl.toString()}`); const matchingHostRule = getMatchingHostRule(parsedSourceUrl.toString()); if (matchingHostRule) { const usernameVariableName = extractEnvironmentVariableName(parsedSourceUrl.username); if (matchingHostRule.username && usernameVariableName) { addExtraEnvVariable(extraEnv, usernameVariableName, matchingHostRule.username); } const passwordVariableName = extractEnvironmentVariableName(parsedSourceUrl.password); if (matchingHostRule.password && passwordVariableName) { addExtraEnvVariable(extraEnv, passwordVariableName, matchingHostRule.password); } } } } async function updateArtifacts({ packageFileName: pipfileName, newPackageFileContent: newPipfileContent, config, }) { logger_1.logger.debug(`pipenv.updateArtifacts(${pipfileName})`); const lockFileName = pipfileName + '.lock'; if (!(await (0, fs_1.localPathExists)(lockFileName))) { logger_1.logger.debug('No Pipfile.lock found'); return null; } try { await (0, fs_1.writeLocalFile)(pipfileName, newPipfileContent); if (config.isLockFileMaintenance) { await (0, fs_1.deleteLocalFile)(lockFileName); } const cmd = 'pipenv lock'; const pipfileDir = (0, fs_1.getParentDir)((0, util_1.ensureLocalPath)(pipfileName)); const tagConstraint = config.constraints?.python ?? (await detect_tools_1.pipenv.getPythonConstraint(pipfileDir)); const pipenvConstraint = config.constraints?.pipenv ?? (await detect_tools_1.pipenv.getPipenvConstraint(pipfileDir)); const extraEnv = { PIPENV_CACHE_DIR: await (0, fs_1.ensureCacheDir)('pipenv'), PIP_CACHE_DIR: await (0, fs_1.ensureCacheDir)('pip'), WORKON_HOME: await (0, fs_1.ensureCacheDir)('virtualenvs'), }; const execOptions = { cwdFile: pipfileName, docker: {}, toolConstraints: [ { toolName: 'python', constraint: tagConstraint, }, { toolName: 'pipenv', constraint: pipenvConstraint, }, ], }; await addCredentialsForSourceUrls(newPipfileContent, pipfileName, extraEnv); execOptions.extraEnv = extraEnv; logger_1.logger.trace({ cmd }, 'pipenv lock command'); await (0, exec_1.exec)(cmd, execOptions); const status = await (0, git_1.getRepoStatus)(); if (!status?.modified.includes(lockFileName)) { return null; } logger_1.logger.debug('Returning updated Pipfile.lock'); return [ { file: { type: 'addition', path: lockFileName, contents: await (0, fs_1.readLocalFile)(lockFileName, 'utf8'), }, }, ]; } catch (err) { // istanbul ignore if if (err.message === error_messages_1.TEMPORARY_ERROR) { throw err; } logger_1.logger.debug({ err }, 'Failed to update Pipfile.lock'); return [ { artifactError: { lockFile: lockFileName, stderr: err.message, }, }, ]; } } //# sourceMappingURL=artifacts.js.map