UNPKG

renovate

Version:

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

359 lines • 17.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getUpdatedPackageFiles = getUpdatedPackageFiles; const tslib_1 = require("tslib"); /* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */ const is_1 = tslib_1.__importDefault(require("@sindresorhus/is")); const error_messages_1 = require("../../../../constants/error-messages"); const logger_1 = require("../../../../logger"); const manager_1 = require("../../../../modules/manager"); const git_1 = require("../../../../util/git"); const string_1 = require("../../../../util/string"); const auto_replace_1 = require("./auto-replace"); async function getFileContent(updatedFileContents, filePath, config) { let fileContent = updatedFileContents[filePath]; if (!fileContent) { fileContent = await (0, git_1.getFile)(filePath, config.reuseExistingBranch ? config.branchName : config.baseBranch); } return fileContent; } function sortPackageFiles(config, manager, packageFiles) { const managerPackageFiles = config.packageFiles?.[manager]; if (!managerPackageFiles) { return; } packageFiles.sort((lhs, rhs) => { const lhsIndex = managerPackageFiles.findIndex((entry) => entry.packageFile === lhs.path); const rhsIndex = managerPackageFiles.findIndex((entry) => entry.packageFile === rhs.path); return lhsIndex - rhsIndex; }); } function hasAny(set, targets) { for (const target of targets) { if (set.has(target)) { return true; } } return false; } function getManagersForPackageFiles(packageFiles, managerPackageFiles) { const packageFileNames = packageFiles.map((packageFile) => packageFile.path); return new Set(Object.keys(managerPackageFiles).filter((manager) => hasAny(managerPackageFiles[manager], packageFileNames))); } function getPackageFilesForManager(packageFiles, managerPackageFiles) { return packageFiles.filter((packageFile) => managerPackageFiles.has(packageFile.path)); } async function getUpdatedPackageFiles(config) { logger_1.logger.trace({ config }); const reuseExistingBranch = config.reuseExistingBranch; logger_1.logger.debug(`manager.getUpdatedPackageFiles() reuseExistingBranch=${reuseExistingBranch}`); let updatedFileContents = {}; const nonUpdatedFileContents = {}; const managerPackageFiles = {}; const packageFileUpdatedDeps = {}; const lockFileMaintenanceFiles = []; let firstUpdate = true; for (const upgrade of config.upgrades) { const manager = upgrade.manager; const packageFile = upgrade.packageFile; const depName = upgrade.depName; // TODO: fix types, can be undefined (#22198) const newVersion = upgrade.newVersion; const currentVersion = upgrade.currentVersion; const updateLockedDependency = (0, manager_1.get)(manager, 'updateLockedDependency'); managerPackageFiles[manager] ??= new Set(); managerPackageFiles[manager].add(packageFile); packageFileUpdatedDeps[packageFile] ??= []; packageFileUpdatedDeps[packageFile].push({ ...upgrade }); const packageFileContent = await getFileContent(updatedFileContents, packageFile, config); let lockFileContent = null; const lockFile = upgrade.lockFile ?? upgrade.lockFiles?.[0] ?? ''; if (lockFile) { lockFileContent = await getFileContent(updatedFileContents, lockFile, config); } // istanbul ignore if if (reuseExistingBranch && (!packageFileContent || (lockFile && !lockFileContent))) { logger_1.logger.debug({ packageFile, depName }, 'Rebasing branch after file not found'); return getUpdatedPackageFiles({ ...config, reuseExistingBranch: false, }); } if (upgrade.updateType === 'lockFileMaintenance') { lockFileMaintenanceFiles.push(packageFile); } else if (upgrade.isRemediation) { const { status, files } = await updateLockedDependency({ ...upgrade, depName, newVersion, currentVersion, packageFile, packageFileContent: packageFileContent, lockFile, lockFileContent: lockFileContent, allowParentUpdates: true, allowHigherOrRemoved: true, }); if (reuseExistingBranch && status !== 'already-updated') { logger_1.logger.debug({ lockFile, depName, status }, 'Need to retry branch as it is not already up-to-date'); return getUpdatedPackageFiles({ ...config, reuseExistingBranch: false, }); } if (files) { updatedFileContents = { ...updatedFileContents, ...files }; Object.keys(files).forEach((file) => delete nonUpdatedFileContents[file]); } if (status === 'update-failed' || status === 'unsupported') { upgrade.remediationNotPossible = true; } } else if (upgrade.isLockfileUpdate) { if (updateLockedDependency) { const { status, files } = await updateLockedDependency({ ...upgrade, depName, newVersion, currentVersion, packageFile, packageFileContent: packageFileContent, lockFile, lockFileContent: lockFileContent, allowParentUpdates: false, }); if (status === 'unsupported') { // incompatible lock file if (!updatedFileContents[packageFile]) { nonUpdatedFileContents[packageFile] = packageFileContent; } } else if (status === 'already-updated') { logger_1.logger.debug(`Upgrade of ${depName} to ${newVersion} is already done in existing branch`); } else { // something changed if (reuseExistingBranch) { logger_1.logger.debug({ lockFile, depName, status }, 'Need to retry branch as upgrade requirements are not mets'); return getUpdatedPackageFiles({ ...config, reuseExistingBranch: false, }); } if (files) { updatedFileContents = { ...updatedFileContents, ...files }; Object.keys(files).forEach((file) => delete nonUpdatedFileContents[file]); } } } else { logger_1.logger.debug({ manager }, 'isLockFileUpdate without updateLockedDependency'); if (!updatedFileContents[packageFile]) { nonUpdatedFileContents[packageFile] = packageFileContent; } } } else { const updateDependency = (0, manager_1.get)(manager, 'updateDependency'); if (!updateDependency) { let res = await (0, auto_replace_1.doAutoReplace)(upgrade, packageFileContent, reuseExistingBranch, firstUpdate); firstUpdate = false; if (res) { res = await applyManagerBumpPackageVersion(res, upgrade); if (res === packageFileContent) { logger_1.logger.debug({ packageFile, depName }, 'No content changed'); } else { logger_1.logger.debug({ packageFile, depName }, 'Contents updated'); updatedFileContents[packageFile] = res; delete nonUpdatedFileContents[packageFile]; } continue; } else if (reuseExistingBranch) { return getUpdatedPackageFiles({ ...config, reuseExistingBranch: false, }); } logger_1.logger.error({ packageFile, depName }, 'Could not autoReplace'); throw new Error(error_messages_1.WORKER_FILE_UPDATE_FAILED); } let newContent = await updateDependency({ fileContent: packageFileContent, upgrade, }); newContent = await applyManagerBumpPackageVersion(newContent, upgrade); if (!newContent) { if (reuseExistingBranch) { logger_1.logger.debug({ packageFile, depName }, 'Rebasing branch after error updating content'); return getUpdatedPackageFiles({ ...config, reuseExistingBranch: false, }); } logger_1.logger.debug({ existingContent: packageFileContent, config: upgrade }, 'Error updating file'); throw new Error(error_messages_1.WORKER_FILE_UPDATE_FAILED); } if (newContent !== packageFileContent) { if (reuseExistingBranch) { // This ensure it's always 1 commit from the bot logger_1.logger.debug({ packageFile, depName }, 'Need to update package file so will rebase first'); return getUpdatedPackageFiles({ ...config, reuseExistingBranch: false, }); } logger_1.logger.debug(`Updating ${depName} in ${(0, string_1.coerceString)(packageFile, lockFile)}`); updatedFileContents[packageFile] = newContent; delete nonUpdatedFileContents[packageFile]; } if (newContent === packageFileContent) { if (upgrade.manager === 'git-submodules') { updatedFileContents[packageFile] = newContent; delete nonUpdatedFileContents[packageFile]; } } } } const updatedPackageFiles = Object.keys(updatedFileContents).map((name) => ({ type: 'addition', path: name, contents: updatedFileContents[name], })); const updatedArtifacts = []; const artifactErrors = []; const artifactNotices = []; if (is_1.default.nonEmptyArray(updatedPackageFiles)) { logger_1.logger.debug('updateArtifacts for updatedPackageFiles'); const updatedPackageFileManagers = getManagersForPackageFiles(updatedPackageFiles, managerPackageFiles); for (const manager of updatedPackageFileManagers) { const packageFilesForManager = getPackageFilesForManager(updatedPackageFiles, managerPackageFiles[manager]); sortPackageFiles(config, manager, packageFilesForManager); for (const packageFile of packageFilesForManager) { const updatedDeps = packageFileUpdatedDeps[packageFile.path]; const results = await managerUpdateArtifacts(manager, { packageFileName: packageFile.path, updatedDeps, // TODO #22198 newPackageFileContent: packageFile.contents.toString(), config: patchConfigForArtifactsUpdate(config, manager, packageFile.path), }); processUpdateArtifactResults(results, updatedArtifacts, artifactErrors, artifactNotices); } } } const nonUpdatedPackageFiles = Object.keys(nonUpdatedFileContents).map((name) => ({ type: 'addition', path: name, contents: nonUpdatedFileContents[name], })); if (is_1.default.nonEmptyArray(nonUpdatedPackageFiles)) { logger_1.logger.debug('updateArtifacts for nonUpdatedPackageFiles'); const nonUpdatedPackageFileManagers = getManagersForPackageFiles(nonUpdatedPackageFiles, managerPackageFiles); for (const manager of nonUpdatedPackageFileManagers) { const packageFilesForManager = getPackageFilesForManager(nonUpdatedPackageFiles, managerPackageFiles[manager]); sortPackageFiles(config, manager, packageFilesForManager); for (const packageFile of packageFilesForManager) { const updatedDeps = packageFileUpdatedDeps[packageFile.path]; const results = await managerUpdateArtifacts(manager, { packageFileName: packageFile.path, updatedDeps, // TODO #22198 newPackageFileContent: packageFile.contents.toString(), config: patchConfigForArtifactsUpdate(config, manager, packageFile.path), }); processUpdateArtifactResults(results, updatedArtifacts, artifactErrors, artifactNotices); if (is_1.default.nonEmptyArray(results)) { updatedPackageFiles.push(packageFile); } } } } if (!reuseExistingBranch) { const lockFileMaintenancePackageFiles = lockFileMaintenanceFiles.map((name) => ({ path: name, })); // Only perform lock file maintenance if it's a fresh commit if (is_1.default.nonEmptyArray(lockFileMaintenanceFiles)) { logger_1.logger.debug('updateArtifacts for lockFileMaintenanceFiles'); const lockFileMaintenanceManagers = getManagersForPackageFiles(lockFileMaintenancePackageFiles, managerPackageFiles); for (const manager of lockFileMaintenanceManagers) { const packageFilesForManager = getPackageFilesForManager(lockFileMaintenancePackageFiles, managerPackageFiles[manager]); sortPackageFiles(config, manager, packageFilesForManager); for (const packageFile of packageFilesForManager) { const contents = updatedFileContents[packageFile.path] || (await (0, git_1.getFile)(packageFile.path, config.baseBranch)); const results = await managerUpdateArtifacts(manager, { packageFileName: packageFile.path, updatedDeps: [], newPackageFileContent: contents, config: patchConfigForArtifactsUpdate(config, manager, packageFile.path), }); processUpdateArtifactResults(results, updatedArtifacts, artifactErrors, artifactNotices); } } } } return { reuseExistingBranch, // Need to overwrite original config updatedPackageFiles, updatedArtifacts, artifactErrors, artifactNotices, }; } // workaround, see #27319 function patchConfigForArtifactsUpdate(config, manager, packageFileName) { // drop any lockFiles that happen to be defined on the branch config const { lockFiles, ...updatedConfig } = config; if (is_1.default.nonEmptyArray(updatedConfig.packageFiles?.[manager])) { const managerPackageFiles = updatedConfig.packageFiles?.[manager]; const packageFile = managerPackageFiles.find((p) => p.packageFile === packageFileName); if (packageFile && is_1.default.nonEmptyArray(packageFile.lockFiles)) { updatedConfig.lockFiles = packageFile.lockFiles; } } return updatedConfig; } async function managerUpdateArtifacts(manager, updateArtifact) { const updateArtifacts = (0, manager_1.get)(manager, 'updateArtifacts'); if (!updateArtifacts) { return null; } if (updateArtifact.config.skipArtifactsUpdate) { logger_1.logger.debug({ manager, packageFileName: updateArtifact.packageFileName }, 'Skipping artifact update'); return null; } return await updateArtifacts(updateArtifact); } function processUpdateArtifactResults(results, updatedArtifacts, artifactErrors, artifactNotices) { if (is_1.default.nonEmptyArray(results)) { for (const res of results) { const { file, notice, artifactError } = res; if (file) { updatedArtifacts.push(file); } if (artifactError) { artifactErrors.push(artifactError); } if (notice) { artifactNotices.push(notice); } } } } async function applyManagerBumpPackageVersion(packageFileContent, upgrade) { const bumpPackageVersion = (0, manager_1.get)(upgrade.manager, 'bumpPackageVersion'); if (!bumpPackageVersion || !packageFileContent || !upgrade.bumpVersion || !upgrade.packageFileVersion) { return packageFileContent; } const result = await bumpPackageVersion(packageFileContent, upgrade.packageFileVersion, upgrade.bumpVersion, upgrade.packageFile); return result.bumpedContent; } //# sourceMappingURL=get-updated.js.map