renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
785 lines • 38.1 kB
JavaScript
;
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}`);
// istanbul ignore if
if (global_1.GlobalConfig.get('dryRun')) {
logger_1.logger.info(`DRY-RUN: Would delete label ${config.rebaseLabel} from #${branchPr.number}`);
}
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);
}
catch (err) /* istanbul ignore next */ {
logger_1.logger.debug({ branchName, err }, 'Branch auto-remove failed');
}
}
function userChangedTargetBranch(pr) {
const oldTargetBranch = pr.bodyStruct?.debugData?.targetBranch;
if (oldTargetBranch && pr.targetBranch) {
return pr.targetBranch !== oldTargetBranch;
}
return false;
}
async function processBranch(branchConfig) {
let commitSha = null;
let config = { ...branchConfig };
logger_1.logger.trace({ config }, 'processBranch()');
let branchExists = await scm_1.scm.branchExists(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');
}
}
let branchPr = await platform_1.platform.getBranchPr(config.branchName, config.baseBranch);
logger_1.logger.debug(`branchExists=${branchExists}`);
const dependencyDashboardCheck = config.dependencyDashboardChecks?.[config.branchName];
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,
prNo: branchPr?.number,
result: 'pending',
};
}
if (!branchExists) {
if (config.mode === 'silent' && !dependencyDashboardCheck) {
logger_1.logger.debug(`Branch ${config.branchName} creation is disabled because mode=silent`);
return {
branchExists,
prNo: branchPr?.number,
result: 'needs-approval',
};
}
if (config.dependencyDashboardApproval && !dependencyDashboardCheck) {
logger_1.logger.debug(`Branch ${config.branchName} creation is disabled because dependencyDashboardApproval=true`);
return {
branchExists,
prNo: branchPr?.number,
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,
prNo: branchPr?.number,
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,
prNo: branchPr?.number,
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,
prNo: branchPr?.number,
result: 'pending',
};
}
}
let userRebaseRequested = dependencyDashboardCheck === 'rebase' ||
!!config.dependencyDashboardRebaseAllOpen ||
!!config.rebaseRequested;
const userApproveAllPendingPR = !!config.dependencyDashboardAllPending;
const userOpenAllRateLimtedPR = !!config.dependencyDashboardAllRateLimited;
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 {
config = await (0, reuse_1.shouldReuseExistingBranch)(config);
}
// TODO: types (#22198)
logger_1.logger.debug(`Using reuseExistingBranch: ${config.reuseExistingBranch}`);
if (!(config.reuseExistingBranch && config.skipBranchUpdate)) {
await scm_1.scm.checkoutBranch(config.baseBranch);
const res = await (0, get_updated_1.getUpdatedPackageFiles)(config);
// istanbul ignore if
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`);
}
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`);
}
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
// istanbul ignore if
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) {
await platform_1.platform.reattemptPlatformAutomerge({
number: branchPr.number,
platformPrOptions,
});
}
// istanbul ignore if
if (platform_1.platform.refreshPr) {
await platform_1.platform.refreshPr(branchPr.number);
}
}
if (!commitSha && !branchExists) {
return {
branchExists,
prNo: branchPr?.number,
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') {
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) &&
!(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;
}
}
}
catch (err) /* istanbul ignore next */ {
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,
};
}
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. You probably do not want to merge this PR as-is.';
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);
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');
}
}
}
}
catch (err) /* istanbul ignore next */ {
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`);
}
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