UNPKG

renovate

Version:

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

182 lines (178 loc) • 9.31 kB
import { REPOSITORY_CLOSED_ONBOARDING } from "../../../../constants/error-messages.js"; import { GlobalConfig } from "../../../../config/global.js"; import { logger } from "../../../../logger/index.js"; import { getInheritedOrGlobal } from "../../../../util/common.js"; import { compile } from "../../../../util/template/index.js"; import { toSha256 } from "../../../../util/hash.js"; import { getFile } from "../../../../util/git/index.js"; import { getElapsedDays } from "../../../../util/date.js"; import { emojify } from "../../../../util/emoji.js"; import { hashBody } from "../../../../modules/platform/pr-body.js"; import { scm } from "../../../../modules/platform/scm.js"; import { platform } from "../../../../modules/platform/index.js"; import { isOnboardingBranchConflicted } from "../branch/onboarding-branch-cache.js"; import { OnboardingState, getDefaultConfigFileName, getSemanticCommitPrTitle } from "../common.js"; import { ensureComment } from "../../../../modules/platform/comment.js"; import { getDepWarningsOnboardingPR, getErrors, getWarnings } from "../../errors-warnings.js"; import { prepareLabels } from "../../update/pr/labels.js"; import { addParticipants } from "../../update/pr/participants.js"; import { getPlatformPrOptions } from "../../update/pr/index.js"; import { getBaseBranchDesc } from "./base-branch.js"; import { getConfigDesc } from "./config-description.js"; import { getExpectedPrList } from "./pr-list.js"; import { isNumber, isString } from "@sindresorhus/is"; //#region lib/workers/repository/onboarding/pr/index.ts /** * Given an existing PR, if onboardingAutoCloseAge has passed, close the PR. * * Returns true if the PR was closed. */ async function ensureOnboardingAutoCloseAge(existingPr) { const ageOfOnboardingPr = getElapsedDays(existingPr.createdAt, false); const onboardingAutoCloseAge = getInheritedOrGlobal("onboardingAutoCloseAge"); if (onboardingAutoCloseAge) logger.debug({ onboardingAutoCloseAge, createdAt: existingPr.createdAt, ageOfOnboardingPr }, `Determining that the onboarding PR created at \`${existingPr.createdAt}\` was created ${ageOfOnboardingPr.toFixed(2)} days ago`); if (isNumber(onboardingAutoCloseAge) && ageOfOnboardingPr > onboardingAutoCloseAge) { await platform.updatePr({ number: existingPr.number, state: "closed", prTitle: existingPr.title }); await ensureComment({ number: existingPr.number, topic: `Renovate is disabled`, content: `Renovate is disabled because the onboarding PR has been unmerged for more than ${onboardingAutoCloseAge} days. To enable Renovate, you can either (a) change this PR's title to get a new onboarding PR, and merge the new onboarding PR, or (b) create a Renovate config file, and commit that file to your base branch.` }); logger.debug({ ageOfOnboardingPr, onboardingAutoCloseAge }, `Renovate is being disabled for this repository as the onboarding PR has been unmerged for more than ${onboardingAutoCloseAge} days`); return true; } return false; } async function ensureOnboardingPr(config, packageFiles, branches) { if (config.repoIsOnboarded === true || config.onboardingRebaseCheckbox && !OnboardingState.prUpdateRequested) return; logger.debug("ensureOnboardingPr()"); logger.trace({ config }); const onboardingBranch = getInheritedOrGlobal("onboardingBranch"); const existingPr = await platform.getBranchPr(onboardingBranch, config.defaultBranch); if (existingPr) { if (await ensureOnboardingAutoCloseAge(existingPr)) throw new Error(REPOSITORY_CLOSED_ONBOARDING); if (await isOnboardingBranchConflicted(config.defaultBranch, onboardingBranch)) { if (GlobalConfig.get("dryRun")) { logger.info("DRY-RUN: Would comment that Onboarding PR is conflicted and needs manual resolving"); return; } await ensureComment({ number: existingPr.number, topic: "Branch Conflicted", content: emojify(`:warning: This PR has a merge conflict which Renovate is unable to automatically resolve, so updates to this PR description are now paused. Please resolve the merge conflict manually.\n\n`) }); return; } } if (OnboardingState.onboardingCacheValid) return; const onboardingConfigHashComment = await getOnboardingConfigHashComment(); const rebaseCheckBox = getRebaseCheckbox(config.onboardingRebaseCheckbox); logger.debug("Filling in onboarding PR template"); let prTemplate = `Welcome to [Renovate](${config.productLinks.homepage})! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin.\n\n`; prTemplate += getInheritedOrGlobal("requireConfig") === "required" ? emojify(`:vertical_traffic_light: To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged.\n\n`) : emojify(`:vertical_traffic_light: Renovate will begin keeping your dependencies up-to-date only once you merge or close this Pull Request.\n\n`); prTemplate += emojify(`:books: See our [Reading List](https://docs.renovatebot.com/reading-list/) for relevant documentation you may be interested in reading.\n\n`); const configFile = getDefaultConfigFileName(); prTemplate += emojify(`:abcd: Do you want to change how Renovate upgrades your dependencies?`); prTemplate += ` Add your custom config to \`${configFile}\` in this branch${config.onboardingRebaseCheckbox ? " and select the Retry/Rebase checkbox below" : ""}. Renovate will update the Pull Request description the next time it runs.`; prTemplate += "\n\n"; prTemplate += emojify(` --- {{PACKAGE FILES}} {{CONFIG}} {{BASEBRANCH}} {{PRLIST}} {{WARNINGS}} {{ERRORS}} --- :question: Got questions? Check out Renovate's [Docs](${config.productLinks.documentation}), particularly the Getting Started section. If you need any further assistance then you can also [request help here](${config.productLinks.help}). `); prTemplate += rebaseCheckBox; let prBody = prTemplate; if (packageFiles && Object.entries(packageFiles).length) { let files = []; for (const [manager, managerFiles] of Object.entries(packageFiles)) files = files.concat(managerFiles.map((file) => ` * \`${file.packageFile}\` (${manager})`)); prBody = `${prBody.replace("{{PACKAGE FILES}}", `### Detected Package Files\n\n${files.join("\n")}`)}\n`; } else prBody = prBody.replace("{{PACKAGE FILES}}\n", ""); let configDesc = ""; if (GlobalConfig.get("dryRun")) logger.info(`DRY-RUN: Would check branch ${onboardingBranch}`); else configDesc = getConfigDesc(config, packageFiles); prBody = prBody.replace("{{CONFIG}}\n", configDesc); prBody = prBody.replace("{{WARNINGS}}\n", getWarnings(config) + getDepWarningsOnboardingPR(packageFiles, config)); prBody = prBody.replace("{{ERRORS}}\n", getErrors(config)); prBody = prBody.replace("{{BASEBRANCH}}\n", getBaseBranchDesc(config)); prBody = prBody.replace("{{PRLIST}}\n", getExpectedPrList(config, branches)); if (isString(config.prHeader)) prBody = `${compile(config.prHeader, config)}\n\n${prBody}`; if (isString(config.prFooter)) prBody = `${prBody}\n---\n\n${compile(config.prFooter, config)}\n`; prBody += onboardingConfigHashComment; logger.trace(`prBody:\n${prBody}`); prBody = platform.massageMarkdown(prBody, config.rebaseLabel); if (existingPr) { logger.debug("Found open onboarding PR"); const prBodyHash = hashBody(prBody); if (existingPr.bodyStruct?.hash === prBodyHash) { logger.debug(`Pull Request #${existingPr.number} does not need updating`); return; } if (GlobalConfig.get("dryRun")) logger.info("DRY-RUN: Would update onboarding PR"); else { await platform.updatePr({ number: existingPr.number, prTitle: existingPr.title, prBody }); logger.info({ pr: existingPr.number }, "Onboarding PR updated"); } return; } logger.debug("Creating onboarding PR"); const labels = prepareLabels(config); try { if (GlobalConfig.get("dryRun")) logger.info("DRY-RUN: Would create onboarding PR"); else { const prTitle = config.semanticCommits === "enabled" ? getSemanticCommitPrTitle(config) : getInheritedOrGlobal("onboardingPrTitle"); const pr = await platform.createPr({ sourceBranch: onboardingBranch, targetBranch: config.defaultBranch, prTitle, prBody, labels, platformPrOptions: getPlatformPrOptions({ ...config, automerge: false }) }); logger.info({ pr: `Pull Request #${pr.number}` }, "Onboarding PR created"); await addParticipants(config, pr); } } catch (err) { if (err.response?.statusCode === 422 && err.response?.body?.errors?.[0]?.message?.startsWith("A pull request already exists")) { logger.warn("Onboarding PR already exists but cannot find it. It was probably created by a different user."); await scm.deleteBranch(onboardingBranch); return; } throw err; } } function getRebaseCheckbox(onboardingRebaseCheckbox) { let rebaseCheckBox = ""; if (onboardingRebaseCheckbox) rebaseCheckBox = `\n\n---\n\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, click this checkbox.\n`; return rebaseCheckBox; } async function getOnboardingConfigHashComment() { return `\n<!--renovate-config-hash:${toSha256(await getFile(getDefaultConfigFileName(), getInheritedOrGlobal("onboardingBranch")) ?? "")}-->\n`; } //#endregion export { ensureOnboardingPr }; //# sourceMappingURL=index.js.map