UNPKG

renovate

Version:

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

816 lines • 39.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processBranch = processBranch; const tslib_1 = require("tslib"); const is_1 = tslib_1.__importDefault(require("@sindresorhus/is")); const luxon_1 = require("luxon"); const global_1 = require("../../../../config/global"); const error_messages_1 = require("../../../../constants/error-messages"); const logger_1 = require("../../../../logger"); const post_update_1 = require("../../../../modules/manager/npm/post-update"); const platform_1 = require("../../../../modules/platform"); const comment_1 = require("../../../../modules/platform/comment"); const scm_1 = require("../../../../modules/platform/scm"); const external_host_error_1 = require("../../../../types/errors/external-host-error"); const date_1 = require("../../../../util/date"); const emoji_1 = require("../../../../util/emoji"); const merge_confidence_1 = require("../../../../util/merge-confidence"); const number_1 = require("../../../../util/number"); const pretty_time_1 = require("../../../../util/pretty-time"); const template = tslib_1.__importStar(require("../../../../util/template")); const limits_1 = require("../../../global/limits"); const changelog_1 = require("../../changelog"); const pr_1 = require("../pr"); const automerge_1 = require("../pr/automerge"); const artifacts_1 = require("./artifacts"); const automerge_2 = require("./automerge"); const bump_versions_1 = require("./bump-versions"); const check_existing_1 = require("./check-existing"); const commit_1 = require("./commit"); const execute_post_upgrade_commands_1 = tslib_1.__importDefault(require("./execute-post-upgrade-commands")); const get_updated_1 = require("./get-updated"); const handle_existing_1 = require("./handle-existing"); const reuse_1 = require("./reuse"); const schedule_1 = require("./schedule"); const status_checks_1 = require("./status-checks"); async function rebaseCheck(config, branchPr) { const titleRebase = branchPr.title?.startsWith('rebase!'); if (titleRebase) { logger_1.logger.debug(`Manual rebase requested via PR title for #${branchPr.number}`); return true; } const labelRebase = !!branchPr.labels?.includes(config.rebaseLabel); if (labelRebase) { logger_1.logger.debug(`Manual rebase requested via PR labels for #${branchPr.number}`); /* v8 ignore start -- needs test */ if (global_1.GlobalConfig.get('dryRun')) { logger_1.logger.info(`DRY-RUN: Would delete label ${config.rebaseLabel} from #${branchPr.number}`); /* v8 ignore stop -- needs test */ } else { await platform_1.platform.deleteLabel(branchPr.number, config.rebaseLabel); } return true; } const prRebaseChecked = !!branchPr.bodyStruct?.rebaseRequested; if (prRebaseChecked) { logger_1.logger.debug(`Manual rebase requested via PR checkbox for #${branchPr.number}`); return true; } return false; } async function deleteBranchSilently(branchName) { try { await scm_1.scm.deleteBranch(branchName); /* v8 ignore start -- needs test */ } catch (err) { logger_1.logger.debug({ branchName, err }, 'Branch auto-remove failed'); } /* v8 ignore stop -- needs test */ } function userChangedTargetBranch(pr) { const oldTargetBranch = pr.bodyStruct?.debugData?.targetBranch; if (oldTargetBranch && pr.targetBranch) { return pr.targetBranch !== oldTargetBranch; } return false; } async function processBranch(branchConfig, forceRebase = false) { let commitSha = null; let config = { ...branchConfig }; logger_1.logger.trace({ config }, 'processBranch()'); let branchExists = await scm_1.scm.branchExists(config.branchName); const dependencyDashboardCheck = config.dependencyDashboardChecks?.[config.branchName]; let updatesVerified = false; if (!branchExists && config.branchPrefix !== config.branchPrefixOld) { const branchName = config.branchName.replace(config.branchPrefix, config.branchPrefixOld); branchExists = await scm_1.scm.branchExists(branchName); if (branchExists) { config.branchName = branchName; logger_1.logger.debug('Found existing branch with branchPrefixOld'); } } if (!branchExists && branchConfig.minimumGroupSize && branchConfig.minimumGroupSize > branchConfig.upgrades.length && !dependencyDashboardCheck) { logger_1.logger.debug(`Skipping branch creation as minimumGroupSize: ${branchConfig.minimumGroupSize} is not met`); return { branchExists: false, result: 'minimum-group-size-not-met', }; } let branchPr = await platform_1.platform.getBranchPr(config.branchName, config.baseBranch); logger_1.logger.debug(`branchExists=${branchExists}`); logger_1.logger.debug(`dependencyDashboardCheck=${dependencyDashboardCheck}`); if (branchPr) { config.rebaseRequested = await rebaseCheck(config, branchPr); logger_1.logger.debug(`PR rebase requested=${config.rebaseRequested}`); } const keepUpdatedLabel = config.keepUpdatedLabel; const artifactErrorTopic = (0, emoji_1.emojify)(':warning: Artifact update problem'); const artifactNoticeTopic = (0, emoji_1.emojify)(':information_source: Artifact update notice'); try { // Check if branch already existed const existingPr = !branchPr || config.automerge ? await (0, check_existing_1.prAlreadyExisted)(config) : undefined; if (existingPr?.state === 'merged') { logger_1.logger.debug(`Matching PR #${existingPr.number} was merged previously`); if (config.automerge) { logger_1.logger.debug('Disabling automerge because PR was merged previously'); config.automerge = false; config.automergedPreviously = true; } } else if (!branchPr && existingPr && !dependencyDashboardCheck) { logger_1.logger.debug({ prTitle: config.prTitle }, 'Closed PR already exists. Skipping branch.'); await (0, handle_existing_1.handleClosedPr)(config, existingPr); return { branchExists: false, prNo: existingPr.number, result: 'already-existed', }; } if (!branchExists && branchConfig.pendingChecks && !dependencyDashboardCheck) { logger_1.logger.debug(`Branch ${config.branchName} creation is disabled because internalChecksFilter was not met`); return { branchExists: false, result: 'pending', }; } if (!branchExists) { if (config.mode === 'silent' && !dependencyDashboardCheck) { logger_1.logger.debug(`Branch ${config.branchName} creation is disabled because mode=silent`); return { branchExists, result: 'needs-approval', }; } if (config.dependencyDashboardApproval && !dependencyDashboardCheck) { logger_1.logger.debug(`Branch ${config.branchName} creation is disabled because dependencyDashboardApproval=true`); return { branchExists, result: 'needs-approval', }; } } logger_1.logger.debug(`Open PR Count: ${(0, limits_1.getCount)('ConcurrentPRs')}, Existing Branch Count: ${(0, limits_1.getCount)('Branches')}, Hourly PR Count: ${(0, limits_1.getCount)('HourlyPRs')}`); if (!branchExists && (0, limits_1.isLimitReached)('Branches', branchConfig) && !dependencyDashboardCheck && !config.isVulnerabilityAlert) { logger_1.logger.debug('Reached branch limit - skipping branch creation'); return { branchExists, result: 'branch-limit-reached', }; } if ((0, limits_1.isLimitReached)('Commits') && !dependencyDashboardCheck && !config.isVulnerabilityAlert) { logger_1.logger.debug('Reached commits limit - skipping branch'); return { branchExists, prNo: branchPr?.number, result: 'commit-limit-reached', }; } if (branchExists) { // check if branch is labelled to stop config.stopUpdating = branchPr?.labels?.includes(config.stopUpdatingLabel); const prRebaseChecked = !!branchPr?.bodyStruct?.rebaseRequested; if (branchExists && !dependencyDashboardCheck && config.stopUpdating) { if (!prRebaseChecked) { logger_1.logger.info('Branch updating is skipped because stopUpdatingLabel is present in config'); return { branchExists: true, prNo: branchPr?.number, result: 'no-work', }; } } logger_1.logger.debug('Checking if PR has been edited'); const branchIsModified = await scm_1.scm.isBranchModified(config.branchName, config.baseBranch); if (branchPr) { logger_1.logger.debug('Found existing branch PR'); if (branchPr.state !== 'open') { logger_1.logger.debug('PR has been closed or merged since this run started - aborting'); throw new Error(error_messages_1.REPOSITORY_CHANGED); } if (branchIsModified || userChangedTargetBranch(branchPr)) { logger_1.logger.debug(`PR has been edited, PrNo:${branchPr.number}`); await (0, handle_existing_1.handleModifiedPr)(config, branchPr); if (!(!!dependencyDashboardCheck || config.rebaseRequested)) { return { branchExists, prNo: branchPr.number, result: 'pr-edited', }; } } } else if (branchIsModified) { const oldPr = await platform_1.platform.findPr({ branchName: config.branchName, state: '!open', targetBranch: config.baseBranch, }); if (!oldPr) { logger_1.logger.debug('Branch has been edited but found no PR - skipping'); return { branchExists, result: 'pr-edited', }; } const branchSha = await scm_1.scm.getBranchCommit(config.branchName); const oldPrSha = oldPr?.sha; if (!oldPrSha || oldPrSha === branchSha) { logger_1.logger.debug({ oldPrNumber: oldPr.number, oldPrSha, branchSha }, 'Found old PR matching this branch - will override it'); } else { logger_1.logger.debug({ oldPrNumber: oldPr.number, oldPrSha, branchSha }, 'Found old PR but the SHA is different'); return { branchExists, result: 'pr-edited', }; } } } // Check schedule config.isScheduledNow = (0, schedule_1.isScheduledNow)(config, 'schedule'); if (!config.isScheduledNow && !dependencyDashboardCheck) { if (!branchExists) { logger_1.logger.debug('Skipping branch creation as not within schedule'); return { branchExists, result: 'not-scheduled', }; } if (config.updateNotScheduled === false && !config.rebaseRequested) { logger_1.logger.debug('Skipping branch update as not within schedule'); return { branchExists, prNo: branchPr?.number, result: 'update-not-scheduled', }; } if (!branchPr && !(config.automerge && config.automergeType === 'branch') // if branch is configured for automerge there's no need for a PR ) { logger_1.logger.debug('Skipping PR creation out of schedule'); return { branchExists, result: 'not-scheduled', }; } logger_1.logger.debug('Branch + PR exists but is not scheduled -- will update if necessary'); } //stability checks if (config.upgrades.some((upgrade) => (is_1.default.nonEmptyString(upgrade.minimumReleaseAge) && is_1.default.nonEmptyString(upgrade.releaseTimestamp)) || (0, merge_confidence_1.isActiveConfidenceLevel)(upgrade.minimumConfidence))) { // Only set a stability status check if one or more of the updates contain // both a minimumReleaseAge setting and a releaseTimestamp config.stabilityStatus = 'green'; // Default to 'success' but set 'pending' if any update is pending for (const upgrade of config.upgrades) { if (is_1.default.nonEmptyString(upgrade.minimumReleaseAge) && upgrade.releaseTimestamp) { const timeElapsed = (0, date_1.getElapsedMs)(upgrade.releaseTimestamp); if (timeElapsed < (0, number_1.coerceNumber)((0, pretty_time_1.toMs)(upgrade.minimumReleaseAge))) { logger_1.logger.debug({ depName: upgrade.depName, timeElapsed, minimumReleaseAge: upgrade.minimumReleaseAge, }, 'Update has not passed minimum release age'); config.stabilityStatus = 'yellow'; continue; } } const datasource = upgrade.datasource; const depName = upgrade.depName; const minimumConfidence = upgrade.minimumConfidence; const updateType = upgrade.updateType; const currentVersion = upgrade.currentVersion; const newVersion = upgrade.newVersion; if ((0, merge_confidence_1.isActiveConfidenceLevel)(minimumConfidence)) { const confidence = (await (0, merge_confidence_1.getMergeConfidenceLevel)(datasource, depName, currentVersion, newVersion, updateType)) ?? 'neutral'; if ((0, merge_confidence_1.satisfiesConfidenceLevel)(confidence, minimumConfidence)) { config.confidenceStatus = 'green'; } else { logger_1.logger.debug({ depName, confidence, minimumConfidence }, 'Update does not meet minimum confidence scores'); config.confidenceStatus = 'yellow'; continue; } } } // Don't create a branch if we know it will be status 'pending' if (!dependencyDashboardCheck && !branchExists && config.stabilityStatus === 'yellow' && ['not-pending', 'status-success'].includes(config.prCreation)) { logger_1.logger.debug('Skipping branch creation due to internal status checks not met'); return { branchExists, result: 'pending', }; } } let userRebaseRequested = dependencyDashboardCheck === 'rebase' || !!config.dependencyDashboardRebaseAllOpen || !!config.rebaseRequested; const userApproveAllPendingPR = !!config.dependencyDashboardAllPending; const userOpenAllRateLimtedPR = !!config.dependencyDashboardAllRateLimited; if (forceRebase) { logger_1.logger.debug('Force rebase because branch needs updating'); config.reuseExistingBranch = false; } else if (userRebaseRequested) { logger_1.logger.debug('User has requested rebase'); config.reuseExistingBranch = false; } else if (dependencyDashboardCheck === 'global-config') { logger_1.logger.debug(`Manual create/rebase requested via checkedBranches`); config.reuseExistingBranch = false; userRebaseRequested = true; } else if (userApproveAllPendingPR) { logger_1.logger.debug('A user manually approved all pending PRs via the Dependency Dashboard.'); } else if (userOpenAllRateLimtedPR) { logger_1.logger.debug('A user manually approved all rate-limited PRs via the Dependency Dashboard.'); } else if (branchExists && config.rebaseWhen === 'never' && !(keepUpdatedLabel && branchPr?.labels?.includes(keepUpdatedLabel)) && !dependencyDashboardCheck) { logger_1.logger.debug('rebaseWhen=never so skipping branch update check'); return { branchExists, prNo: branchPr?.number, result: 'no-work', }; } // if the base branch has been changed by user in renovate config, rebase onto the new baseBranch // we have already confirmed earlier that branch isn't modified, so its safe to use targetBranch here else if (branchPr?.targetBranch && branchPr.targetBranch !== config.baseBranch) { logger_1.logger.debug('Base branch changed by user, rebasing the branch onto new base'); config.reuseExistingBranch = false; } else if (config.cacheFingerprintMatch === 'no-match') { logger_1.logger.debug('Cache fingerprint does not match, cannot reuse existing branch'); config.reuseExistingBranch = false; } else { config = await (0, reuse_1.shouldReuseExistingBranch)(config); } // TODO: types (#22198) logger_1.logger.debug(`Using reuseExistingBranch: ${config.reuseExistingBranch}`); if (!(config.reuseExistingBranch && config.cacheFingerprintMatch === 'matched')) { await scm_1.scm.checkoutBranch(config.baseBranch); const res = await (0, get_updated_1.getUpdatedPackageFiles)(config); if (res.artifactErrors && config.artifactErrors) { res.artifactErrors = config.artifactErrors.concat(res.artifactErrors); } config = { ...config, ...res }; if (config.updatedPackageFiles?.length) { logger_1.logger.debug(`Updated ${config.updatedPackageFiles.length} package files`); if (config.reuseExistingBranch && !forceRebase) { logger_1.logger.debug('Existing branch needs updating. Restarting processBranch() with a clean branch'); return processBranch(branchConfig, true); } } else { logger_1.logger.debug('No package files need updating'); } const additionalFiles = await (0, post_update_1.getAdditionalFiles)(config, branchConfig.packageFiles); config.artifactErrors = (config.artifactErrors ?? []).concat(additionalFiles.artifactErrors); config.updatedArtifacts = (config.updatedArtifacts ?? []).concat(additionalFiles.updatedArtifacts); if (config.updatedArtifacts?.length) { logger_1.logger.debug({ updatedArtifacts: config.updatedArtifacts.map((f) => f.type === 'deletion' ? `${f.path} (delete)` : f.path), }, `Updated ${config.updatedArtifacts.length} lock files`); if (config.reuseExistingBranch && !forceRebase) { logger_1.logger.debug('Existing branch needs updating. Restarting processBranch() with a clean branch'); return processBranch(branchConfig, true); } } else { logger_1.logger.debug('No updated lock files in branch'); } if (config.fetchChangeLogs === 'branch') { await (0, changelog_1.embedChangelogs)(config.upgrades); } const postUpgradeCommandResults = await (0, execute_post_upgrade_commands_1.default)(config); if (postUpgradeCommandResults !== null) { const { updatedArtifacts, artifactErrors } = postUpgradeCommandResults; config.updatedArtifacts = updatedArtifacts; config.artifactErrors = artifactErrors; } // modifies the file changes in place to allow having a version bump in a packageFile or artifact await (0, bump_versions_1.bumpVersions)(config); (0, logger_1.removeMeta)(['dep']); if (config.artifactErrors?.length) { if (config.releaseTimestamp) { logger_1.logger.debug(`Branch timestamp: ` + config.releaseTimestamp); const releaseTimestamp = luxon_1.DateTime.fromISO(config.releaseTimestamp); if (releaseTimestamp.plus({ hours: 2 }) < luxon_1.DateTime.local()) { logger_1.logger.debug('PR is older than 2 hours, raise PR with lock file errors'); } else if (branchExists) { logger_1.logger.debug('PR is less than 2 hours old but branchExists so updating anyway'); } else { logger_1.logger.debug('PR is less than 2 hours old - raise error instead of PR'); throw new Error(error_messages_1.MANAGER_LOCKFILE_ERROR); } } else { logger_1.logger.debug('PR has no releaseTimestamp'); } } else if (config.updatedArtifacts?.length && branchPr) { // If there are artifacts, no errors, and an existing PR then ensure any artifacts error comment is removed if (global_1.GlobalConfig.get('dryRun')) { logger_1.logger.info(`DRY-RUN: Would ensure comment removal in PR #${branchPr.number}`); } else { // Remove artifacts error comment only if this run has successfully updated artifacts await (0, comment_1.ensureCommentRemoval)({ type: 'by-topic', number: branchPr.number, topic: artifactErrorTopic, }); if (!config.artifactNotices?.length) { await (0, comment_1.ensureCommentRemoval)({ type: 'by-topic', number: branchPr.number, topic: artifactNoticeTopic, }); } } } const forcedManually = userRebaseRequested || !branchExists; config.isConflicted ??= branchExists && (await scm_1.scm.isBranchConflicted(config.baseBranch, config.branchName)); config.forceCommit = forcedManually || config.isConflicted; // compile commit message with body, which maybe needs changelogs if (config.commitBody) { // changelog is on first upgrade config.commitMessage = `${config.commitMessage}\n\n${template.compile(config.commitBody, { ...config, logJSON: config.upgrades[0].logJSON, releases: config.upgrades[0].releases, })}`; logger_1.logger.trace(`commitMessage: ` + JSON.stringify(config.commitMessage)); } commitSha = await (0, commit_1.commitFilesToBranch)(config); // Checkout to base branch to ensure that the next branch processing always starts with git being on the baseBranch // baseBranch is not checked out at the start of processBranch() due to pull/16246 await scm_1.scm.checkoutBranch(config.baseBranch); updatesVerified = true; } if (branchPr) { const platformPrOptions = (0, pr_1.getPlatformPrOptions)(config); if (platformPrOptions.usePlatformAutomerge && platform_1.platform.reattemptPlatformAutomerge) { if (global_1.GlobalConfig.get('dryRun')) { logger_1.logger.info(`DRY-RUN: Would reattempt platform automerge for PR #${branchPr.number}`); } else { await platform_1.platform.reattemptPlatformAutomerge({ number: branchPr.number, platformPrOptions, }); } } if (platform_1.platform.refreshPr) { await platform_1.platform.refreshPr(branchPr.number); } } if (!commitSha && !branchExists) { return { branchExists, result: 'no-work', }; } if (commitSha) { const action = branchExists ? 'updated' : 'created'; logger_1.logger.info({ commitSha }, `Branch ${action}`); } // Set branch statuses await (0, artifacts_1.setArtifactErrorStatus)(config); await (0, status_checks_1.setStability)(config); await (0, status_checks_1.setConfidence)(config); // new commit means status check are pretty sure pending but maybe not reported yet // if PR has not been created + new commit + prCreation !== immediate skip // but do not break when there are artifact errors if (!branchPr && !config.artifactErrors?.length && !userRebaseRequested && commitSha && config.prCreation !== 'immediate') { logger_1.logger.debug(`Branch status pending, current sha: ${commitSha}`); return { branchExists: true, updatesVerified, result: 'pending', commitSha, }; } // Try to automerge branch and finish if successful, but only if branch already existed before this run // skip if we have a non-immediate pr and there is an existing PR, // we want to update the PR and skip the Auto merge since status checks aren't done yet if (!config.artifactErrors?.length && (!commitSha || config.ignoreTests)) { const mergeStatus = await (0, automerge_2.tryBranchAutomerge)(config); logger_1.logger.debug(`mergeStatus=${mergeStatus}`); if (mergeStatus === 'automerged') { if (global_1.GlobalConfig.get('dryRun')) { logger_1.logger.info('DRY-RUN: Would delete branch' + config.branchName); } else { await deleteBranchSilently(config.branchName); } logger_1.logger.debug('Branch is automerged - returning'); return { branchExists: false, result: 'automerged' }; } if (mergeStatus === 'off schedule') { if (userRebaseRequested) { config.forcePr = true; } else { logger_1.logger.debug('Branch cannot automerge now because automergeSchedule is off schedule - skipping'); return { branchExists, result: 'not-scheduled', commitSha, }; } } if (mergeStatus === 'stale' && ['conflicted', 'never'].includes(config.rebaseWhen) && /* v8 ignore next -- needs test */ !(keepUpdatedLabel && branchPr?.labels?.includes(keepUpdatedLabel))) { logger_1.logger.warn('Branch cannot automerge because it is behind base branch and rebaseWhen setting disallows rebasing - raising a PR instead'); config.forcePr = true; config.branchAutomergeFailureMessage = mergeStatus; } if (mergeStatus === 'automerge aborted - PR exists' || mergeStatus === 'branch status error' || mergeStatus === 'failed') { logger_1.logger.debug(`Branch automerge not possible, mergeStatus:${mergeStatus}`); config.forcePr = true; config.branchAutomergeFailureMessage = mergeStatus; } } /* v8 ignore start -- needs test */ } catch (err) { if (err.statusCode === 404) { logger_1.logger.debug({ err }, 'Received a 404 error - aborting run'); throw new Error(error_messages_1.REPOSITORY_CHANGED); } if (err.message === error_messages_1.PLATFORM_RATE_LIMIT_EXCEEDED) { logger_1.logger.debug('Passing rate-limit-exceeded error up'); throw err; } if (err.message === error_messages_1.REPOSITORY_CHANGED) { logger_1.logger.debug('Passing repository-changed error up'); throw err; } if (err.message?.startsWith('remote: Invalid username or password')) { logger_1.logger.debug('Throwing bad credentials'); throw new Error(error_messages_1.PLATFORM_BAD_CREDENTIALS); } if (err.message?.startsWith('ssh_exchange_identification: Connection closed by remote host')) { logger_1.logger.debug('Throwing bad credentials'); throw new Error(error_messages_1.PLATFORM_BAD_CREDENTIALS); } if (err.message === error_messages_1.PLATFORM_BAD_CREDENTIALS) { logger_1.logger.debug('Passing bad-credentials error up'); throw err; } if (err.message === error_messages_1.PLATFORM_INTEGRATION_UNAUTHORIZED) { logger_1.logger.debug('Passing integration-unauthorized error up'); throw err; } if (err.message === error_messages_1.MANAGER_LOCKFILE_ERROR) { logger_1.logger.debug('Passing lockfile-error up'); throw err; } if (err.message?.includes('space left on device')) { throw new Error(error_messages_1.SYSTEM_INSUFFICIENT_DISK_SPACE); } if (err.message === error_messages_1.SYSTEM_INSUFFICIENT_DISK_SPACE) { logger_1.logger.debug('Passing disk-space error up'); throw err; } if (err.message.startsWith('Resource not accessible by integration')) { logger_1.logger.debug('Passing 403 error up'); throw err; } if (err.message === error_messages_1.WORKER_FILE_UPDATE_FAILED) { logger_1.logger.warn('Error updating branch: update failure'); } else if (err.message.startsWith('bundler-')) { // we have already warned inside the bundler artifacts error handling, so just return return { branchExists: true, updatesVerified, prNo: branchPr?.number, result: 'error', commitSha, }; } else if (err.messagee && err.message.includes('fatal: Authentication failed')) { throw new Error(error_messages_1.PLATFORM_AUTHENTICATION_ERROR); } else if (err.message?.includes('fatal: bad revision')) { logger_1.logger.debug({ err }, 'Aborting job due to bad revision error'); throw new Error(error_messages_1.REPOSITORY_CHANGED); } else if (err.message === error_messages_1.CONFIG_VALIDATION) { logger_1.logger.debug('Passing config validation error up'); throw err; } else if (err.message === error_messages_1.TEMPORARY_ERROR) { logger_1.logger.debug('Passing TEMPORARY_ERROR error up'); throw err; } else if (!(err instanceof external_host_error_1.ExternalHostError)) { logger_1.logger.warn({ err }, `Error updating branch`); } // Don't throw here - we don't want to stop the other renovations return { branchExists, prNo: branchPr?.number, result: 'error', commitSha, }; } /* v8 ignore stop -- needs test */ try { logger_1.logger.debug('Ensuring PR'); logger_1.logger.debug(`There are ${config.errors.length} errors and ${config.warnings.length} warnings`); const ensurePrResult = await (0, pr_1.ensurePr)(config); if (ensurePrResult.type === 'without-pr') { const { prBlockedBy } = ensurePrResult; branchPr = null; if (prBlockedBy === 'RateLimited' && !config.isVulnerabilityAlert) { logger_1.logger.debug('Reached PR limit - skipping PR creation'); return { branchExists, prBlockedBy, result: 'pr-limit-reached', commitSha, }; } // TODO: ensurePr should check for automerge itself (#9719) if (prBlockedBy === 'NeedsApproval') { return { branchExists, prBlockedBy, result: 'needs-pr-approval', commitSha, }; } if (prBlockedBy === 'AwaitingTests') { return { branchExists, prBlockedBy, result: 'pending', commitSha, }; } if (prBlockedBy === 'BranchAutomerge') { return { branchExists, prBlockedBy, result: 'done', commitSha, }; } if (prBlockedBy === 'Error') { return { branchExists, prBlockedBy, result: 'error', commitSha, }; } logger_1.logger.warn({ prBlockedBy }, 'Unknown PrBlockedBy result'); return { branchExists, prBlockedBy, result: 'error', commitSha, }; } if (ensurePrResult.type === 'with-pr') { const { pr } = ensurePrResult; branchPr = pr; if (config.artifactErrors?.length) { logger_1.logger.warn({ artifactErrors: config.artifactErrors }, 'artifactErrors'); let content = `Renovate failed to update `; content += config.artifactErrors.length > 1 ? 'artifacts' : 'an artifact'; content += ' related to this branch. '; content += template.compile(config.userStrings.artifactErrorWarning, config); content += (0, emoji_1.emojify)(`\n\n:recycle: Renovate will retry this branch, including artifacts, only when one of the following happens:\n\n`); content += ' - any of the package files in this branch needs updating, or \n'; content += ' - the branch becomes conflicted, or\n'; content += ' - you click the rebase/retry checkbox if found above, or\n'; content += ' - you rename this PR\'s title to start with "rebase!" to trigger it manually'; content += '\n\nThe artifact failure details are included below:\n\n'; // TODO: types (#22198) config.artifactErrors.forEach((error) => { content += `##### File name: ${error.lockFile}\n\n`; content += `\`\`\`\n${error.stderr}\n\`\`\`\n\n`; }); content = platform_1.platform.massageMarkdown(content, config.rebaseLabel); if (!(config.suppressNotifications.includes('artifactErrors') || config.suppressNotifications.includes('lockFileErrors'))) { if (global_1.GlobalConfig.get('dryRun')) { logger_1.logger.info(`DRY-RUN: Would ensure lock file error comment in PR #${pr.number}`); } else { await (0, comment_1.ensureComment)({ number: pr.number, topic: artifactErrorTopic, content, }); } } } else { if (config.artifactNotices?.length) { const contentLines = []; for (const notice of config.artifactNotices) { contentLines.push(`##### File name: ${notice.file}`); contentLines.push(notice.message); } const content = contentLines.join('\n\n'); await (0, comment_1.ensureComment)({ number: pr.number, topic: artifactNoticeTopic, content, }); } if (config.automerge) { logger_1.logger.debug('PR is configured for automerge'); // skip automerge if there is a new commit since status checks aren't done yet if (config.ignoreTests === true || !commitSha) { logger_1.logger.debug('checking auto-merge'); const prAutomergeResult = await (0, automerge_1.checkAutoMerge)(pr, config); if (prAutomergeResult?.automerged) { return { branchExists, result: 'automerged', commitSha, }; } } } else { logger_1.logger.debug('PR is not configured for automerge'); } } } /* v8 ignore start -- needs test */ } catch (err) { if (err instanceof external_host_error_1.ExternalHostError || [error_messages_1.PLATFORM_RATE_LIMIT_EXCEEDED, error_messages_1.REPOSITORY_CHANGED].includes(err.message)) { logger_1.logger.debug('Passing PR error up'); throw err; } // Otherwise don't throw here - we don't want to stop the other renovations logger_1.logger.error({ err }, `Error ensuring PR`); } /* v8 ignore stop -- needs test */ if (!branchExists) { return { branchExists: true, updatesVerified, prNo: branchPr?.number, result: 'pr-created', commitSha, }; } return { branchExists, updatesVerified, prNo: branchPr?.number, result: 'done', commitSha, }; } //# sourceMappingURL=index.js.map