UNPKG

renovate

Version:

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

150 lines • 7.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.pruneStaleBranches = pruneStaleBranches; const tslib_1 = require("tslib"); const is_1 = tslib_1.__importDefault(require("@sindresorhus/is")); const global_1 = require("../../../config/global"); const error_messages_1 = require("../../../constants/error-messages"); const logger_1 = require("../../../logger"); const platform_1 = require("../../../modules/platform"); const comment_1 = require("../../../modules/platform/comment"); const scm_1 = require("../../../modules/platform/scm"); const git_1 = require("../../../util/git"); const regex_1 = require("../../../util/regex"); const string_1 = require("../../../util/string"); const utils_1 = require("../reconfigure/utils"); async function cleanUpBranches(config, remainingBranches) { if (!config.pruneStaleBranches) { logger_1.logger.debug('Branch/PR pruning is disabled - skipping'); return; } // set Git author in case the repository is not initialized yet (0, git_1.setUserRepoConfig)(config); // calculate regex to extract base branch from branch name const baseBranchRe = calculateBaseBranchRegex(config); for (const branchName of remainingBranches) { try { // get base branch from branch name if base branches are configured // use default branch if no base branches are configured // use defaul branch name if no match (can happen when base branches are configured later) const baseBranch = baseBranchRe?.exec(branchName)?.[1] ?? config.defaultBranch; const pr = await platform_1.platform.findPr({ branchName, state: 'open', targetBranch: baseBranch, }); const branchIsModified = await scm_1.scm.isBranchModified(branchName, baseBranch); if (pr) { if (branchIsModified) { logger_1.logger.debug({ prNo: pr.number, prTitle: pr.title }, 'Branch is modified - skipping PR autoclosing'); if (global_1.GlobalConfig.get('dryRun')) { logger_1.logger.info(`DRY-RUN: Would update PR title and ensure comment.`); } else { if (!pr.title.endsWith('- abandoned')) { const newPrTitle = pr.title + ' - abandoned'; await platform_1.platform.updatePr({ number: pr.number, prTitle: newPrTitle, state: 'open', }); } await (0, comment_1.ensureComment)({ number: pr.number, topic: 'Autoclosing Skipped', content: 'This PR has been flagged for autoclosing. However, it is being skipped due to the branch being already modified. Please close/delete it manually or report a bug if you think this is in error.', }); } } else if (global_1.GlobalConfig.get('dryRun')) { logger_1.logger.info({ prNo: pr.number, prTitle: pr.title }, `DRY-RUN: Would autoclose PR`); } else { logger_1.logger.info({ branchName, prNo: pr.number, prTitle: pr.title }, 'Autoclosing PR'); let newPrTitle = pr.title; if (!pr.title.endsWith('- autoclosed')) { newPrTitle += ' - autoclosed'; } await platform_1.platform.updatePr({ number: pr.number, prTitle: newPrTitle, state: 'closed', }); await scm_1.scm.deleteBranch(branchName); } } else if (branchIsModified) { logger_1.logger.debug('Orphan Branch is modified - skipping branch deletion'); } else if (global_1.GlobalConfig.get('dryRun')) { logger_1.logger.info(`DRY-RUN: Would delete orphan branch ${branchName}`); } else { logger_1.logger.info({ branch: branchName }, `Deleting orphan branch`); await scm_1.scm.deleteBranch(branchName); } } catch (err) /* istanbul ignore next */ { if (err.message === 'config-validation') { logger_1.logger.debug('Cannot prune branch due to collision between tags and branch names'); } else if (err.message?.includes("bad revision 'origin/")) { logger_1.logger.debug({ branchName }, 'Branch not found on origin when attempting to prune'); } else if (err.message !== error_messages_1.REPOSITORY_CHANGED) { logger_1.logger.warn({ err, branch: branchName }, 'Error pruning branch'); } } } } /** * Calculates a {RegExp} to extract the base branch from a branch name if base branches are configured. * @param config Renovate configuration */ function calculateBaseBranchRegex(config) { if (!config.baseBranches?.length) { return null; } // calculate possible branch prefixes and escape for regex const branchPrefixes = [config.branchPrefix, config.branchPrefixOld] .filter(is_1.default.nonEmptyStringAndNotWhitespace) .filter(string_1.uniqueStrings) .map(regex_1.escapeRegExp); // calculate possible base branches and escape for regex const baseBranches = config.baseBranches.map(regex_1.escapeRegExp); // create regex to extract base branche from branch name const baseBranchRe = (0, regex_1.regEx)(`^(?:${branchPrefixes.join('|')})(${baseBranches.join('|')})-`); return baseBranchRe; } async function pruneStaleBranches(config, branchList) { logger_1.logger.debug('Removing any stale branches'); logger_1.logger.trace({ config }, `pruneStaleBranches`); // TODO: types (#22198) logger_1.logger.debug(`config.repoIsOnboarded=${config.repoIsOnboarded}`); if (!branchList) { logger_1.logger.debug('No branchList'); return; } // TODO: types (#22198) let renovateBranches = (0, git_1.getBranchList)().filter((branchName) => branchName.startsWith(config.branchPrefix) && branchName !== (0, utils_1.getReconfigureBranchName)(config.branchPrefix)); if (!renovateBranches?.length) { logger_1.logger.debug('No renovate branches found'); return; } logger_1.logger.debug({ branchList: branchList?.sort(), renovateBranches: renovateBranches?.sort(), }, 'Branch lists'); // TODO: types (#22198) const lockFileBranch = `${config.branchPrefix}lock-file-maintenance`; renovateBranches = renovateBranches.filter((branch) => branch !== lockFileBranch); const remainingBranches = renovateBranches.filter((branch) => !branchList.includes(branch)); logger_1.logger.debug(`remainingBranches=${String(remainingBranches)}`); if (remainingBranches.length === 0) { logger_1.logger.debug('No branches to clean up'); return; } await cleanUpBranches(config, remainingBranches); } //# sourceMappingURL=prune.js.map