UNPKG

renovate

Version:

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

204 lines • 9.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getPythonConstraint = getPythonConstraint; exports.getPoetryRequirement = getPoetryRequirement; exports.updateArtifacts = updateArtifacts; const tslib_1 = require("tslib"); const is_1 = tslib_1.__importDefault(require("@sindresorhus/is")); const shlex_1 = require("shlex"); 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 auth_1 = require("../../../util/git/auth"); const host_rules_1 = require("../../../util/host-rules"); const regex_1 = require("../../../util/regex"); const result_1 = require("../../../util/result"); const toml_1 = require("../../../util/toml"); const url_1 = require("../../../util/url"); const pypi_1 = require("../../datasource/pypi"); const util_1 = require("../../datasource/util"); const schema_1 = require("./schema"); function getPythonConstraint(pyProjectContent, existingLockFileContent) { // Read Python version from `pyproject.toml` first as it could have been updated const pyprojectPythonConstraint = result_1.Result.parse((0, toml_1.massage)(pyProjectContent), schema_1.PoetryPyProject.transform(({ packageFileContent }) => packageFileContent.deps.find((dep) => dep.depName === 'python') ?.currentValue)).unwrapOrNull(); if (pyprojectPythonConstraint) { logger_1.logger.debug('Using python version from pyproject.toml'); return pyprojectPythonConstraint; } const lockfilePythonConstraint = result_1.Result.parse(existingLockFileContent, schema_1.Lockfile.transform(({ pythonVersions }) => pythonVersions)).unwrapOrNull(); if (lockfilePythonConstraint) { logger_1.logger.debug('Using python version from poetry.lock'); return lockfilePythonConstraint; } return null; } function getPoetryRequirement(pyProjectContent, existingLockFileContent) { // Read Poetry version from first line of poetry.lock const firstLine = existingLockFileContent.split('\n')[0]; const poetryVersionMatch = (0, regex_1.regEx)(/by Poetry ([\d\\.]+)/).exec(firstLine); if (poetryVersionMatch?.[1]) { const poetryVersion = poetryVersionMatch[1]; logger_1.logger.debug(`Using poetry version ${poetryVersion} from poetry.lock header`); return poetryVersion; } const { val: lockfilePoetryConstraint } = result_1.Result.parse(existingLockFileContent, schema_1.Lockfile.transform(({ poetryConstraint }) => poetryConstraint)).unwrap(); if (lockfilePoetryConstraint) { logger_1.logger.debug(`Using poetry version ${lockfilePoetryConstraint} from poetry.lock metadata`); return lockfilePoetryConstraint; } const { val: pyprojectPoetryConstraint } = result_1.Result.parse((0, toml_1.massage)(pyProjectContent), schema_1.PoetryPyProject.transform(({ poetryRequirement }) => poetryRequirement)).unwrap(); if (pyprojectPoetryConstraint) { logger_1.logger.debug(`Using poetry version ${pyprojectPoetryConstraint} from pyproject.toml`); return pyprojectPoetryConstraint; } return null; } function getPoetrySources(content, fileName) { let pyprojectFile; try { pyprojectFile = (0, toml_1.parse)((0, toml_1.massage)(content)); } catch (err) { logger_1.logger.debug({ err }, 'Error parsing pyproject.toml file'); return []; } if (!pyprojectFile.tool?.poetry) { logger_1.logger.debug(`${fileName} contains no poetry section`); return []; } const sources = pyprojectFile.tool?.poetry?.source ?? []; const sourceArray = []; for (const source of sources) { if (source.name && source.url) { sourceArray.push({ name: source.name, url: source.url }); } } return sourceArray; } async function getMatchingHostRule(url) { const scopedMatch = (0, host_rules_1.find)({ hostType: pypi_1.PypiDatasource.id, url }); const hostRule = is_1.default.nonEmptyObject(scopedMatch) ? scopedMatch : (0, host_rules_1.find)({ url }); if (hostRule && Object.keys(hostRule).length !== 0) { return hostRule; } const parsedUrl = (0, url_1.parseUrl)(url); if (!parsedUrl) { logger_1.logger.once.debug(`Failed to parse URL ${url}`); return {}; } if (parsedUrl.hostname.endsWith('.pkg.dev')) { const hostRule = await (0, util_1.getGoogleAuthHostRule)(); if (hostRule && Object.keys(hostRule).length !== 0) { return hostRule; } logger_1.logger.once.debug(`Could not get Google access token (url=${url})`); } return {}; } async function getSourceCredentialVars(pyprojectContent, packageFileName) { const poetrySources = getPoetrySources(pyprojectContent, packageFileName); const envVars = {}; for (const source of poetrySources) { const matchingHostRule = await getMatchingHostRule(source.url); const formattedSourceName = source.name .replace((0, regex_1.regEx)(/(\.|-)+/g), '_') .toUpperCase(); if (matchingHostRule.username) { envVars[`POETRY_HTTP_BASIC_${formattedSourceName}_USERNAME`] = matchingHostRule.username; } if (matchingHostRule.password) { envVars[`POETRY_HTTP_BASIC_${formattedSourceName}_PASSWORD`] = matchingHostRule.password; } } return envVars; } async function updateArtifacts({ packageFileName, updatedDeps, newPackageFileContent, config, }) { logger_1.logger.debug(`poetry.updateArtifacts(${packageFileName})`); const { isLockFileMaintenance } = config; if (!is_1.default.nonEmptyArray(updatedDeps) && !isLockFileMaintenance) { logger_1.logger.debug('No updated poetry deps - returning null'); return null; } // Try poetry.lock first let lockFileName = (0, fs_1.getSiblingFileName)(packageFileName, 'poetry.lock'); let existingLockFileContent = await (0, fs_1.readLocalFile)(lockFileName, 'utf8'); if (!existingLockFileContent) { // Try pyproject.lock next lockFileName = (0, fs_1.getSiblingFileName)(packageFileName, 'pyproject.lock'); existingLockFileContent = await (0, fs_1.readLocalFile)(lockFileName, 'utf8'); if (!existingLockFileContent) { logger_1.logger.debug(`No lock file found`); return null; } } logger_1.logger.debug(`Updating ${lockFileName}`); try { await (0, fs_1.writeLocalFile)(packageFileName, newPackageFileContent); const cmd = []; if (isLockFileMaintenance) { await (0, fs_1.deleteLocalFile)(lockFileName); cmd.push('poetry update --lock --no-interaction'); } else { cmd.push(`poetry update --lock --no-interaction ${updatedDeps .map((dep) => dep.depName) .filter(is_1.default.string) .map((dep) => (0, shlex_1.quote)(dep)) .join(' ')}`); } const pythonConstraint = config?.constraints?.python ?? getPythonConstraint(newPackageFileContent, existingLockFileContent); const poetryConstraint = config.constraints?.poetry ?? getPoetryRequirement(newPackageFileContent, existingLockFileContent); const extraEnv = { ...(await getSourceCredentialVars(newPackageFileContent, packageFileName)), ...(0, auth_1.getGitEnvironmentVariables)(['poetry']), PIP_CACHE_DIR: await (0, fs_1.ensureCacheDir)('pip'), }; const execOptions = { cwdFile: packageFileName, extraEnv, docker: {}, toolConstraints: [ { toolName: 'python', constraint: pythonConstraint }, { toolName: 'poetry', constraint: poetryConstraint }, ], }; await (0, exec_1.exec)(cmd, execOptions); const newPoetryLockContent = await (0, fs_1.readLocalFile)(lockFileName, 'utf8'); if (existingLockFileContent === newPoetryLockContent) { logger_1.logger.debug(`${lockFileName} is unchanged`); return null; } logger_1.logger.debug(`Returning updated ${lockFileName}`); return [ { file: { type: 'addition', path: lockFileName, contents: newPoetryLockContent, }, }, ]; } catch (err) { // istanbul ignore if if (err.message === error_messages_1.TEMPORARY_ERROR) { throw err; } logger_1.logger.debug({ err }, `Failed to update ${lockFileName} file`); return [ { artifactError: { lockFile: lockFileName, stderr: `${String(err.stdout)}\n${String(err.stderr)}`, }, }, ]; } } //# sourceMappingURL=artifacts.js.map