renovate 43.274.0 → 43.275.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/workers/repository/onboarding/pr/index.js +9 -3
- package/dist/workers/repository/onboarding/pr/index.js.map +1 -1
- package/dist/workers/repository/onboarding/pr/package-files.js +25 -1
- package/dist/workers/repository/onboarding/pr/package-files.js.map +1 -1
- package/dist/workers/repository/onboarding/pr/pr-list.js +162 -2
- package/dist/workers/repository/onboarding/pr/pr-list.js.map +1 -1
- package/dist/workers/repository/reconfigure/comment.js +12 -7
- package/dist/workers/repository/reconfigure/comment.js.map +1 -1
- package/package.json +1 -1
- package/renovate-schema.json +2 -2
|
@@ -19,8 +19,8 @@ import { addParticipants } from "../../update/pr/participants.js";
|
|
|
19
19
|
import { getPlatformPrOptions } from "../../update/pr/index.js";
|
|
20
20
|
import { getBaseBranchDesc } from "./base-branch.js";
|
|
21
21
|
import { getConfigDesc } from "./config-description.js";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
22
|
+
import { getPackageFilesDesc, getPackageFilesSummary } from "./package-files.js";
|
|
23
|
+
import { getExpectedPrList, getExpectedPrListSummary } from "./pr-list.js";
|
|
24
24
|
import { isNumber, isString } from "@sindresorhus/is";
|
|
25
25
|
//#region lib/workers/repository/onboarding/pr/index.ts
|
|
26
26
|
/**
|
|
@@ -114,10 +114,16 @@ If you need any further assistance then you can also [request help here](${Globa
|
|
|
114
114
|
prBody = prBody.replace("{{WARNINGS}}\n", getWarnings(config) + getDepWarningsOnboardingPR(packageFiles, config));
|
|
115
115
|
prBody = prBody.replace("{{ERRORS}}\n", getErrors(config));
|
|
116
116
|
prBody = prBody.replace("{{BASEBRANCH}}\n", getBaseBranchDesc(config));
|
|
117
|
-
|
|
117
|
+
const prList = getExpectedPrList(config, branches);
|
|
118
|
+
prBody = prBody.replace("{{PRLIST}}\n", prList);
|
|
118
119
|
if (isString(config.prHeader)) prBody = `${compile(config.prHeader, config)}\n\n${prBody}`;
|
|
119
120
|
if (isString(config.prFooter)) prBody = `${prBody}\n---\n\n${compile(config.prFooter, config)}\n`;
|
|
120
121
|
prBody += onboardingConfigHashComment;
|
|
122
|
+
if (prBody.length > platform.maxBodyLength()) {
|
|
123
|
+
logger.debug("Onboarding PR body exceeds platform limit, switching to summary PR list and package files");
|
|
124
|
+
prBody = prBody.replace(prList, getExpectedPrListSummary(config, branches));
|
|
125
|
+
if (packageFilesDesc) prBody = prBody.replace(packageFilesDesc, `### Detected Package Files\n\n${getPackageFilesSummary(packageFiles)}`);
|
|
126
|
+
}
|
|
121
127
|
logger.trace(`prBody:\n${prBody}`);
|
|
122
128
|
prBody = platform.massageMarkdown(prBody, config.rebaseLabel);
|
|
123
129
|
if (existingPr) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["template.compile"],"sources":["../../../../../lib/workers/repository/onboarding/pr/index.ts"],"sourcesContent":["import { isNumber, isString } from '@sindresorhus/is';\nimport { GlobalConfig } from '../../../../config/global.ts';\nimport type { RenovateConfig } from '../../../../config/types.ts';\nimport { REPOSITORY_CLOSED_ONBOARDING } from '../../../../constants/error-messages.ts';\nimport { logger } from '../../../../logger/index.ts';\nimport type { PackageFile } from '../../../../modules/manager/types.ts';\nimport { ensureComment } from '../../../../modules/platform/comment.ts';\nimport type { Pr } from '../../../../modules/platform/index.ts';\nimport { platform } from '../../../../modules/platform/index.ts';\nimport { hashBody } from '../../../../modules/platform/pr-body.ts';\nimport { scm } from '../../../../modules/platform/scm.ts';\nimport { getInheritedOrGlobal } from '../../../../util/common.ts';\nimport { getElapsedDays } from '../../../../util/date.ts';\nimport { emojify } from '../../../../util/emoji.ts';\nimport { getFile } from '../../../../util/git/index.ts';\nimport { toSha256 } from '../../../../util/hash.ts';\nimport * as template from '../../../../util/template/index.ts';\nimport type { BranchConfig } from '../../../types.ts';\nimport {\n getDepWarningsOnboardingPR,\n getErrors,\n getWarnings,\n} from '../../errors-warnings.ts';\nimport { getPlatformPrOptions } from '../../update/pr/index.ts';\nimport { prepareLabels } from '../../update/pr/labels.ts';\nimport { addParticipants } from '../../update/pr/participants.ts';\nimport { isOnboardingBranchConflicted } from '../branch/onboarding-branch-cache.ts';\nimport {\n OnboardingState,\n getDefaultConfigFileName,\n getSemanticCommitPrTitle,\n} from '../common.ts';\nimport { getBaseBranchDesc } from './base-branch.ts';\nimport { getConfigDesc } from './config-description.ts';\nimport { getPackageFilesDesc } from './package-files.ts';\nimport { getExpectedPrList } from './pr-list.ts';\n\n/**\n * Given an existing PR, if onboardingAutoCloseAge has passed, close the PR.\n *\n * Returns true if the PR was closed.\n */\nasync function ensureOnboardingAutoCloseAge(existingPr: Pr): Promise<boolean> {\n // check if the existing pr crosses the onboarding autoclose age\n const ageOfOnboardingPr = getElapsedDays(existingPr.createdAt!, false);\n const onboardingAutoCloseAge = getInheritedOrGlobal('onboardingAutoCloseAge');\n if (onboardingAutoCloseAge) {\n logger.debug(\n {\n onboardingAutoCloseAge,\n createdAt: existingPr.createdAt!,\n ageOfOnboardingPr,\n },\n `Determining that the onboarding PR created at \\`${existingPr.createdAt!}\\` was created ${ageOfOnboardingPr.toFixed(2)} days ago`,\n );\n }\n if (\n isNumber(onboardingAutoCloseAge) &&\n ageOfOnboardingPr > onboardingAutoCloseAge\n ) {\n // close the pr\n await platform.updatePr({\n number: existingPr.number,\n state: 'closed',\n prTitle: existingPr.title,\n });\n // ensure comment\n await ensureComment({\n number: existingPr.number,\n topic: `Renovate is disabled`,\n 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.`,\n });\n logger.debug(\n {\n ageOfOnboardingPr,\n onboardingAutoCloseAge,\n },\n `Renovate is being disabled for this repository as the onboarding PR has been unmerged for more than ${onboardingAutoCloseAge} days`,\n );\n return true;\n }\n return false;\n}\n\nexport async function ensureOnboardingPr(\n config: RenovateConfig,\n packageFiles: Record<string, PackageFile[]> | null,\n branches: BranchConfig[],\n): Promise<void> {\n if (\n config.repoIsOnboarded === true ||\n (config.onboardingRebaseCheckbox && !OnboardingState.prUpdateRequested)\n ) {\n return;\n }\n logger.debug('ensureOnboardingPr()');\n logger.trace({ config });\n // TODO #22198\n const onboardingBranch = getInheritedOrGlobal('onboardingBranch')!;\n const existingPr = await platform.getBranchPr(\n onboardingBranch,\n config.defaultBranch,\n );\n if (existingPr) {\n const wasClosed = await ensureOnboardingAutoCloseAge(existingPr);\n if (wasClosed) {\n throw new Error(REPOSITORY_CLOSED_ONBOARDING);\n }\n\n // skip pr-update if branch is conflicted\n if (\n await isOnboardingBranchConflicted(\n config.defaultBranch!,\n onboardingBranch,\n )\n ) {\n if (GlobalConfig.get('dryRun')) {\n logger.info(\n 'DRY-RUN: Would comment that Onboarding PR is conflicted and needs manual resolving',\n );\n return;\n }\n await ensureComment({\n number: existingPr.number,\n topic: 'Branch Conflicted',\n content: emojify(\n `: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`,\n ),\n });\n return;\n }\n }\n\n if (OnboardingState.onboardingCacheValid) {\n return;\n }\n\n const onboardingConfigHashComment = await getOnboardingConfigHashComment();\n const rebaseCheckBox = getRebaseCheckbox(config.onboardingRebaseCheckbox);\n logger.debug('Filling in onboarding PR template');\n let prTemplate = `Welcome to [Renovate](${\n GlobalConfig.get('productLinks').homepage\n })! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin.\\n\\n`;\n prTemplate +=\n getInheritedOrGlobal('requireConfig') === 'required'\n ? emojify(\n `:vertical_traffic_light: To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged.\\n\\n`,\n )\n : emojify(\n `:vertical_traffic_light: Renovate will begin keeping your dependencies up-to-date only once you merge or close this Pull Request.\\n\\n`,\n );\n\n prTemplate += emojify(\n `:books: See our [Reading List](${GlobalConfig.get('productLinks').documentation}reading-list/) for relevant documentation you may be interested in reading.\\n\\n`,\n );\n\n const configFile = getDefaultConfigFileName();\n prTemplate += emojify(\n `:abcd: Do you want to change how Renovate upgrades your dependencies?`,\n );\n prTemplate += ` Add your custom config to \\`${configFile}\\` in this branch${\n config.onboardingRebaseCheckbox\n ? ' and select the Retry/Rebase checkbox below'\n : ''\n }. Renovate will update the Pull Request description the next time it runs.`;\n prTemplate += '\\n\\n';\n // TODO #22198\n prTemplate += emojify(\n `\n\n---\n{{PACKAGE FILES}}\n{{CONFIG}}\n{{BASEBRANCH}}\n{{PRLIST}}\n{{WARNINGS}}\n{{ERRORS}}\n\n---\n\n:question: Got questions? Check out Renovate's [Docs](${\n GlobalConfig.get('productLinks').documentation\n }), particularly the Getting Started section.\nIf you need any further assistance then you can also [request help here](${\n GlobalConfig.get('productLinks').help\n }).\n`,\n );\n prTemplate += rebaseCheckBox;\n let prBody = prTemplate;\n const packageFilesDesc = getPackageFilesDesc(packageFiles);\n if (packageFilesDesc) {\n prBody = `${prBody.replace('{{PACKAGE FILES}}', packageFilesDesc)}\\n`;\n } else {\n prBody = prBody.replace('{{PACKAGE FILES}}\\n', '');\n }\n let configDesc = '';\n if (GlobalConfig.get('dryRun')) {\n // TODO: types (#22198)\n logger.info(`DRY-RUN: Would check branch ${onboardingBranch}`);\n } else {\n configDesc = getConfigDesc(config, packageFiles!);\n }\n prBody = prBody.replace('{{CONFIG}}\\n', configDesc);\n prBody = prBody.replace(\n '{{WARNINGS}}\\n',\n getWarnings(config) + getDepWarningsOnboardingPR(packageFiles!, config),\n );\n prBody = prBody.replace('{{ERRORS}}\\n', getErrors(config));\n prBody = prBody.replace('{{BASEBRANCH}}\\n', getBaseBranchDesc(config));\n prBody = prBody.replace('{{PRLIST}}\\n', getExpectedPrList(config, branches));\n if (isString(config.prHeader)) {\n prBody = `${template.compile(config.prHeader, config)}\\n\\n${prBody}`;\n }\n if (isString(config.prFooter)) {\n prBody = `${prBody}\\n---\\n\\n${template.compile(config.prFooter, config)}\\n`;\n }\n\n prBody += onboardingConfigHashComment;\n\n logger.trace(`prBody:\\n${prBody}`);\n\n prBody = platform.massageMarkdown(prBody, config.rebaseLabel);\n\n if (existingPr) {\n logger.debug('Found open onboarding PR');\n // Check if existing PR needs updating\n const prBodyHash = hashBody(prBody);\n if (existingPr.bodyStruct?.hash === prBodyHash) {\n logger.debug(`Pull Request #${existingPr.number} does not need updating`);\n return;\n }\n // PR must need updating\n if (GlobalConfig.get('dryRun')) {\n logger.info('DRY-RUN: Would update onboarding PR');\n } else {\n await platform.updatePr({\n number: existingPr.number,\n prTitle: existingPr.title,\n prBody,\n });\n logger.info({ pr: existingPr.number }, 'Onboarding PR updated');\n }\n return;\n }\n logger.debug('Creating onboarding PR');\n const labels: string[] = prepareLabels(config);\n try {\n if (GlobalConfig.get('dryRun')) {\n logger.info('DRY-RUN: Would create onboarding PR');\n } else {\n // TODO #22198\n const prTitle =\n config.semanticCommits === 'enabled'\n ? getSemanticCommitPrTitle(config)\n : getInheritedOrGlobal('onboardingPrTitle')!;\n const pr = await platform.createPr({\n sourceBranch: onboardingBranch,\n targetBranch: config.defaultBranch!,\n prTitle,\n prBody,\n labels,\n platformPrOptions: getPlatformPrOptions({\n ...config,\n automerge: false,\n }),\n });\n logger.info(\n { pr: `Pull Request #${pr!.number}` },\n 'Onboarding PR created',\n );\n await addParticipants(config, pr!);\n }\n } catch (err) {\n if (\n err.response?.statusCode === 422 &&\n err.response?.body?.errors?.[0]?.message?.startsWith(\n 'A pull request already exists',\n )\n ) {\n logger.warn(\n 'Onboarding PR already exists but cannot find it. It was probably created by a different user.',\n );\n await scm.deleteBranch(onboardingBranch);\n return;\n }\n throw err;\n }\n}\n\nfunction getRebaseCheckbox(onboardingRebaseCheckbox?: boolean): string {\n let rebaseCheckBox = '';\n if (onboardingRebaseCheckbox) {\n // Create markdown checkbox\n rebaseCheckBox = `\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, click this checkbox.\\n`;\n }\n\n return rebaseCheckBox;\n}\n\nasync function getOnboardingConfigHashComment(): Promise<string> {\n const configFile = getDefaultConfigFileName();\n const existingContents =\n (await getFile(configFile, getInheritedOrGlobal('onboardingBranch'))) ?? '';\n const hash = toSha256(existingContents);\n\n return `\\n<!--renovate-config-hash:${hash}-->\\n`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["template.compile"],"sources":["../../../../../lib/workers/repository/onboarding/pr/index.ts"],"sourcesContent":["import { isNumber, isString } from '@sindresorhus/is';\nimport { GlobalConfig } from '../../../../config/global.ts';\nimport type { RenovateConfig } from '../../../../config/types.ts';\nimport { REPOSITORY_CLOSED_ONBOARDING } from '../../../../constants/error-messages.ts';\nimport { logger } from '../../../../logger/index.ts';\nimport type { PackageFile } from '../../../../modules/manager/types.ts';\nimport { ensureComment } from '../../../../modules/platform/comment.ts';\nimport type { Pr } from '../../../../modules/platform/index.ts';\nimport { platform } from '../../../../modules/platform/index.ts';\nimport { hashBody } from '../../../../modules/platform/pr-body.ts';\nimport { scm } from '../../../../modules/platform/scm.ts';\nimport { getInheritedOrGlobal } from '../../../../util/common.ts';\nimport { getElapsedDays } from '../../../../util/date.ts';\nimport { emojify } from '../../../../util/emoji.ts';\nimport { getFile } from '../../../../util/git/index.ts';\nimport { toSha256 } from '../../../../util/hash.ts';\nimport * as template from '../../../../util/template/index.ts';\nimport type { BranchConfig } from '../../../types.ts';\nimport {\n getDepWarningsOnboardingPR,\n getErrors,\n getWarnings,\n} from '../../errors-warnings.ts';\nimport { getPlatformPrOptions } from '../../update/pr/index.ts';\nimport { prepareLabels } from '../../update/pr/labels.ts';\nimport { addParticipants } from '../../update/pr/participants.ts';\nimport { isOnboardingBranchConflicted } from '../branch/onboarding-branch-cache.ts';\nimport {\n OnboardingState,\n getDefaultConfigFileName,\n getSemanticCommitPrTitle,\n} from '../common.ts';\nimport { getBaseBranchDesc } from './base-branch.ts';\nimport { getConfigDesc } from './config-description.ts';\nimport {\n getPackageFilesDesc,\n getPackageFilesSummary,\n} from './package-files.ts';\nimport { getExpectedPrList, getExpectedPrListSummary } from './pr-list.ts';\n\n/**\n * Given an existing PR, if onboardingAutoCloseAge has passed, close the PR.\n *\n * Returns true if the PR was closed.\n */\nasync function ensureOnboardingAutoCloseAge(existingPr: Pr): Promise<boolean> {\n // check if the existing pr crosses the onboarding autoclose age\n const ageOfOnboardingPr = getElapsedDays(existingPr.createdAt!, false);\n const onboardingAutoCloseAge = getInheritedOrGlobal('onboardingAutoCloseAge');\n if (onboardingAutoCloseAge) {\n logger.debug(\n {\n onboardingAutoCloseAge,\n createdAt: existingPr.createdAt!,\n ageOfOnboardingPr,\n },\n `Determining that the onboarding PR created at \\`${existingPr.createdAt!}\\` was created ${ageOfOnboardingPr.toFixed(2)} days ago`,\n );\n }\n if (\n isNumber(onboardingAutoCloseAge) &&\n ageOfOnboardingPr > onboardingAutoCloseAge\n ) {\n // close the pr\n await platform.updatePr({\n number: existingPr.number,\n state: 'closed',\n prTitle: existingPr.title,\n });\n // ensure comment\n await ensureComment({\n number: existingPr.number,\n topic: `Renovate is disabled`,\n 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.`,\n });\n logger.debug(\n {\n ageOfOnboardingPr,\n onboardingAutoCloseAge,\n },\n `Renovate is being disabled for this repository as the onboarding PR has been unmerged for more than ${onboardingAutoCloseAge} days`,\n );\n return true;\n }\n return false;\n}\n\nexport async function ensureOnboardingPr(\n config: RenovateConfig,\n packageFiles: Record<string, PackageFile[]> | null,\n branches: BranchConfig[],\n): Promise<void> {\n if (\n config.repoIsOnboarded === true ||\n (config.onboardingRebaseCheckbox && !OnboardingState.prUpdateRequested)\n ) {\n return;\n }\n logger.debug('ensureOnboardingPr()');\n logger.trace({ config });\n // TODO #22198\n const onboardingBranch = getInheritedOrGlobal('onboardingBranch')!;\n const existingPr = await platform.getBranchPr(\n onboardingBranch,\n config.defaultBranch,\n );\n if (existingPr) {\n const wasClosed = await ensureOnboardingAutoCloseAge(existingPr);\n if (wasClosed) {\n throw new Error(REPOSITORY_CLOSED_ONBOARDING);\n }\n\n // skip pr-update if branch is conflicted\n if (\n await isOnboardingBranchConflicted(\n config.defaultBranch!,\n onboardingBranch,\n )\n ) {\n if (GlobalConfig.get('dryRun')) {\n logger.info(\n 'DRY-RUN: Would comment that Onboarding PR is conflicted and needs manual resolving',\n );\n return;\n }\n await ensureComment({\n number: existingPr.number,\n topic: 'Branch Conflicted',\n content: emojify(\n `: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`,\n ),\n });\n return;\n }\n }\n\n if (OnboardingState.onboardingCacheValid) {\n return;\n }\n\n const onboardingConfigHashComment = await getOnboardingConfigHashComment();\n const rebaseCheckBox = getRebaseCheckbox(config.onboardingRebaseCheckbox);\n logger.debug('Filling in onboarding PR template');\n let prTemplate = `Welcome to [Renovate](${\n GlobalConfig.get('productLinks').homepage\n })! This is an onboarding PR to help you understand and configure settings before regular Pull Requests begin.\\n\\n`;\n prTemplate +=\n getInheritedOrGlobal('requireConfig') === 'required'\n ? emojify(\n `:vertical_traffic_light: To activate Renovate, merge this Pull Request. To disable Renovate, simply close this Pull Request unmerged.\\n\\n`,\n )\n : emojify(\n `:vertical_traffic_light: Renovate will begin keeping your dependencies up-to-date only once you merge or close this Pull Request.\\n\\n`,\n );\n\n prTemplate += emojify(\n `:books: See our [Reading List](${GlobalConfig.get('productLinks').documentation}reading-list/) for relevant documentation you may be interested in reading.\\n\\n`,\n );\n\n const configFile = getDefaultConfigFileName();\n prTemplate += emojify(\n `:abcd: Do you want to change how Renovate upgrades your dependencies?`,\n );\n prTemplate += ` Add your custom config to \\`${configFile}\\` in this branch${\n config.onboardingRebaseCheckbox\n ? ' and select the Retry/Rebase checkbox below'\n : ''\n }. Renovate will update the Pull Request description the next time it runs.`;\n prTemplate += '\\n\\n';\n // TODO #22198\n prTemplate += emojify(\n `\n\n---\n{{PACKAGE FILES}}\n{{CONFIG}}\n{{BASEBRANCH}}\n{{PRLIST}}\n{{WARNINGS}}\n{{ERRORS}}\n\n---\n\n:question: Got questions? Check out Renovate's [Docs](${\n GlobalConfig.get('productLinks').documentation\n }), particularly the Getting Started section.\nIf you need any further assistance then you can also [request help here](${\n GlobalConfig.get('productLinks').help\n }).\n`,\n );\n prTemplate += rebaseCheckBox;\n let prBody = prTemplate;\n const packageFilesDesc = getPackageFilesDesc(packageFiles);\n if (packageFilesDesc) {\n prBody = `${prBody.replace('{{PACKAGE FILES}}', packageFilesDesc)}\\n`;\n } else {\n prBody = prBody.replace('{{PACKAGE FILES}}\\n', '');\n }\n let configDesc = '';\n if (GlobalConfig.get('dryRun')) {\n // TODO: types (#22198)\n logger.info(`DRY-RUN: Would check branch ${onboardingBranch}`);\n } else {\n configDesc = getConfigDesc(config, packageFiles!);\n }\n prBody = prBody.replace('{{CONFIG}}\\n', configDesc);\n prBody = prBody.replace(\n '{{WARNINGS}}\\n',\n getWarnings(config) + getDepWarningsOnboardingPR(packageFiles!, config),\n );\n prBody = prBody.replace('{{ERRORS}}\\n', getErrors(config));\n prBody = prBody.replace('{{BASEBRANCH}}\\n', getBaseBranchDesc(config));\n const prList = getExpectedPrList(config, branches);\n prBody = prBody.replace('{{PRLIST}}\\n', prList);\n if (isString(config.prHeader)) {\n prBody = `${template.compile(config.prHeader, config)}\\n\\n${prBody}`;\n }\n if (isString(config.prFooter)) {\n prBody = `${prBody}\\n---\\n\\n${template.compile(config.prFooter, config)}\\n`;\n }\n\n prBody += onboardingConfigHashComment;\n\n if (prBody.length > platform.maxBodyLength()) {\n logger.debug(\n 'Onboarding PR body exceeds platform limit, switching to summary PR list and package files',\n );\n prBody = prBody.replace(prList, getExpectedPrListSummary(config, branches));\n if (packageFilesDesc) {\n prBody = prBody.replace(\n packageFilesDesc,\n `### Detected Package Files\\n\\n${getPackageFilesSummary(packageFiles)}`,\n );\n }\n }\n\n logger.trace(`prBody:\\n${prBody}`);\n\n prBody = platform.massageMarkdown(prBody, config.rebaseLabel);\n\n if (existingPr) {\n logger.debug('Found open onboarding PR');\n // Check if existing PR needs updating\n const prBodyHash = hashBody(prBody);\n if (existingPr.bodyStruct?.hash === prBodyHash) {\n logger.debug(`Pull Request #${existingPr.number} does not need updating`);\n return;\n }\n // PR must need updating\n if (GlobalConfig.get('dryRun')) {\n logger.info('DRY-RUN: Would update onboarding PR');\n } else {\n await platform.updatePr({\n number: existingPr.number,\n prTitle: existingPr.title,\n prBody,\n });\n logger.info({ pr: existingPr.number }, 'Onboarding PR updated');\n }\n return;\n }\n logger.debug('Creating onboarding PR');\n const labels: string[] = prepareLabels(config);\n try {\n if (GlobalConfig.get('dryRun')) {\n logger.info('DRY-RUN: Would create onboarding PR');\n } else {\n // TODO #22198\n const prTitle =\n config.semanticCommits === 'enabled'\n ? getSemanticCommitPrTitle(config)\n : getInheritedOrGlobal('onboardingPrTitle')!;\n const pr = await platform.createPr({\n sourceBranch: onboardingBranch,\n targetBranch: config.defaultBranch!,\n prTitle,\n prBody,\n labels,\n platformPrOptions: getPlatformPrOptions({\n ...config,\n automerge: false,\n }),\n });\n logger.info(\n { pr: `Pull Request #${pr!.number}` },\n 'Onboarding PR created',\n );\n await addParticipants(config, pr!);\n }\n } catch (err) {\n if (\n err.response?.statusCode === 422 &&\n err.response?.body?.errors?.[0]?.message?.startsWith(\n 'A pull request already exists',\n )\n ) {\n logger.warn(\n 'Onboarding PR already exists but cannot find it. It was probably created by a different user.',\n );\n await scm.deleteBranch(onboardingBranch);\n return;\n }\n throw err;\n }\n}\n\nfunction getRebaseCheckbox(onboardingRebaseCheckbox?: boolean): string {\n let rebaseCheckBox = '';\n if (onboardingRebaseCheckbox) {\n // Create markdown checkbox\n rebaseCheckBox = `\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, click this checkbox.\\n`;\n }\n\n return rebaseCheckBox;\n}\n\nasync function getOnboardingConfigHashComment(): Promise<string> {\n const configFile = getDefaultConfigFileName();\n const existingContents =\n (await getFile(configFile, getInheritedOrGlobal('onboardingBranch'))) ?? '';\n const hash = toSha256(existingContents);\n\n return `\\n<!--renovate-config-hash:${hash}-->\\n`;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,28 @@
|
|
|
1
1
|
//#region lib/workers/repository/onboarding/pr/package-files.ts
|
|
2
|
+
const GROUP_THRESHOLD = 3;
|
|
3
|
+
function formatManagerFiles(files) {
|
|
4
|
+
const byDir = /* @__PURE__ */ new Map();
|
|
5
|
+
for (const { packageFile } of files) {
|
|
6
|
+
const lastSlash = packageFile.lastIndexOf("/");
|
|
7
|
+
const dir = lastSlash >= 0 ? packageFile.slice(0, lastSlash + 1) : "";
|
|
8
|
+
const name = lastSlash >= 0 ? packageFile.slice(lastSlash + 1) : packageFile;
|
|
9
|
+
const existing = byDir.get(dir);
|
|
10
|
+
if (existing) existing.push(name);
|
|
11
|
+
else byDir.set(dir, [name]);
|
|
12
|
+
}
|
|
13
|
+
const lines = [];
|
|
14
|
+
for (const [dir, names] of byDir) if (dir && names.length >= GROUP_THRESHOLD) {
|
|
15
|
+
lines.push(` * \`${dir}\``);
|
|
16
|
+
for (const name of names) lines.push(` * \`${name}\``);
|
|
17
|
+
} else for (const name of names) lines.push(` * \`${dir}${name}\``);
|
|
18
|
+
return lines.join("\n");
|
|
19
|
+
}
|
|
20
|
+
function getPackageFilesSummary(packageFiles) {
|
|
21
|
+
if (!packageFiles || !Object.entries(packageFiles).length) return "";
|
|
22
|
+
const sections = [];
|
|
23
|
+
for (const [manager, managerFiles] of Object.entries(packageFiles)) sections.push(`#### ${manager}\n\n${formatManagerFiles(managerFiles)}`);
|
|
24
|
+
return sections.join("\n\n");
|
|
25
|
+
}
|
|
2
26
|
function getPackageFilesDesc(packageFiles) {
|
|
3
27
|
if (!packageFiles || !Object.entries(packageFiles).length) return "";
|
|
4
28
|
let files = [];
|
|
@@ -6,6 +30,6 @@ function getPackageFilesDesc(packageFiles) {
|
|
|
6
30
|
return `### Detected Package Files\n\n${files.join("\n")}`;
|
|
7
31
|
}
|
|
8
32
|
//#endregion
|
|
9
|
-
export { getPackageFilesDesc };
|
|
33
|
+
export { getPackageFilesDesc, getPackageFilesSummary };
|
|
10
34
|
|
|
11
35
|
//# sourceMappingURL=package-files.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-files.js","names":[],"sources":["../../../../../lib/workers/repository/onboarding/pr/package-files.ts"],"sourcesContent":["import type { PackageFile } from '../../../../modules/manager/types.ts';\n\nconst GROUP_THRESHOLD = 3;\n\nfunction formatManagerFiles(files: PackageFile[]): string {\n const byDir = new Map<string, string[]>();\n for (const { packageFile } of files) {\n const lastSlash = packageFile.lastIndexOf('/');\n const dir = lastSlash >= 0 ? packageFile.slice(0, lastSlash + 1) : '';\n const name =\n lastSlash >= 0 ? packageFile.slice(lastSlash + 1) : packageFile;\n const existing = byDir.get(dir);\n if (existing) {\n existing.push(name);\n } else {\n byDir.set(dir, [name]);\n }\n }\n\n const lines: string[] = [];\n for (const [dir, names] of byDir) {\n if (dir && names.length >= GROUP_THRESHOLD) {\n lines.push(` * \\`${dir}\\``);\n for (const name of names) {\n lines.push(` * \\`${name}\\``);\n }\n } else {\n for (const name of names) {\n lines.push(` * \\`${dir}${name}\\``);\n }\n }\n }\n return lines.join('\\n');\n}\n\nexport function getPackageFilesSummary(\n packageFiles: Record<string, PackageFile[]> | null,\n): string {\n if (!packageFiles || !Object.entries(packageFiles).length) {\n return '';\n }\n const sections: string[] = [];\n for (const [manager, managerFiles] of Object.entries(packageFiles)) {\n sections.push(`#### ${manager}\\n\\n${formatManagerFiles(managerFiles)}`);\n }\n return sections.join('\\n\\n');\n}\n\nexport function getPackageFilesDesc(\n packageFiles: Record<string, PackageFile[]> | null,\n): string {\n if (!packageFiles || !Object.entries(packageFiles).length) {\n return '';\n }\n let files: string[] = [];\n for (const [manager, managerFiles] of Object.entries(packageFiles)) {\n files = files.concat(\n managerFiles.map((file) => ` * \\`${file.packageFile}\\` (${manager})`),\n );\n }\n return `### Detected Package Files\\n\\n${files.join('\\n')}`;\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"file":"package-files.js","names":[],"sources":["../../../../../lib/workers/repository/onboarding/pr/package-files.ts"],"sourcesContent":["import type { PackageFile } from '../../../../modules/manager/types.ts';\n\nconst GROUP_THRESHOLD = 3;\n\nfunction formatManagerFiles(files: PackageFile[]): string {\n const byDir = new Map<string, string[]>();\n for (const { packageFile } of files) {\n const lastSlash = packageFile.lastIndexOf('/');\n const dir = lastSlash >= 0 ? packageFile.slice(0, lastSlash + 1) : '';\n const name =\n lastSlash >= 0 ? packageFile.slice(lastSlash + 1) : packageFile;\n const existing = byDir.get(dir);\n if (existing) {\n existing.push(name);\n } else {\n byDir.set(dir, [name]);\n }\n }\n\n const lines: string[] = [];\n for (const [dir, names] of byDir) {\n if (dir && names.length >= GROUP_THRESHOLD) {\n lines.push(` * \\`${dir}\\``);\n for (const name of names) {\n lines.push(` * \\`${name}\\``);\n }\n } else {\n for (const name of names) {\n lines.push(` * \\`${dir}${name}\\``);\n }\n }\n }\n return lines.join('\\n');\n}\n\nexport function getPackageFilesSummary(\n packageFiles: Record<string, PackageFile[]> | null,\n): string {\n if (!packageFiles || !Object.entries(packageFiles).length) {\n return '';\n }\n const sections: string[] = [];\n for (const [manager, managerFiles] of Object.entries(packageFiles)) {\n sections.push(`#### ${manager}\\n\\n${formatManagerFiles(managerFiles)}`);\n }\n return sections.join('\\n\\n');\n}\n\nexport function getPackageFilesDesc(\n packageFiles: Record<string, PackageFile[]> | null,\n): string {\n if (!packageFiles || !Object.entries(packageFiles).length) {\n return '';\n }\n let files: string[] = [];\n for (const [manager, managerFiles] of Object.entries(packageFiles)) {\n files = files.concat(\n managerFiles.map((file) => ` * \\`${file.packageFile}\\` (${manager})`),\n );\n }\n return `### Detected Package Files\\n\\n${files.join('\\n')}`;\n}\n"],"mappings":";AAEA,MAAM,kBAAkB;AAExB,SAAS,mBAAmB,OAA8B;CACxD,MAAM,wBAAQ,IAAI,IAAsB;CACxC,KAAK,MAAM,EAAE,iBAAiB,OAAO;EACnC,MAAM,YAAY,YAAY,YAAY,GAAG;EAC7C,MAAM,MAAM,aAAa,IAAI,YAAY,MAAM,GAAG,YAAY,CAAC,IAAI;EACnE,MAAM,OACJ,aAAa,IAAI,YAAY,MAAM,YAAY,CAAC,IAAI;EACtD,MAAM,WAAW,MAAM,IAAI,GAAG;EAC9B,IAAI,UACF,SAAS,KAAK,IAAI;OAElB,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC;CAEzB;CAEA,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,CAAC,KAAK,UAAU,OACzB,IAAI,OAAO,MAAM,UAAU,iBAAiB;EAC1C,MAAM,KAAK,QAAQ,IAAI,GAAG;EAC1B,KAAK,MAAM,QAAQ,OACjB,MAAM,KAAK,UAAU,KAAK,GAAG;CAEjC,OACE,KAAK,MAAM,QAAQ,OACjB,MAAM,KAAK,QAAQ,MAAM,KAAK,GAAG;CAIvC,OAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAgB,uBACd,cACQ;CACR,IAAI,CAAC,gBAAgB,CAAC,OAAO,QAAQ,YAAY,CAAC,CAAC,QACjD,OAAO;CAET,MAAM,WAAqB,CAAC;CAC5B,KAAK,MAAM,CAAC,SAAS,iBAAiB,OAAO,QAAQ,YAAY,GAC/D,SAAS,KAAK,QAAQ,QAAQ,MAAM,mBAAmB,YAAY,GAAG;CAExE,OAAO,SAAS,KAAK,MAAM;AAC7B;AAEA,SAAgB,oBACd,cACQ;CACR,IAAI,CAAC,gBAAgB,CAAC,OAAO,QAAQ,YAAY,CAAC,CAAC,QACjD,OAAO;CAET,IAAI,QAAkB,CAAC;CACvB,KAAK,MAAM,CAAC,SAAS,iBAAiB,OAAO,QAAQ,YAAY,GAC/D,QAAQ,MAAM,OACZ,aAAa,KAAK,SAAS,QAAQ,KAAK,YAAY,MAAM,QAAQ,EAAE,CACtE;CAEF,OAAO,iCAAiC,MAAM,KAAK,IAAI;AACzD"}
|
|
@@ -4,7 +4,12 @@ import { logger } from "../../../../logger/index.js";
|
|
|
4
4
|
import { UpdateTypesOptions } from "../../../../config/types.js";
|
|
5
5
|
import { coerceNumber } from "../../../../util/number.js";
|
|
6
6
|
import { emojify } from "../../../../util/emoji.js";
|
|
7
|
-
|
|
7
|
+
//#region lib/workers/repository/onboarding/pr/pr-list.ts
|
|
8
|
+
/** Priority order when rendering the `SummaryCategory`s in the summary view.
|
|
9
|
+
*
|
|
10
|
+
* NOTE that this is not exhaustive - this is only the priority order for rendering, and other categories, such as `other` are placed after.
|
|
11
|
+
*/
|
|
12
|
+
const SUMMARY_CATEGORY_PRIORITY_ORDER = ["security", ...UpdateTypesOptions];
|
|
8
13
|
function getExpectedPrList(config, branches) {
|
|
9
14
|
logger.debug("getExpectedPrList()");
|
|
10
15
|
logger.trace({ config });
|
|
@@ -44,7 +49,162 @@ function getExpectedPrList(config, branches) {
|
|
|
44
49
|
else if (prHourlyLimit > 0 && prHourlyLimit < 5 && prHourlyLimit < branches.length) prDesc += emojify(`\n\n:children_crossing: PR creation will be limited to maximum ${prHourlyLimit} per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for \`prHourlyLimit\`](${GlobalConfig.get("productLinks").documentation}configuration-options/#prhourlylimit) for details.\n\n`);
|
|
45
50
|
return prDesc;
|
|
46
51
|
}
|
|
52
|
+
function getBranchUpgradeTypes(branch) {
|
|
53
|
+
if (branch.isVulnerabilityAlert) return /* @__PURE__ */ new Set(["security"]);
|
|
54
|
+
const types = /* @__PURE__ */ new Set();
|
|
55
|
+
for (const upgrade of branch.upgrades) if (upgrade.updateType) types.add(upgrade.updateType);
|
|
56
|
+
else if (upgrade.isLockfileUpdate) types.add("lockfileUpdate");
|
|
57
|
+
else types.add("other");
|
|
58
|
+
return types;
|
|
59
|
+
}
|
|
60
|
+
function sortBaseBranches(bases) {
|
|
61
|
+
return [...bases].sort((a, b) => {
|
|
62
|
+
if (a === b)
|
|
63
|
+
/* v8 ignore next -- base branches are unique Record keys; equal comparison cannot occur */
|
|
64
|
+
return 0;
|
|
65
|
+
if (a === "") return -1;
|
|
66
|
+
if (b === "") return 1;
|
|
67
|
+
return a.localeCompare(b);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function describeSecurityGroup(groupBranches) {
|
|
71
|
+
const firstUpgrade = groupBranches[0].upgrades[0];
|
|
72
|
+
const depName = firstUpgrade?.depName ?? groupBranches[0].prTitle ?? "";
|
|
73
|
+
const updateType = firstUpgrade?.updateType ?? "unknown";
|
|
74
|
+
const packageFiles = groupBranches.map((b) => ({
|
|
75
|
+
file: b.packageFile ?? "",
|
|
76
|
+
manager: b.manager
|
|
77
|
+
})).filter((f) => f.file);
|
|
78
|
+
const uniqueManagers = new Set(packageFiles.map((f) => f.manager));
|
|
79
|
+
if (packageFiles.length === 0) {
|
|
80
|
+
const branchManagers = new Set(groupBranches.map((b) => b.manager));
|
|
81
|
+
if (branchManagers.size === 1) return `- \`${depName}\`, (${[...branchManagers][0]}, ${updateType})\n`;
|
|
82
|
+
return `- \`${depName}\`, (${updateType}): ${[...branchManagers].sort().join(", ")}\n`;
|
|
83
|
+
}
|
|
84
|
+
if (packageFiles.length === 1) {
|
|
85
|
+
const file = packageFiles[0].file;
|
|
86
|
+
const [manager] = uniqueManagers;
|
|
87
|
+
return `- \`${depName}\`, (${manager}, ${updateType}): \`${file}\`\n`;
|
|
88
|
+
}
|
|
89
|
+
if (uniqueManagers.size === 1) return `- \`${depName}\`, (${[...uniqueManagers][0]}, ${updateType}):\n${packageFiles.map(({ file }) => ` - \`${file}\`\n`).join("")}`;
|
|
90
|
+
return `- \`${depName}\`, (${updateType}):\n${packageFiles.map(({ file, manager }) => ` - \`${file}\` (${manager})\n`).join("")}`;
|
|
91
|
+
}
|
|
92
|
+
function collectBranchStats(branches) {
|
|
93
|
+
const prCountByBase = {};
|
|
94
|
+
const tableStats = {};
|
|
95
|
+
const presentTypes = /* @__PURE__ */ new Set();
|
|
96
|
+
const securityGroups = {};
|
|
97
|
+
const seenPrs = /* @__PURE__ */ new Set();
|
|
98
|
+
const seenTableKeys = /* @__PURE__ */ new Set();
|
|
99
|
+
for (const branch of branches) {
|
|
100
|
+
const base = branch.baseBranch ?? "";
|
|
101
|
+
const { manager, branchName } = branch;
|
|
102
|
+
const branchTypes = getBranchUpgradeTypes(branch);
|
|
103
|
+
for (const type of branchTypes) presentTypes.add(type);
|
|
104
|
+
if (!seenPrs.has(branchName)) {
|
|
105
|
+
seenPrs.add(branchName);
|
|
106
|
+
prCountByBase[base] = (prCountByBase[base] ?? 0) + 1;
|
|
107
|
+
}
|
|
108
|
+
tableStats[base] ??= {};
|
|
109
|
+
const baseStats = tableStats[base];
|
|
110
|
+
baseStats[manager] ??= {};
|
|
111
|
+
const managerStats = baseStats[manager];
|
|
112
|
+
for (const type of branchTypes) {
|
|
113
|
+
const key = `${branchName}:${manager}:${type}`;
|
|
114
|
+
if (seenTableKeys.has(key)) continue;
|
|
115
|
+
seenTableKeys.add(key);
|
|
116
|
+
managerStats[type] ??= 0;
|
|
117
|
+
managerStats[type]++;
|
|
118
|
+
}
|
|
119
|
+
if (branch.isVulnerabilityAlert) {
|
|
120
|
+
securityGroups[branchName] ??= [];
|
|
121
|
+
securityGroups[branchName].push(branch);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
prCountByBase,
|
|
126
|
+
tableStats,
|
|
127
|
+
presentCategories: presentTypes,
|
|
128
|
+
securityGroups,
|
|
129
|
+
prCount: seenPrs.size
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function getCategoryColumns(presentTypes) {
|
|
133
|
+
const cols = SUMMARY_CATEGORY_PRIORITY_ORDER.filter((t) => presentTypes.has(t));
|
|
134
|
+
for (const t of presentTypes) if (t !== "other" && !cols.includes(t)) cols.push(t);
|
|
135
|
+
if (presentTypes.has("other")) cols.push("other");
|
|
136
|
+
return cols;
|
|
137
|
+
}
|
|
138
|
+
function categoriesToColumnHeaders(cols) {
|
|
139
|
+
/* v8 ignore next -- branches always have at least one upgrade, so cols is never empty in practice */
|
|
140
|
+
if (cols.length === 0) return "";
|
|
141
|
+
return ` | ${cols.join(" | ")}`;
|
|
142
|
+
}
|
|
143
|
+
function renderRowCounts(typeColumns, typeCounts) {
|
|
144
|
+
return categoriesToColumnHeaders(typeColumns.map((t) => `${typeCounts[t] ?? 0}`));
|
|
145
|
+
}
|
|
146
|
+
function sumCategoryCounts(rows, categoryColumns) {
|
|
147
|
+
const sum = {};
|
|
148
|
+
for (const categoryCounts of rows) for (const category of categoryColumns) sum[category] = (sum[category] ?? 0) + (categoryCounts[category] ?? 0);
|
|
149
|
+
return sum;
|
|
150
|
+
}
|
|
151
|
+
function getExpectedPrListSummary(config, branches) {
|
|
152
|
+
logger.debug("getExpectedPrListSummary()");
|
|
153
|
+
logger.trace({ config });
|
|
154
|
+
let prDesc = `\n### What to Expect\n\n`;
|
|
155
|
+
if (!branches.length) return `${prDesc}It looks like your repository dependencies are already up-to-date and no Pull Requests will be necessary right away.\n`;
|
|
156
|
+
const stats = collectBranchStats(branches);
|
|
157
|
+
const sortedBases = sortBaseBranches(Object.keys(stats.prCountByBase));
|
|
158
|
+
const hasMultipleBaseBranches = sortedBases.length > 1;
|
|
159
|
+
const prHourlyLimit = coerceNumber(config.prHourlyLimit);
|
|
160
|
+
const commitHourlyLimit = coerceNumber(config.commitHourlyLimit);
|
|
161
|
+
if (hasMultipleBaseBranches) {
|
|
162
|
+
let total = 0;
|
|
163
|
+
const parts = sortedBases.map((base) => {
|
|
164
|
+
const count = stats.prCountByBase[base];
|
|
165
|
+
total += count;
|
|
166
|
+
const label = base ? `the \`${base}\` branch` : "the default branch";
|
|
167
|
+
return `${count} Pull Request${count > 1 ? "s" : ""} to ${label}`;
|
|
168
|
+
});
|
|
169
|
+
const hourlyLimitsNotice = determineHourlyLimitsNotice(prHourlyLimit, commitHourlyLimit, total);
|
|
170
|
+
prDesc += `With your current configuration, Renovate will create ${parts.join(" and ")}${hourlyLimitsNotice}:\n\n`;
|
|
171
|
+
} else {
|
|
172
|
+
const hourlyLimitsNotice = determineHourlyLimitsNotice(prHourlyLimit, commitHourlyLimit, stats.prCount);
|
|
173
|
+
prDesc += `With your current configuration, Renovate will create ${stats.prCount} Pull Request${stats.prCount > 1 ? "s" : ""}${hourlyLimitsNotice}:\n\n`;
|
|
174
|
+
}
|
|
175
|
+
const categoryColumns = getCategoryColumns(stats.presentCategories);
|
|
176
|
+
if (hasMultipleBaseBranches) {
|
|
177
|
+
prDesc += `| Branch | Manager${categoriesToColumnHeaders(categoryColumns)} |\n`;
|
|
178
|
+
prDesc += `| --- | ---${categoryColumns.map(() => " | ---").join("")} |\n`;
|
|
179
|
+
for (const base of sortedBases) {
|
|
180
|
+
const label = base || "$default";
|
|
181
|
+
for (const [manager, typeCounts] of Object.entries(stats.tableStats[base])) prDesc += `| ${label} | ${manager}${renderRowCounts(categoryColumns, typeCounts)} |\n`;
|
|
182
|
+
}
|
|
183
|
+
const sumRow = sumCategoryCounts(Object.values(stats.tableStats).flatMap((b) => Object.values(b)), categoryColumns);
|
|
184
|
+
prDesc += `| **Total** | ${renderRowCounts(categoryColumns, sumRow)} |\n`;
|
|
185
|
+
} else {
|
|
186
|
+
prDesc += `| Manager${categoriesToColumnHeaders(categoryColumns)} |\n`;
|
|
187
|
+
prDesc += `| ---${categoryColumns.map(() => " | ---").join("")} |\n`;
|
|
188
|
+
for (const [manager, typeCounts] of Object.entries(stats.tableStats[sortedBases[0]])) prDesc += `| ${manager}${renderRowCounts(categoryColumns, typeCounts)} |\n`;
|
|
189
|
+
const sumRow = sumCategoryCounts(Object.values(stats.tableStats[sortedBases[0]]), categoryColumns);
|
|
190
|
+
prDesc += `| **Total**${renderRowCounts(categoryColumns, sumRow)} |\n`;
|
|
191
|
+
}
|
|
192
|
+
prDesc += `\n<small>Note that a single PR can update multiple files and/or managers, so the above rows may not align with the number of PRs being listed above.</small>\n`;
|
|
193
|
+
if (Object.keys(stats.securityGroups).length) {
|
|
194
|
+
prDesc += `\n**Security updates**:\n\n`;
|
|
195
|
+
for (const groupBranches of Object.values(stats.securityGroups)) prDesc += describeSecurityGroup(groupBranches);
|
|
196
|
+
}
|
|
197
|
+
if (commitHourlyLimit > 0 && commitHourlyLimit < 5 && commitHourlyLimit < stats.prCount) prDesc += emojify(`\n\n:children_crossing: Branch creation and rebasing will be limited to maximum ${commitHourlyLimit} per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for \`commitHourlyLimit\`](${GlobalConfig.get("productLinks").documentation}configuration-options/#commithourlylimit) for details.\n\n`);
|
|
198
|
+
else if (prHourlyLimit > 0 && prHourlyLimit < 5 && prHourlyLimit < stats.prCount) prDesc += emojify(`\n\n:children_crossing: PR creation will be limited to maximum ${prHourlyLimit} per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for \`prHourlyLimit\`](${GlobalConfig.get("productLinks").documentation}configuration-options/#prhourlylimit) for details.\n\n`);
|
|
199
|
+
return prDesc;
|
|
200
|
+
}
|
|
201
|
+
function determineHourlyLimitsNotice(prHourlyLimit, commitHourlyLimit, prCount) {
|
|
202
|
+
if (commitHourlyLimit === 0 && prHourlyLimit === 0) return " (with no configured maximum of PRs per hour)";
|
|
203
|
+
if (commitHourlyLimit > 0 && commitHourlyLimit < 5 && commitHourlyLimit < prCount) return emojify(` (at a maximum of ${commitHourlyLimit} PR${commitHourlyLimit > 1 ? "s" : ""}/rebase${commitHourlyLimit > 1 ? "s" : ""} per hour)`);
|
|
204
|
+
if (prHourlyLimit > 0 && prHourlyLimit < 5 && prHourlyLimit < prCount) return emojify(` (at a maximum of ${prHourlyLimit} PR${prHourlyLimit > 1 ? "s" : ""} per hour)`);
|
|
205
|
+
return "";
|
|
206
|
+
}
|
|
47
207
|
//#endregion
|
|
48
|
-
export { getExpectedPrList };
|
|
208
|
+
export { getExpectedPrList, getExpectedPrListSummary };
|
|
49
209
|
|
|
50
210
|
//# sourceMappingURL=pr-list.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-list.js","names":[],"sources":["../../../../../lib/workers/repository/onboarding/pr/pr-list.ts"],"sourcesContent":["import { GlobalConfig } from '../../../../config/global.ts';\nimport {\n type RenovateConfig,\n type UpdateType,\n UpdateTypesOptions,\n} from '../../../../config/types.ts';\nimport { logger } from '../../../../logger/index.ts';\nimport { emojify } from '../../../../util/emoji.ts';\nimport { coerceNumber } from '../../../../util/number.ts';\nimport { regEx } from '../../../../util/regex.ts';\nimport type { BranchConfig } from '../../../types.ts';\n\n/**\n * The different categories of dependency updates to output, when providing the summary view.\n *\n * - `security`: if the upgrade is driven by a vulnerability alert\n * - `${updateType}`: if it's set. I.e. `major`\n * - `lockfileUpdate` when `isLockfileUpdate` is true, without an `updateType`\n * - `other`: otherwise\n */\ntype SummaryCategory = UpdateType | 'security' | 'other';\n\n/** Priority order when rendering the `SummaryCategory`s in the summary view.\n *\n * NOTE that this is not exhaustive - this is only the priority order for rendering, and other categories, such as `other` are placed after.\n */\nconst SUMMARY_CATEGORY_PRIORITY_ORDER: readonly SummaryCategory[] = [\n 'security',\n ...UpdateTypesOptions,\n // ... anything else\n];\n\nexport function getExpectedPrList(\n config: RenovateConfig,\n branches: BranchConfig[],\n): string {\n logger.debug('getExpectedPrList()');\n logger.trace({ config });\n let prDesc = `\\n### What to Expect\\n\\n`;\n if (!branches.length) {\n return `${prDesc}It looks like your repository dependencies are already up-to-date and no Pull Requests will be necessary right away.\\n`;\n }\n prDesc += `With your current configuration, Renovate will create ${branches.length} Pull Request`;\n prDesc += branches.length > 1 ? `s:\\n\\n` : `:\\n\\n`;\n\n for (const branch of branches) {\n const prTitleRe = regEx(/@([a-z]+\\/[a-z]+)/);\n // TODO #22198\n prDesc += `<details>\\n<summary>${branch.prTitle!.replace(\n prTitleRe,\n '@​$1',\n )}</summary>\\n\\n`;\n if (branch.schedule?.length) {\n prDesc += ` - Schedule: ${JSON.stringify(branch.schedule)}\\n`;\n }\n prDesc += ` - Branch name: \\`${branch.branchName}\\`\\n`;\n prDesc += branch.baseBranch\n ? ` - Merge into: \\`${branch.baseBranch}\\`\\n`\n : '';\n const seen: string[] = [];\n for (const upgrade of branch.upgrades) {\n let text = '';\n if (upgrade.updateType === 'lockFileMaintenance') {\n text += ' - Regenerate lock files to use latest dependency versions';\n } else {\n if (upgrade.updateType === 'pin') {\n text += ' - Pin ';\n } else {\n text += ' - Upgrade ';\n }\n if (upgrade.sourceUrl) {\n // TODO: types (#22198)\n text += `[${upgrade.depName!}](${upgrade.sourceUrl})`;\n } else {\n text += upgrade.depName!.replace(prTitleRe, '@​$1');\n }\n // TODO: types (#22198)\n text += upgrade.isLockfileUpdate\n ? ` to \\`${upgrade.newVersion!}\\``\n : ` to \\`${upgrade.newDigest ?? upgrade.newValue!}\\``;\n text += '\\n';\n }\n if (!seen.includes(text)) {\n prDesc += text;\n seen.push(text);\n }\n }\n prDesc += '\\n\\n';\n prDesc += '</details>\\n\\n';\n }\n const prHourlyLimit = coerceNumber(config.prHourlyLimit);\n const commitHourlyLimit = coerceNumber(config.commitHourlyLimit);\n if (\n commitHourlyLimit > 0 &&\n commitHourlyLimit < 5 &&\n commitHourlyLimit < branches.length\n ) {\n prDesc += emojify(\n `\\n\\n:children_crossing: Branch creation and rebasing will be limited to maximum ${commitHourlyLimit} per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for \\`commitHourlyLimit\\`](${GlobalConfig.get('productLinks').documentation}configuration-options/#commithourlylimit) for details.\\n\\n`,\n );\n } else if (\n prHourlyLimit > 0 &&\n prHourlyLimit < 5 &&\n prHourlyLimit < branches.length\n ) {\n prDesc += emojify(\n `\\n\\n:children_crossing: PR creation will be limited to maximum ${prHourlyLimit} per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for \\`prHourlyLimit\\`](${GlobalConfig.get('productLinks').documentation}configuration-options/#prhourlylimit) for details.\\n\\n`,\n );\n }\n return prDesc;\n}\n\nfunction getBranchUpgradeTypes(branch: BranchConfig): Set<SummaryCategory> {\n if (branch.isVulnerabilityAlert) {\n return new Set(['security']);\n }\n const types = new Set<SummaryCategory>();\n for (const upgrade of branch.upgrades) {\n if (upgrade.updateType) {\n types.add(upgrade.updateType);\n } else if (upgrade.isLockfileUpdate) {\n types.add('lockfileUpdate');\n } else {\n types.add('other');\n }\n }\n return types;\n}\n\n// Sort: default branch (empty string) first, then named branches alphabetically.\nfunction sortBaseBranches(bases: Iterable<string>): string[] {\n return [...bases].sort((a, b) => {\n if (a === b) {\n /* v8 ignore next -- base branches are unique Record keys; equal comparison cannot occur */\n return 0;\n }\n if (a === '') {\n return -1;\n }\n if (b === '') {\n return 1;\n }\n return a.localeCompare(b);\n });\n}\n\nfunction describeSecurityGroup(groupBranches: BranchConfig[]): string {\n const firstUpgrade = groupBranches[0].upgrades[0];\n const depName = firstUpgrade?.depName ?? groupBranches[0].prTitle ?? '';\n const updateType = firstUpgrade?.updateType ?? 'unknown';\n const packageFiles = groupBranches\n .map((b) => ({ file: b.packageFile ?? '', manager: b.manager }))\n .filter((f) => f.file);\n const uniqueManagers = new Set(packageFiles.map((f) => f.manager));\n\n // Vulnerability alerts can match on datasource + packageName without a specific file (e.g. GitHub vulnerability alerts),\n // so we need to handle an absent packageFile\n if (packageFiles.length === 0) {\n const branchManagers = new Set(groupBranches.map((b) => b.manager));\n if (branchManagers.size === 1) {\n return `- \\`${depName}\\`, (${[...branchManagers][0]}, ${updateType})\\n`;\n }\n\n return `- \\`${depName}\\`, (${updateType}): ${[...branchManagers].sort().join(', ')}\\n`;\n }\n\n if (packageFiles.length === 1) {\n const file = packageFiles[0].file;\n const [manager] = uniqueManagers;\n return `- \\`${depName}\\`, (${manager}, ${updateType}): \\`${file}\\`\\n`;\n }\n\n if (uniqueManagers.size === 1) {\n const manager = [...uniqueManagers][0];\n const fileLines = packageFiles\n .map(({ file }) => ` - \\`${file}\\`\\n`)\n .join('');\n return `- \\`${depName}\\`, (${manager}, ${updateType}):\\n${fileLines}`;\n }\n\n const fileLines = packageFiles\n .map(({ file, manager }) => ` - \\`${file}\\` (${manager})\\n`)\n .join('');\n return `- \\`${depName}\\`, (${updateType}):\\n${fileLines}`;\n}\n\ninterface BranchStats {\n // PR count per base branch, deduplicated by branchName.\n prCountByBase: Record<string, number>;\n // base -> manager -> type -> count, deduplicated by branchName+manager+type.\n tableStats: Record<\n string,\n Record<string, Partial<Record<SummaryCategory, number>>>\n >;\n // All upgrade types seen anywhere — drives the table columns.\n presentCategories: Set<SummaryCategory>;\n // Security branches grouped by branchName.\n securityGroups: Record<string, BranchConfig[]>;\n prCount: number;\n}\n\nfunction collectBranchStats(branches: BranchConfig[]): BranchStats {\n const prCountByBase: Record<string, number> = {};\n const tableStats: Record<\n string,\n Record<string, Partial<Record<SummaryCategory, number>>>\n > = {};\n const presentTypes = new Set<SummaryCategory>();\n const securityGroups: Record<string, BranchConfig[]> = {};\n const seenPrs = new Set<string>();\n const seenTableKeys = new Set<string>();\n\n for (const branch of branches) {\n const base = branch.baseBranch ?? '';\n const { manager, branchName } = branch;\n const branchTypes = getBranchUpgradeTypes(branch);\n\n for (const type of branchTypes) {\n presentTypes.add(type);\n }\n\n if (!seenPrs.has(branchName)) {\n seenPrs.add(branchName);\n prCountByBase[base] = (prCountByBase[base] ?? 0) + 1;\n }\n\n tableStats[base] ??= {};\n const baseStats = tableStats[base];\n baseStats[manager] ??= {};\n const managerStats = baseStats[manager];\n for (const type of branchTypes) {\n const key = `${branchName}:${manager}:${type}`;\n if (seenTableKeys.has(key)) {\n continue;\n }\n seenTableKeys.add(key);\n managerStats[type] ??= 0;\n managerStats[type]++;\n }\n\n if (branch.isVulnerabilityAlert) {\n securityGroups[branchName] ??= [];\n securityGroups[branchName].push(branch);\n }\n }\n\n return {\n prCountByBase,\n tableStats,\n presentCategories: presentTypes,\n securityGroups,\n prCount: seenPrs.size,\n };\n}\n\nfunction getCategoryColumns(\n presentTypes: Set<SummaryCategory>,\n): SummaryCategory[] {\n const cols: SummaryCategory[] = SUMMARY_CATEGORY_PRIORITY_ORDER.filter((t) =>\n presentTypes.has(t),\n );\n // Append any present types not in the standard display order\n // (e.g. lockfileUpdate, bump).\n for (const t of presentTypes) {\n if (t !== 'other' && !cols.includes(t)) {\n cols.push(t);\n }\n }\n\n if (presentTypes.has('other')) {\n cols.push('other');\n }\n\n return cols;\n}\n\nfunction categoriesToColumnHeaders(cols: readonly string[]): string {\n /* v8 ignore next -- branches always have at least one upgrade, so cols is never empty in practice */\n if (cols.length === 0) {\n return '';\n }\n return ` | ${cols.join(' | ')}`;\n}\n\nfunction renderRowCounts(\n typeColumns: readonly SummaryCategory[],\n typeCounts: Partial<Record<SummaryCategory, number>>,\n): string {\n return categoriesToColumnHeaders(\n typeColumns.map((t) => `${typeCounts[t] ?? 0}`),\n );\n}\n\nfunction sumCategoryCounts(\n rows: Partial<Record<SummaryCategory, number>>[],\n categoryColumns: readonly SummaryCategory[],\n): Partial<Record<SummaryCategory, number>> {\n const sum: Partial<Record<SummaryCategory, number>> = {};\n for (const categoryCounts of rows) {\n for (const category of categoryColumns) {\n sum[category] = (sum[category] ?? 0) + (categoryCounts[category] ?? 0);\n }\n }\n return sum;\n}\n\nexport function getExpectedPrListSummary(\n config: RenovateConfig,\n branches: BranchConfig[],\n): string {\n logger.debug('getExpectedPrListSummary()');\n logger.trace({ config });\n let prDesc = `\\n### What to Expect\\n\\n`;\n if (!branches.length) {\n return `${prDesc}It looks like your repository dependencies are already up-to-date and no Pull Requests will be necessary right away.\\n`;\n }\n\n const stats = collectBranchStats(branches);\n const sortedBases = sortBaseBranches(Object.keys(stats.prCountByBase));\n const hasMultipleBaseBranches = sortedBases.length > 1;\n\n const prHourlyLimit = coerceNumber(config.prHourlyLimit);\n const commitHourlyLimit = coerceNumber(config.commitHourlyLimit);\n\n if (hasMultipleBaseBranches) {\n let total = 0;\n const parts = sortedBases.map((base) => {\n const count = stats.prCountByBase[base];\n total += count;\n const label = base ? `the \\`${base}\\` branch` : 'the default branch';\n return `${count} Pull Request${count > 1 ? 's' : ''} to ${label}`;\n });\n const hourlyLimitsNotice = determineHourlyLimitsNotice(\n prHourlyLimit,\n commitHourlyLimit,\n total,\n );\n prDesc += `With your current configuration, Renovate will create ${parts.join(' and ')}${hourlyLimitsNotice}:\\n\\n`;\n } else {\n const hourlyLimitsNotice = determineHourlyLimitsNotice(\n prHourlyLimit,\n commitHourlyLimit,\n stats.prCount,\n );\n prDesc += `With your current configuration, Renovate will create ${stats.prCount} Pull Request${stats.prCount > 1 ? 's' : ''}${hourlyLimitsNotice}:\\n\\n`;\n }\n\n const categoryColumns = getCategoryColumns(stats.presentCategories);\n if (hasMultipleBaseBranches) {\n prDesc += `| Branch | Manager${categoriesToColumnHeaders(categoryColumns)} |\\n`;\n prDesc += `| --- | ---${categoryColumns.map(() => ' | ---').join('')} |\\n`;\n for (const base of sortedBases) {\n const label = base || '$default';\n for (const [manager, typeCounts] of Object.entries(\n stats.tableStats[base],\n )) {\n prDesc += `| ${label} | ${manager}${renderRowCounts(categoryColumns, typeCounts)} |\\n`;\n }\n }\n const sumRow = sumCategoryCounts(\n Object.values(stats.tableStats).flatMap((b) => Object.values(b)),\n categoryColumns,\n );\n prDesc += `| **Total** | ${renderRowCounts(categoryColumns, sumRow)} |\\n`;\n } else {\n prDesc += `| Manager${categoriesToColumnHeaders(categoryColumns)} |\\n`;\n prDesc += `| ---${categoryColumns.map(() => ' | ---').join('')} |\\n`;\n for (const [manager, typeCounts] of Object.entries(\n stats.tableStats[sortedBases[0]],\n )) {\n prDesc += `| ${manager}${renderRowCounts(categoryColumns, typeCounts)} |\\n`;\n }\n const sumRow = sumCategoryCounts(\n Object.values(stats.tableStats[sortedBases[0]]),\n categoryColumns,\n );\n prDesc += `| **Total**${renderRowCounts(categoryColumns, sumRow)} |\\n`;\n }\n\n prDesc += `\\n<small>Note that a single PR can update multiple files and/or managers, so the above rows may not align with the number of PRs being listed above.</small>\\n`;\n\n // provide a summary of the given security updates, as they're likely more important to the user\n if (Object.keys(stats.securityGroups).length) {\n prDesc += `\\n**Security updates**:\\n\\n`;\n for (const groupBranches of Object.values(stats.securityGroups)) {\n prDesc += describeSecurityGroup(groupBranches);\n }\n }\n\n if (\n commitHourlyLimit > 0 &&\n commitHourlyLimit < 5 &&\n commitHourlyLimit < stats.prCount\n ) {\n prDesc += emojify(\n `\\n\\n:children_crossing: Branch creation and rebasing will be limited to maximum ${commitHourlyLimit} per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for \\`commitHourlyLimit\\`](${GlobalConfig.get('productLinks').documentation}configuration-options/#commithourlylimit) for details.\\n\\n`,\n );\n } else if (\n prHourlyLimit > 0 &&\n prHourlyLimit < 5 &&\n prHourlyLimit < stats.prCount\n ) {\n prDesc += emojify(\n `\\n\\n:children_crossing: PR creation will be limited to maximum ${prHourlyLimit} per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for \\`prHourlyLimit\\`](${GlobalConfig.get('productLinks').documentation}configuration-options/#prhourlylimit) for details.\\n\\n`,\n );\n }\n return prDesc;\n}\n\nfunction determineHourlyLimitsNotice(\n prHourlyLimit: number,\n commitHourlyLimit: number,\n prCount: number,\n): string {\n if (commitHourlyLimit === 0 && prHourlyLimit === 0) {\n return ' (with no configured maximum of PRs per hour)';\n }\n\n if (\n commitHourlyLimit > 0 &&\n commitHourlyLimit < 5 &&\n commitHourlyLimit < prCount\n ) {\n return emojify(\n ` (at a maximum of ${commitHourlyLimit} PR${commitHourlyLimit > 1 ? 's' : ''}/rebase${commitHourlyLimit > 1 ? 's' : ''} per hour)`,\n );\n }\n\n if (prHourlyLimit > 0 && prHourlyLimit < 5 && prHourlyLimit < prCount) {\n return emojify(\n ` (at a maximum of ${prHourlyLimit} PR${prHourlyLimit > 1 ? 's' : ''} per hour)`,\n );\n }\n\n return '';\n}\n"],"mappings":";;;;;;AA0BoE,CAElE,GAAG,kBAEL;AAEA,SAAgB,kBACd,QACA,UACQ;CACR,OAAO,MAAM,qBAAqB;CAClC,OAAO,MAAM,EAAE,OAAO,CAAC;CACvB,IAAI,SAAS;CACb,IAAI,CAAC,SAAS,QACZ,OAAO,GAAG,OAAO;CAEnB,UAAU,yDAAyD,SAAS,OAAO;CACnF,UAAU,SAAS,SAAS,IAAI,WAAW;CAE3C,KAAK,MAAM,UAAU,UAAU;EAC7B,MAAM,YAAY,MAAM,mBAAmB;EAE3C,UAAU,uBAAuB,OAAO,QAAS,QAC/C,WACA,YACF,EAAE;EACF,IAAI,OAAO,UAAU,QACnB,UAAU,iBAAiB,KAAK,UAAU,OAAO,QAAQ,EAAE;EAE7D,UAAU,sBAAsB,OAAO,WAAW;EAClD,UAAU,OAAO,aACb,qBAAqB,OAAO,WAAW,QACvC;EACJ,MAAM,OAAiB,CAAC;EACxB,KAAK,MAAM,WAAW,OAAO,UAAU;GACrC,IAAI,OAAO;GACX,IAAI,QAAQ,eAAe,uBACzB,QAAQ;QACH;IACL,IAAI,QAAQ,eAAe,OACzB,QAAQ;SAER,QAAQ;IAEV,IAAI,QAAQ,WAEV,QAAQ,IAAI,QAAQ,QAAS,IAAI,QAAQ,UAAU;SAEnD,QAAQ,QAAQ,QAAS,QAAQ,WAAW,YAAY;IAG1D,QAAQ,QAAQ,mBACZ,SAAS,QAAQ,WAAY,MAC7B,SAAS,QAAQ,aAAa,QAAQ,SAAU;IACpD,QAAQ;GACV;GACA,IAAI,CAAC,KAAK,SAAS,IAAI,GAAG;IACxB,UAAU;IACV,KAAK,KAAK,IAAI;GAChB;EACF;EACA,UAAU;EACV,UAAU;CACZ;CACA,MAAM,gBAAgB,aAAa,OAAO,aAAa;CACvD,MAAM,oBAAoB,aAAa,OAAO,iBAAiB;CAC/D,IACE,oBAAoB,KACpB,oBAAoB,KACpB,oBAAoB,SAAS,QAE7B,UAAU,QACR,mFAAmF,kBAAkB,iHAAiH,aAAa,IAAI,cAAc,CAAC,CAAC,cAAc,2DACvQ;MACK,IACL,gBAAgB,KAChB,gBAAgB,KAChB,gBAAgB,SAAS,QAEzB,UAAU,QACR,kEAAkE,cAAc,6GAA6G,aAAa,IAAI,cAAc,CAAC,CAAC,cAAc,uDAC9O;CAEF,OAAO;AACT"}
|
|
1
|
+
{"version":3,"file":"pr-list.js","names":[],"sources":["../../../../../lib/workers/repository/onboarding/pr/pr-list.ts"],"sourcesContent":["import { GlobalConfig } from '../../../../config/global.ts';\nimport {\n type RenovateConfig,\n type UpdateType,\n UpdateTypesOptions,\n} from '../../../../config/types.ts';\nimport { logger } from '../../../../logger/index.ts';\nimport { emojify } from '../../../../util/emoji.ts';\nimport { coerceNumber } from '../../../../util/number.ts';\nimport { regEx } from '../../../../util/regex.ts';\nimport type { BranchConfig } from '../../../types.ts';\n\n/**\n * The different categories of dependency updates to output, when providing the summary view.\n *\n * - `security`: if the upgrade is driven by a vulnerability alert\n * - `${updateType}`: if it's set. I.e. `major`\n * - `lockfileUpdate` when `isLockfileUpdate` is true, without an `updateType`\n * - `other`: otherwise\n */\ntype SummaryCategory = UpdateType | 'security' | 'other';\n\n/** Priority order when rendering the `SummaryCategory`s in the summary view.\n *\n * NOTE that this is not exhaustive - this is only the priority order for rendering, and other categories, such as `other` are placed after.\n */\nconst SUMMARY_CATEGORY_PRIORITY_ORDER: readonly SummaryCategory[] = [\n 'security',\n ...UpdateTypesOptions,\n // ... anything else\n];\n\nexport function getExpectedPrList(\n config: RenovateConfig,\n branches: BranchConfig[],\n): string {\n logger.debug('getExpectedPrList()');\n logger.trace({ config });\n let prDesc = `\\n### What to Expect\\n\\n`;\n if (!branches.length) {\n return `${prDesc}It looks like your repository dependencies are already up-to-date and no Pull Requests will be necessary right away.\\n`;\n }\n prDesc += `With your current configuration, Renovate will create ${branches.length} Pull Request`;\n prDesc += branches.length > 1 ? `s:\\n\\n` : `:\\n\\n`;\n\n for (const branch of branches) {\n const prTitleRe = regEx(/@([a-z]+\\/[a-z]+)/);\n // TODO #22198\n prDesc += `<details>\\n<summary>${branch.prTitle!.replace(\n prTitleRe,\n '@​$1',\n )}</summary>\\n\\n`;\n if (branch.schedule?.length) {\n prDesc += ` - Schedule: ${JSON.stringify(branch.schedule)}\\n`;\n }\n prDesc += ` - Branch name: \\`${branch.branchName}\\`\\n`;\n prDesc += branch.baseBranch\n ? ` - Merge into: \\`${branch.baseBranch}\\`\\n`\n : '';\n const seen: string[] = [];\n for (const upgrade of branch.upgrades) {\n let text = '';\n if (upgrade.updateType === 'lockFileMaintenance') {\n text += ' - Regenerate lock files to use latest dependency versions';\n } else {\n if (upgrade.updateType === 'pin') {\n text += ' - Pin ';\n } else {\n text += ' - Upgrade ';\n }\n if (upgrade.sourceUrl) {\n // TODO: types (#22198)\n text += `[${upgrade.depName!}](${upgrade.sourceUrl})`;\n } else {\n text += upgrade.depName!.replace(prTitleRe, '@​$1');\n }\n // TODO: types (#22198)\n text += upgrade.isLockfileUpdate\n ? ` to \\`${upgrade.newVersion!}\\``\n : ` to \\`${upgrade.newDigest ?? upgrade.newValue!}\\``;\n text += '\\n';\n }\n if (!seen.includes(text)) {\n prDesc += text;\n seen.push(text);\n }\n }\n prDesc += '\\n\\n';\n prDesc += '</details>\\n\\n';\n }\n const prHourlyLimit = coerceNumber(config.prHourlyLimit);\n const commitHourlyLimit = coerceNumber(config.commitHourlyLimit);\n if (\n commitHourlyLimit > 0 &&\n commitHourlyLimit < 5 &&\n commitHourlyLimit < branches.length\n ) {\n prDesc += emojify(\n `\\n\\n:children_crossing: Branch creation and rebasing will be limited to maximum ${commitHourlyLimit} per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for \\`commitHourlyLimit\\`](${GlobalConfig.get('productLinks').documentation}configuration-options/#commithourlylimit) for details.\\n\\n`,\n );\n } else if (\n prHourlyLimit > 0 &&\n prHourlyLimit < 5 &&\n prHourlyLimit < branches.length\n ) {\n prDesc += emojify(\n `\\n\\n:children_crossing: PR creation will be limited to maximum ${prHourlyLimit} per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for \\`prHourlyLimit\\`](${GlobalConfig.get('productLinks').documentation}configuration-options/#prhourlylimit) for details.\\n\\n`,\n );\n }\n return prDesc;\n}\n\nfunction getBranchUpgradeTypes(branch: BranchConfig): Set<SummaryCategory> {\n if (branch.isVulnerabilityAlert) {\n return new Set(['security']);\n }\n const types = new Set<SummaryCategory>();\n for (const upgrade of branch.upgrades) {\n if (upgrade.updateType) {\n types.add(upgrade.updateType);\n } else if (upgrade.isLockfileUpdate) {\n types.add('lockfileUpdate');\n } else {\n types.add('other');\n }\n }\n return types;\n}\n\n// Sort: default branch (empty string) first, then named branches alphabetically.\nfunction sortBaseBranches(bases: Iterable<string>): string[] {\n return [...bases].sort((a, b) => {\n if (a === b) {\n /* v8 ignore next -- base branches are unique Record keys; equal comparison cannot occur */\n return 0;\n }\n if (a === '') {\n return -1;\n }\n if (b === '') {\n return 1;\n }\n return a.localeCompare(b);\n });\n}\n\nfunction describeSecurityGroup(groupBranches: BranchConfig[]): string {\n const firstUpgrade = groupBranches[0].upgrades[0];\n const depName = firstUpgrade?.depName ?? groupBranches[0].prTitle ?? '';\n const updateType = firstUpgrade?.updateType ?? 'unknown';\n const packageFiles = groupBranches\n .map((b) => ({ file: b.packageFile ?? '', manager: b.manager }))\n .filter((f) => f.file);\n const uniqueManagers = new Set(packageFiles.map((f) => f.manager));\n\n // Vulnerability alerts can match on datasource + packageName without a specific file (e.g. GitHub vulnerability alerts),\n // so we need to handle an absent packageFile\n if (packageFiles.length === 0) {\n const branchManagers = new Set(groupBranches.map((b) => b.manager));\n if (branchManagers.size === 1) {\n return `- \\`${depName}\\`, (${[...branchManagers][0]}, ${updateType})\\n`;\n }\n\n return `- \\`${depName}\\`, (${updateType}): ${[...branchManagers].sort().join(', ')}\\n`;\n }\n\n if (packageFiles.length === 1) {\n const file = packageFiles[0].file;\n const [manager] = uniqueManagers;\n return `- \\`${depName}\\`, (${manager}, ${updateType}): \\`${file}\\`\\n`;\n }\n\n if (uniqueManagers.size === 1) {\n const manager = [...uniqueManagers][0];\n const fileLines = packageFiles\n .map(({ file }) => ` - \\`${file}\\`\\n`)\n .join('');\n return `- \\`${depName}\\`, (${manager}, ${updateType}):\\n${fileLines}`;\n }\n\n const fileLines = packageFiles\n .map(({ file, manager }) => ` - \\`${file}\\` (${manager})\\n`)\n .join('');\n return `- \\`${depName}\\`, (${updateType}):\\n${fileLines}`;\n}\n\ninterface BranchStats {\n // PR count per base branch, deduplicated by branchName.\n prCountByBase: Record<string, number>;\n // base -> manager -> type -> count, deduplicated by branchName+manager+type.\n tableStats: Record<\n string,\n Record<string, Partial<Record<SummaryCategory, number>>>\n >;\n // All upgrade types seen anywhere — drives the table columns.\n presentCategories: Set<SummaryCategory>;\n // Security branches grouped by branchName.\n securityGroups: Record<string, BranchConfig[]>;\n prCount: number;\n}\n\nfunction collectBranchStats(branches: BranchConfig[]): BranchStats {\n const prCountByBase: Record<string, number> = {};\n const tableStats: Record<\n string,\n Record<string, Partial<Record<SummaryCategory, number>>>\n > = {};\n const presentTypes = new Set<SummaryCategory>();\n const securityGroups: Record<string, BranchConfig[]> = {};\n const seenPrs = new Set<string>();\n const seenTableKeys = new Set<string>();\n\n for (const branch of branches) {\n const base = branch.baseBranch ?? '';\n const { manager, branchName } = branch;\n const branchTypes = getBranchUpgradeTypes(branch);\n\n for (const type of branchTypes) {\n presentTypes.add(type);\n }\n\n if (!seenPrs.has(branchName)) {\n seenPrs.add(branchName);\n prCountByBase[base] = (prCountByBase[base] ?? 0) + 1;\n }\n\n tableStats[base] ??= {};\n const baseStats = tableStats[base];\n baseStats[manager] ??= {};\n const managerStats = baseStats[manager];\n for (const type of branchTypes) {\n const key = `${branchName}:${manager}:${type}`;\n if (seenTableKeys.has(key)) {\n continue;\n }\n seenTableKeys.add(key);\n managerStats[type] ??= 0;\n managerStats[type]++;\n }\n\n if (branch.isVulnerabilityAlert) {\n securityGroups[branchName] ??= [];\n securityGroups[branchName].push(branch);\n }\n }\n\n return {\n prCountByBase,\n tableStats,\n presentCategories: presentTypes,\n securityGroups,\n prCount: seenPrs.size,\n };\n}\n\nfunction getCategoryColumns(\n presentTypes: Set<SummaryCategory>,\n): SummaryCategory[] {\n const cols: SummaryCategory[] = SUMMARY_CATEGORY_PRIORITY_ORDER.filter((t) =>\n presentTypes.has(t),\n );\n // Append any present types not in the standard display order\n // (e.g. lockfileUpdate, bump).\n for (const t of presentTypes) {\n if (t !== 'other' && !cols.includes(t)) {\n cols.push(t);\n }\n }\n\n if (presentTypes.has('other')) {\n cols.push('other');\n }\n\n return cols;\n}\n\nfunction categoriesToColumnHeaders(cols: readonly string[]): string {\n /* v8 ignore next -- branches always have at least one upgrade, so cols is never empty in practice */\n if (cols.length === 0) {\n return '';\n }\n return ` | ${cols.join(' | ')}`;\n}\n\nfunction renderRowCounts(\n typeColumns: readonly SummaryCategory[],\n typeCounts: Partial<Record<SummaryCategory, number>>,\n): string {\n return categoriesToColumnHeaders(\n typeColumns.map((t) => `${typeCounts[t] ?? 0}`),\n );\n}\n\nfunction sumCategoryCounts(\n rows: Partial<Record<SummaryCategory, number>>[],\n categoryColumns: readonly SummaryCategory[],\n): Partial<Record<SummaryCategory, number>> {\n const sum: Partial<Record<SummaryCategory, number>> = {};\n for (const categoryCounts of rows) {\n for (const category of categoryColumns) {\n sum[category] = (sum[category] ?? 0) + (categoryCounts[category] ?? 0);\n }\n }\n return sum;\n}\n\nexport function getExpectedPrListSummary(\n config: RenovateConfig,\n branches: BranchConfig[],\n): string {\n logger.debug('getExpectedPrListSummary()');\n logger.trace({ config });\n let prDesc = `\\n### What to Expect\\n\\n`;\n if (!branches.length) {\n return `${prDesc}It looks like your repository dependencies are already up-to-date and no Pull Requests will be necessary right away.\\n`;\n }\n\n const stats = collectBranchStats(branches);\n const sortedBases = sortBaseBranches(Object.keys(stats.prCountByBase));\n const hasMultipleBaseBranches = sortedBases.length > 1;\n\n const prHourlyLimit = coerceNumber(config.prHourlyLimit);\n const commitHourlyLimit = coerceNumber(config.commitHourlyLimit);\n\n if (hasMultipleBaseBranches) {\n let total = 0;\n const parts = sortedBases.map((base) => {\n const count = stats.prCountByBase[base];\n total += count;\n const label = base ? `the \\`${base}\\` branch` : 'the default branch';\n return `${count} Pull Request${count > 1 ? 's' : ''} to ${label}`;\n });\n const hourlyLimitsNotice = determineHourlyLimitsNotice(\n prHourlyLimit,\n commitHourlyLimit,\n total,\n );\n prDesc += `With your current configuration, Renovate will create ${parts.join(' and ')}${hourlyLimitsNotice}:\\n\\n`;\n } else {\n const hourlyLimitsNotice = determineHourlyLimitsNotice(\n prHourlyLimit,\n commitHourlyLimit,\n stats.prCount,\n );\n prDesc += `With your current configuration, Renovate will create ${stats.prCount} Pull Request${stats.prCount > 1 ? 's' : ''}${hourlyLimitsNotice}:\\n\\n`;\n }\n\n const categoryColumns = getCategoryColumns(stats.presentCategories);\n if (hasMultipleBaseBranches) {\n prDesc += `| Branch | Manager${categoriesToColumnHeaders(categoryColumns)} |\\n`;\n prDesc += `| --- | ---${categoryColumns.map(() => ' | ---').join('')} |\\n`;\n for (const base of sortedBases) {\n const label = base || '$default';\n for (const [manager, typeCounts] of Object.entries(\n stats.tableStats[base],\n )) {\n prDesc += `| ${label} | ${manager}${renderRowCounts(categoryColumns, typeCounts)} |\\n`;\n }\n }\n const sumRow = sumCategoryCounts(\n Object.values(stats.tableStats).flatMap((b) => Object.values(b)),\n categoryColumns,\n );\n prDesc += `| **Total** | ${renderRowCounts(categoryColumns, sumRow)} |\\n`;\n } else {\n prDesc += `| Manager${categoriesToColumnHeaders(categoryColumns)} |\\n`;\n prDesc += `| ---${categoryColumns.map(() => ' | ---').join('')} |\\n`;\n for (const [manager, typeCounts] of Object.entries(\n stats.tableStats[sortedBases[0]],\n )) {\n prDesc += `| ${manager}${renderRowCounts(categoryColumns, typeCounts)} |\\n`;\n }\n const sumRow = sumCategoryCounts(\n Object.values(stats.tableStats[sortedBases[0]]),\n categoryColumns,\n );\n prDesc += `| **Total**${renderRowCounts(categoryColumns, sumRow)} |\\n`;\n }\n\n prDesc += `\\n<small>Note that a single PR can update multiple files and/or managers, so the above rows may not align with the number of PRs being listed above.</small>\\n`;\n\n // provide a summary of the given security updates, as they're likely more important to the user\n if (Object.keys(stats.securityGroups).length) {\n prDesc += `\\n**Security updates**:\\n\\n`;\n for (const groupBranches of Object.values(stats.securityGroups)) {\n prDesc += describeSecurityGroup(groupBranches);\n }\n }\n\n if (\n commitHourlyLimit > 0 &&\n commitHourlyLimit < 5 &&\n commitHourlyLimit < stats.prCount\n ) {\n prDesc += emojify(\n `\\n\\n:children_crossing: Branch creation and rebasing will be limited to maximum ${commitHourlyLimit} per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for \\`commitHourlyLimit\\`](${GlobalConfig.get('productLinks').documentation}configuration-options/#commithourlylimit) for details.\\n\\n`,\n );\n } else if (\n prHourlyLimit > 0 &&\n prHourlyLimit < 5 &&\n prHourlyLimit < stats.prCount\n ) {\n prDesc += emojify(\n `\\n\\n:children_crossing: PR creation will be limited to maximum ${prHourlyLimit} per hour, so it doesn't swamp any CI resources or overwhelm the project. See [docs for \\`prHourlyLimit\\`](${GlobalConfig.get('productLinks').documentation}configuration-options/#prhourlylimit) for details.\\n\\n`,\n );\n }\n return prDesc;\n}\n\nfunction determineHourlyLimitsNotice(\n prHourlyLimit: number,\n commitHourlyLimit: number,\n prCount: number,\n): string {\n if (commitHourlyLimit === 0 && prHourlyLimit === 0) {\n return ' (with no configured maximum of PRs per hour)';\n }\n\n if (\n commitHourlyLimit > 0 &&\n commitHourlyLimit < 5 &&\n commitHourlyLimit < prCount\n ) {\n return emojify(\n ` (at a maximum of ${commitHourlyLimit} PR${commitHourlyLimit > 1 ? 's' : ''}/rebase${commitHourlyLimit > 1 ? 's' : ''} per hour)`,\n );\n }\n\n if (prHourlyLimit > 0 && prHourlyLimit < 5 && prHourlyLimit < prCount) {\n return emojify(\n ` (at a maximum of ${prHourlyLimit} PR${prHourlyLimit > 1 ? 's' : ''} per hour)`,\n );\n }\n\n return '';\n}\n"],"mappings":"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"}
|
|
@@ -5,7 +5,8 @@ import { ensureComment } from "../../../modules/platform/comment.js";
|
|
|
5
5
|
import { getDepWarningsOnboardingPR, getErrors, getWarnings } from "../errors-warnings.js";
|
|
6
6
|
import { getBaseBranchDesc } from "../onboarding/pr/base-branch.js";
|
|
7
7
|
import { getScheduleDesc } from "../onboarding/pr/config-description.js";
|
|
8
|
-
import {
|
|
8
|
+
import { getPackageFilesDesc, getPackageFilesSummary } from "../onboarding/pr/package-files.js";
|
|
9
|
+
import { getExpectedPrList, getExpectedPrListSummary } from "../onboarding/pr/pr-list.js";
|
|
9
10
|
import { isArray, isString } from "@sindresorhus/is";
|
|
10
11
|
//#region lib/workers/repository/reconfigure/comment.ts
|
|
11
12
|
async function ensureReconfigurePrComment(config, packageFiles, branches, branchName, pr) {
|
|
@@ -22,11 +23,9 @@ async function ensureReconfigurePrComment(config, packageFiles, branches, branch
|
|
|
22
23
|
{{ERRORS}}
|
|
23
24
|
`;
|
|
24
25
|
let prBody = prCommentTemplate;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
prBody = `${prBody.replace("{{PACKAGE FILES}}", `### Detected Package Files\n\n${files.join("\n")}`)}\n`;
|
|
29
|
-
} else prBody = prBody.replace("{{PACKAGE FILES}}\n", "");
|
|
26
|
+
const packageFilesDesc = getPackageFilesDesc(packageFiles);
|
|
27
|
+
if (packageFilesDesc) prBody = `${prBody.replace("{{PACKAGE FILES}}", packageFilesDesc)}\n`;
|
|
28
|
+
else prBody = prBody.replace("{{PACKAGE FILES}}\n", "");
|
|
30
29
|
let configDesc = "";
|
|
31
30
|
if (GlobalConfig.get("dryRun")) logger.info(`DRY-RUN: Would check branch ${branchName}`);
|
|
32
31
|
else configDesc = getConfigDesc(config);
|
|
@@ -34,7 +33,13 @@ async function ensureReconfigurePrComment(config, packageFiles, branches, branch
|
|
|
34
33
|
prBody = prBody.replace("{{WARNINGS}}\n", getWarnings(config) + getDepWarningsOnboardingPR(packageFiles, config));
|
|
35
34
|
prBody = prBody.replace("{{ERRORS}}\n", getErrors(config));
|
|
36
35
|
prBody = prBody.replace("{{BASEBRANCH}}\n", getBaseBranchDesc(config));
|
|
37
|
-
|
|
36
|
+
const prList = getExpectedPrList(config, branches);
|
|
37
|
+
prBody = prBody.replace("{{PRLIST}}\n", prList);
|
|
38
|
+
if (prBody.length > platform.maxBodyLength()) {
|
|
39
|
+
logger.debug("Reconfigure PR body exceeds platform limit, switching to summary PR list and package files");
|
|
40
|
+
prBody = prBody.replace(prList, getExpectedPrListSummary(config, branches));
|
|
41
|
+
if (packageFilesDesc) prBody = prBody.replace(packageFilesDesc, `### Detected Package Files\n\n${getPackageFilesSummary(packageFiles)}`);
|
|
42
|
+
}
|
|
38
43
|
logger.trace(`prBody:\n${prBody}`);
|
|
39
44
|
prBody = platform.massageMarkdown(prBody);
|
|
40
45
|
if (GlobalConfig.get("dryRun")) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment.js","names":[],"sources":["../../../../lib/workers/repository/reconfigure/comment.ts"],"sourcesContent":["import { isArray, isString } from '@sindresorhus/is';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport type { RenovateConfig } from '../../../config/types.ts';\nimport { logger } from '../../../logger/index.ts';\nimport type { PackageFile } from '../../../modules/manager/types.ts';\nimport { ensureComment } from '../../../modules/platform/comment.ts';\nimport type { Pr } from '../../../modules/platform/index.ts';\nimport { platform } from '../../../modules/platform/index.ts';\nimport type { BranchConfig } from '../../types.ts';\nimport {\n getDepWarningsOnboardingPR,\n getErrors,\n getWarnings,\n} from '../errors-warnings.ts';\nimport { getBaseBranchDesc } from '../onboarding/pr/base-branch.ts';\nimport { getScheduleDesc } from '../onboarding/pr/config-description.ts';\nimport { getExpectedPrList
|
|
1
|
+
{"version":3,"file":"comment.js","names":[],"sources":["../../../../lib/workers/repository/reconfigure/comment.ts"],"sourcesContent":["import { isArray, isString } from '@sindresorhus/is';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport type { RenovateConfig } from '../../../config/types.ts';\nimport { logger } from '../../../logger/index.ts';\nimport type { PackageFile } from '../../../modules/manager/types.ts';\nimport { ensureComment } from '../../../modules/platform/comment.ts';\nimport type { Pr } from '../../../modules/platform/index.ts';\nimport { platform } from '../../../modules/platform/index.ts';\nimport type { BranchConfig } from '../../types.ts';\nimport {\n getDepWarningsOnboardingPR,\n getErrors,\n getWarnings,\n} from '../errors-warnings.ts';\nimport { getBaseBranchDesc } from '../onboarding/pr/base-branch.ts';\nimport { getScheduleDesc } from '../onboarding/pr/config-description.ts';\nimport {\n getPackageFilesDesc,\n getPackageFilesSummary,\n} from '../onboarding/pr/package-files.ts';\nimport {\n getExpectedPrList,\n getExpectedPrListSummary,\n} from '../onboarding/pr/pr-list.ts';\n\nexport async function ensureReconfigurePrComment(\n config: RenovateConfig,\n packageFiles: Record<string, PackageFile[]> | null,\n branches: BranchConfig[],\n branchName: string,\n pr: Pr,\n): Promise<boolean> {\n logger.debug('ensureReconfigurePrComment()');\n logger.trace({ config });\n let prCommentTemplate = `This is a reconfigure PR comment to help you understand and re-configure your renovate bot settings. If this Reconfigure PR were to be merged, we'd expect to see the following outcome:\\n\\n`;\n\n // TODO #22198\n prCommentTemplate += `\n---\n{{PACKAGE FILES}}\n{{CONFIG}}\n{{BASEBRANCH}}\n{{PRLIST}}\n{{WARNINGS}}\n{{ERRORS}}\n`;\n let prBody = prCommentTemplate;\n const packageFilesDesc = getPackageFilesDesc(packageFiles);\n if (packageFilesDesc) {\n prBody = `${prBody.replace('{{PACKAGE FILES}}', packageFilesDesc)}\\n`;\n } else {\n prBody = prBody.replace('{{PACKAGE FILES}}\\n', '');\n }\n let configDesc = '';\n if (GlobalConfig.get('dryRun')) {\n logger.info(`DRY-RUN: Would check branch ${branchName}`);\n } else {\n configDesc = getConfigDesc(config);\n }\n prBody = prBody.replace('{{CONFIG}}\\n', configDesc);\n prBody = prBody.replace(\n '{{WARNINGS}}\\n',\n getWarnings(config) + getDepWarningsOnboardingPR(packageFiles!, config),\n );\n prBody = prBody.replace('{{ERRORS}}\\n', getErrors(config));\n prBody = prBody.replace('{{BASEBRANCH}}\\n', getBaseBranchDesc(config));\n const prList = getExpectedPrList(config, branches);\n prBody = prBody.replace('{{PRLIST}}\\n', prList);\n\n if (prBody.length > platform.maxBodyLength()) {\n logger.debug(\n 'Reconfigure PR body exceeds platform limit, switching to summary PR list and package files',\n );\n prBody = prBody.replace(prList, getExpectedPrListSummary(config, branches));\n if (packageFilesDesc) {\n prBody = prBody.replace(\n packageFilesDesc,\n `### Detected Package Files\\n\\n${getPackageFilesSummary(packageFiles)}`,\n );\n }\n }\n\n logger.trace(`prBody:\\n${prBody}`);\n\n prBody = platform.massageMarkdown(prBody);\n\n if (GlobalConfig.get('dryRun')) {\n logger.info('DRY-RUN: Would ensure comment');\n return true;\n }\n\n return await ensureComment({\n number: pr.number,\n topic: 'Reconfigure PR Results',\n content: prBody,\n });\n}\n\nfunction getDescriptionArray(config: RenovateConfig): string[] {\n logger.debug('getDescriptionArray()');\n logger.trace({ config });\n const desc = isArray(config.description, isString) ? config.description : [];\n return desc.concat(getScheduleDesc(config));\n}\n\nexport function getConfigDesc(config: RenovateConfig): string {\n logger.debug('getConfigDesc()');\n logger.trace({ config });\n const descriptionArr = getDescriptionArray(config);\n if (!descriptionArr.length) {\n logger.debug('No config description found');\n return '';\n }\n logger.debug(`Found description array with length:${descriptionArr.length}`);\n let desc = `\\n### Configuration Summary\\n\\nBased on the default config's presets, Renovate will:\\n\\n`;\n descriptionArr.forEach((d) => {\n desc += ` - ${d}\\n`;\n });\n desc += '\\n\\n---\\n';\n return desc;\n}\n"],"mappings":";;;;;;;;;;;AAyBA,eAAsB,2BACpB,QACA,cACA,UACA,YACA,IACkB;CAClB,OAAO,MAAM,8BAA8B;CAC3C,OAAO,MAAM,EAAE,OAAO,CAAC;CACvB,IAAI,oBAAoB;CAGxB,qBAAqB;;;;;;;;;CASrB,IAAI,SAAS;CACb,MAAM,mBAAmB,oBAAoB,YAAY;CACzD,IAAI,kBACF,SAAS,GAAG,OAAO,QAAQ,qBAAqB,gBAAgB,EAAE;MAElE,SAAS,OAAO,QAAQ,uBAAuB,EAAE;CAEnD,IAAI,aAAa;CACjB,IAAI,aAAa,IAAI,QAAQ,GAC3B,OAAO,KAAK,+BAA+B,YAAY;MAEvD,aAAa,cAAc,MAAM;CAEnC,SAAS,OAAO,QAAQ,gBAAgB,UAAU;CAClD,SAAS,OAAO,QACd,kBACA,YAAY,MAAM,IAAI,2BAA2B,cAAe,MAAM,CACxE;CACA,SAAS,OAAO,QAAQ,gBAAgB,UAAU,MAAM,CAAC;CACzD,SAAS,OAAO,QAAQ,oBAAoB,kBAAkB,MAAM,CAAC;CACrE,MAAM,SAAS,kBAAkB,QAAQ,QAAQ;CACjD,SAAS,OAAO,QAAQ,gBAAgB,MAAM;CAE9C,IAAI,OAAO,SAAS,SAAS,cAAc,GAAG;EAC5C,OAAO,MACL,4FACF;EACA,SAAS,OAAO,QAAQ,QAAQ,yBAAyB,QAAQ,QAAQ,CAAC;EAC1E,IAAI,kBACF,SAAS,OAAO,QACd,kBACA,iCAAiC,uBAAuB,YAAY,GACtE;CAEJ;CAEA,OAAO,MAAM,YAAY,QAAQ;CAEjC,SAAS,SAAS,gBAAgB,MAAM;CAExC,IAAI,aAAa,IAAI,QAAQ,GAAG;EAC9B,OAAO,KAAK,+BAA+B;EAC3C,OAAO;CACT;CAEA,OAAO,MAAM,cAAc;EACzB,QAAQ,GAAG;EACX,OAAO;EACP,SAAS;CACX,CAAC;AACH;AAEA,SAAS,oBAAoB,QAAkC;CAC7D,OAAO,MAAM,uBAAuB;CACpC,OAAO,MAAM,EAAE,OAAO,CAAC;CAEvB,QADa,QAAQ,OAAO,aAAa,QAAQ,IAAI,OAAO,cAAc,CAAC,EAAA,CAC/D,OAAO,gBAAgB,MAAM,CAAC;AAC5C;AAEA,SAAgB,cAAc,QAAgC;CAC5D,OAAO,MAAM,iBAAiB;CAC9B,OAAO,MAAM,EAAE,OAAO,CAAC;CACvB,MAAM,iBAAiB,oBAAoB,MAAM;CACjD,IAAI,CAAC,eAAe,QAAQ;EAC1B,OAAO,MAAM,6BAA6B;EAC1C,OAAO;CACT;CACA,OAAO,MAAM,uCAAuC,eAAe,QAAQ;CAC3E,IAAI,OAAO;CACX,eAAe,SAAS,MAAM;EAC5B,QAAQ,OAAO,EAAE;CACnB,CAAC;CACD,QAAQ;CACR,OAAO;AACT"}
|
package/package.json
CHANGED
package/renovate-schema.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$id": "https://docs.renovatebot.com/renovate-schema.json",
|
|
3
|
-
"title": "JSON schema for Renovate 43.
|
|
3
|
+
"title": "JSON schema for Renovate 43.275.0 config files (https://renovatebot.com/)",
|
|
4
4
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
5
|
-
"x-renovate-version": "43.
|
|
5
|
+
"x-renovate-version": "43.275.0",
|
|
6
6
|
"allowComments": true,
|
|
7
7
|
"type": "object",
|
|
8
8
|
"definitions": {
|