renovate 44.33.2 → 44.34.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.
Files changed (28) hide show
  1. package/dist/config/types.d.ts +2 -1
  2. package/dist/config/types.js.map +1 -1
  3. package/dist/config/validation-helpers/match-base-branches.js +2 -1
  4. package/dist/config/validation-helpers/match-base-branches.js.map +1 -1
  5. package/dist/config/validation-helpers/regex-glob-matchers.js +4 -3
  6. package/dist/config/validation-helpers/regex-glob-matchers.js.map +1 -1
  7. package/dist/config/validation-helpers/types.d.ts +17 -0
  8. package/dist/config/validation-helpers/types.js +16 -0
  9. package/dist/config/validation-helpers/types.js.map +1 -0
  10. package/dist/config/validation-helpers/utils.js +12 -11
  11. package/dist/config/validation-helpers/utils.js.map +1 -1
  12. package/dist/config/validation.js +80 -79
  13. package/dist/config/validation.js.map +1 -1
  14. package/dist/modules/manager/fingerprint.generated.js +1 -1
  15. package/dist/modules/manager/fingerprint.generated.js.map +1 -1
  16. package/dist/modules/manager/poetry/artifacts.js +15 -8
  17. package/dist/modules/manager/poetry/artifacts.js.map +1 -1
  18. package/dist/modules/manager/types.d.ts +1 -0
  19. package/dist/workers/repository/update/pr/changelog/bitbucket/source.js +4 -0
  20. package/dist/workers/repository/update/pr/changelog/bitbucket/source.js.map +1 -1
  21. package/dist/workers/repository/update/pr/changelog/bitbucket-server/source.js +5 -1
  22. package/dist/workers/repository/update/pr/changelog/bitbucket-server/source.js.map +1 -1
  23. package/dist/workers/repository/update/pr/changelog/release-notes.js +7 -13
  24. package/dist/workers/repository/update/pr/changelog/release-notes.js.map +1 -1
  25. package/dist/workers/repository/update/pr/changelog/source.js +17 -3
  26. package/dist/workers/repository/update/pr/changelog/source.js.map +1 -1
  27. package/package.json +3 -3
  28. package/renovate-schema.json +2 -2
@@ -22,6 +22,7 @@ import { getExpression } from "../util/jsonata.js";
22
22
  import { hasValidSchedule, hasValidTimezone } from "../workers/repository/update/branch/schedule.js";
23
23
  import { isRelativePresetReference, parsePreset } from "./presets/parse.js";
24
24
  import { resolveConfigPresets } from "./presets/index.js";
25
+ import { ConfigValidationTopic } from "./validation-helpers/types.js";
25
26
  import { check } from "./validation-helpers/match-base-branches.js";
26
27
  import { check as check$1 } from "./validation-helpers/regex-glob-matchers.js";
27
28
  import { getParentName, isFalseGlobal, validateJSONataManagerFields, validateNumber, validatePlainObject, validateRegexManagerFields } from "./validation-helpers/utils.js";
@@ -151,13 +152,13 @@ async function validateConfig(configType, config, isPreset, parentPath) {
151
152
  /* v8 ignore next 7 -- TODO: add test */
152
153
  if (key === "__proto__") {
153
154
  errors.push({
154
- topic: "Config security error",
155
+ topic: ConfigValidationTopic.Security,
155
156
  message: "__proto__"
156
157
  });
157
158
  continue;
158
159
  }
159
160
  if (parentPath && parentPath !== "onboardingConfig" && !repoEntryRe.test(parentPath) && topLevelObjects.includes(key)) errors.push({
160
- topic: "Configuration Error",
161
+ topic: ConfigValidationTopic.Error,
161
162
  message: `The "${key}" object can only be configured at the top level of a config but was found inside "${parentPath}"`
162
163
  });
163
164
  if (isGlobalOption(key)) {
@@ -166,7 +167,7 @@ async function validateConfig(configType, config, isPreset, parentPath) {
166
167
  continue;
167
168
  } else if (!isFalseGlobal(key, parentPath) && !(configType === "inherit" && isInhertConfigOption(key))) {
168
169
  warnings.push({
169
- topic: "Configuration Error",
170
+ topic: ConfigValidationTopic.Error,
170
171
  message: `The "${key}" option is a global option reserved only for Renovate's global configuration and cannot be configured within a repository's config file.`
171
172
  });
172
173
  continue;
@@ -175,28 +176,28 @@ async function validateConfig(configType, config, isPreset, parentPath) {
175
176
  if (key === "enabledManagers" && val) {
176
177
  const unsupportedManagers = getUnsupportedEnabledManagers(val);
177
178
  if (isNonEmptyArray(unsupportedManagers)) errors.push({
178
- topic: "Configuration Error",
179
+ topic: ConfigValidationTopic.Error,
179
180
  message: `The following managers configured in enabledManagers are not supported: "${unsupportedManagers.join(", ")}"`
180
181
  });
181
182
  }
182
183
  if (key === "registryUrls" && !parentPath && isNonEmptyArray(val)) warnings.push({
183
- topic: "Configuration Warning",
184
+ topic: ConfigValidationTopic.Warning,
184
185
  message: "Setting `registryUrls` at the top level of your config will apply it to all managers and datasources, which can cause the wrong registry URL to be used for some packages. Use `registryUrls` inside `packageRules` to target specific managers or packages."
185
186
  });
186
187
  if (key === "defaultRegistryUrls" && !parentPath && isNonEmptyArray(val)) warnings.push({
187
- topic: "Configuration Warning",
188
+ topic: ConfigValidationTopic.Warning,
188
189
  message: "Setting `defaultRegistryUrls` at the top level of your config will apply it to all managers and datasources, which can cause the wrong registry URL to be used for some packages. Use `defaultRegistryUrls` inside `packageRules` to target specific managers or packages."
189
190
  });
190
191
  if (!isIgnored(key) && !is.function(val)) {
191
192
  if (getDeprecationMessage(key)) warnings.push({
192
- topic: "Deprecation Warning",
193
+ topic: ConfigValidationTopic.Deprecation,
193
194
  message: getDeprecationMessage(key)
194
195
  });
195
196
  if (optionSupportsTemplating.has(key) && val) try {
196
197
  validate(val.toString());
197
198
  } catch {
198
199
  errors.push({
199
- topic: "Configuration Error",
200
+ topic: ConfigValidationTopic.Error,
200
201
  message: `Invalid template in config path: ${currentPath}`
201
202
  });
202
203
  }
@@ -210,13 +211,13 @@ async function validateConfig(configType, config, isPreset, parentPath) {
210
211
  }
211
212
  // v8 ignore else -- intentionally unhandled - if we knew what was to be covered here, we'd add validation
212
213
  if (!optionTypes[key]) errors.push({
213
- topic: "Configuration Error",
214
+ topic: ConfigValidationTopic.Error,
214
215
  message: `Invalid configuration option: ${currentPath}`
215
216
  });
216
217
  else if (key === "schedule") {
217
218
  const [validSchedule, errorMessage] = hasValidSchedule(val);
218
219
  if (!validSchedule) errors.push({
219
- topic: "Configuration Error",
220
+ topic: ConfigValidationTopic.Error,
220
221
  message: `Invalid ${currentPath}: \`${errorMessage}\``
221
222
  });
222
223
  } else if ([
@@ -226,20 +227,20 @@ async function validateConfig(configType, config, isPreset, parentPath) {
226
227
  "matchNewValue"
227
228
  ].includes(key) && isRegexMatch(val)) {
228
229
  if (!getRegexPredicate(val)) errors.push({
229
- topic: "Configuration Error",
230
+ topic: ConfigValidationTopic.Error,
230
231
  message: `Invalid regExp for ${currentPath}: \`${val}\``
231
232
  });
232
233
  } else if (key === "timezone" && val !== null) {
233
234
  const [validTimezone, errorMessage] = hasValidTimezone(val);
234
235
  if (!validTimezone) errors.push({
235
- topic: "Configuration Error",
236
+ topic: ConfigValidationTopic.Error,
236
237
  message: `${currentPath}: ${errorMessage}`
237
238
  });
238
239
  } else if (val !== null) {
239
240
  const type = optionTypes[key];
240
241
  if (type === "boolean") {
241
242
  if (val !== true && val !== false) errors.push({
242
- topic: "Configuration Error",
243
+ topic: ConfigValidationTopic.Error,
243
244
  message: `Configuration option \`${currentPath}\` should be boolean. Found: ${JSON.stringify(val)} (${typeof val})`
244
245
  });
245
246
  } else if (type === "integer") {
@@ -257,18 +258,18 @@ async function validateConfig(configType, config, isPreset, parentPath) {
257
258
  }));
258
259
  if (key === "extends") for (const subval of val) if (isString(subval)) {
259
260
  if (configType !== "global" && subval.startsWith("global:")) errors.push({
260
- topic: "Configuration Error",
261
+ topic: ConfigValidationTopic.Error,
261
262
  message: `${currentPath}: you cannot extend from "global:" presets in a repository config's "extends"`
262
263
  });
263
264
  if (parentName === "packageRules" && subval.startsWith("group:")) warnings.push({
264
- topic: "Configuration Warning",
265
+ topic: ConfigValidationTopic.Warning,
265
266
  message: `${currentPath}: you should not extend "group:" presets`
266
267
  });
267
268
  if (tzRe.test(subval)) {
268
269
  const [, timezone] = tzRe.exec(subval);
269
270
  const [validTimezone, errorMessage] = hasValidTimezone(timezone);
270
271
  if (!validTimezone) errors.push({
271
- topic: "Configuration Error",
272
+ topic: ConfigValidationTopic.Error,
272
273
  message: `${currentPath}: ${errorMessage}`
273
274
  });
274
275
  }
@@ -276,17 +277,17 @@ async function validateConfig(configType, config, isPreset, parentPath) {
276
277
  parsePreset(subval);
277
278
  } catch {
278
279
  errors.push({
279
- topic: "Configuration Error",
280
+ topic: ConfigValidationTopic.Error,
280
281
  message: `${currentPath}: preset "${subval}" is not valid`
281
282
  });
282
283
  }
283
284
  } else errors.push({
284
- topic: "Configuration Error",
285
+ topic: ConfigValidationTopic.Error,
285
286
  message: `${currentPath}: preset value is not a string`
286
287
  });
287
288
  if (key === "commitTrailers") {
288
289
  for (const subval of val) if (!isValidCommitTrailer(subval)) errors.push({
289
- topic: "Configuration Error",
290
+ topic: ConfigValidationTopic.Error,
290
291
  message: `Invalid commit trailer: \`${JSON.stringify(subval)}\`. Must be a single-line string in the form \`Key: value\`, where the key contains only letters, digits and \`-\`.`
291
292
  });
292
293
  }
@@ -324,20 +325,20 @@ async function validateConfig(configType, config, isPreset, parentPath) {
324
325
  if (!selectorLength) if (hasRelativePresets) {
325
326
  const message = `${currentPath}[${subIndex}]: this rule extends a relative preset that cannot be resolved during validation, so its selectors could not be checked. Rule: ${JSON.stringify(packageRule)}`;
326
327
  warnings.push({
327
- topic: "Configuration Error",
328
+ topic: ConfigValidationTopic.Error,
328
329
  message
329
330
  });
330
331
  } else {
331
332
  const message = `${currentPath}[${subIndex}]: Each packageRule must contain at least one match* or exclude* selector. Rule: ${JSON.stringify(packageRule)}`;
332
333
  errors.push({
333
- topic: "Configuration Error",
334
+ topic: ConfigValidationTopic.Error,
334
335
  message
335
336
  });
336
337
  }
337
338
  if (!hasRelativePresets && selectorLength === Object.keys(resolvedRule).length) {
338
339
  const message = `${currentPath}[${subIndex}]: Each packageRule must contain at least one non-match* or non-exclude* field. Rule: ${JSON.stringify(packageRule)}`;
339
340
  warnings.push({
340
- topic: "Configuration Error",
341
+ topic: ConfigValidationTopic.Error,
341
342
  message
342
343
  });
343
344
  }
@@ -361,13 +362,13 @@ async function validateConfig(configType, config, isPreset, parentPath) {
361
362
  for (const option of preLookupOptions) if (resolvedRule[option] !== void 0) {
362
363
  const message = `${currentPath}[${subIndex}]: packageRules cannot combine both matchUpdateTypes and ${option}. Rule: ${JSON.stringify(packageRule)}`;
363
364
  errors.push({
364
- topic: "Configuration Error",
365
+ topic: ConfigValidationTopic.Error,
365
366
  message
366
367
  });
367
368
  }
368
369
  }
369
370
  } else errors.push({
370
- topic: "Configuration Error",
371
+ topic: ConfigValidationTopic.Error,
371
372
  message: `${currentPath} must contain JSON objects`
372
373
  });
373
374
  if (key === "customManagers") {
@@ -391,7 +392,7 @@ async function validateConfig(configType, config, isPreset, parentPath) {
391
392
  for (const customManager of val) if (Object.keys(customManager).some((k) => !allowedKeys.includes(k))) {
392
393
  const disallowedKeys = Object.keys(customManager).filter((k) => !allowedKeys.includes(k));
393
394
  errors.push({
394
- topic: "Configuration Error",
395
+ topic: ConfigValidationTopic.Error,
395
396
  message: `Custom Manager contains disallowed fields: ${disallowedKeys.join(", ")}`
396
397
  });
397
398
  } else if (isNonEmptyString(customManager.customType) && isCustomManager(customManager.customType)) if (isNonEmptyArray(customManager.managerFilePatterns)) switch (customManager.customType) {
@@ -401,15 +402,15 @@ async function validateConfig(configType, config, isPreset, parentPath) {
401
402
  case "jsonata": validateJSONataManagerFields(customManager, currentPath, errors);
402
403
  }
403
404
  else errors.push({
404
- topic: "Configuration Error",
405
+ topic: ConfigValidationTopic.Error,
405
406
  message: `Each Custom Manager must contain a non-empty managerFilePatterns array`
406
407
  });
407
408
  else if (isEmptyString(customManager.customType) || isUndefined(customManager.customType)) errors.push({
408
- topic: "Configuration Error",
409
+ topic: ConfigValidationTopic.Error,
409
410
  message: `Each Custom Manager must contain a non-empty customType string`
410
411
  });
411
412
  else errors.push({
412
- topic: "Configuration Error",
413
+ topic: ConfigValidationTopic.Error,
413
414
  message: `Invalid customType: ${customManager.customType}. Key is not a custom manager`
414
415
  });
415
416
  }
@@ -420,57 +421,57 @@ async function validateConfig(configType, config, isPreset, parentPath) {
420
421
  regEx(pattern.replace(startPattern, "/"));
421
422
  } catch {
422
423
  errors.push({
423
- topic: "Configuration Error",
424
+ topic: ConfigValidationTopic.Error,
424
425
  message: `Invalid regExp for ${currentPath}: \`${pattern}\``
425
426
  });
426
427
  }
427
428
  }
428
429
  if (key === "baseBranchPatterns") {
429
430
  for (const baseBranchPattern of val) if (isRegexMatch(baseBranchPattern) && !getRegexPredicate(baseBranchPattern)) errors.push({
430
- topic: "Configuration Error",
431
+ topic: ConfigValidationTopic.Error,
431
432
  message: `Invalid regExp for ${currentPath}: \`${baseBranchPattern}\``
432
433
  });
433
434
  }
434
435
  if ((selectors.includes(key) || key === "matchCurrentVersion" || key === "matchCurrentValue") && !rulesRe.test(parentPath) && (isString(parentPath) || !isPreset)) errors.push({
435
- topic: "Configuration Error",
436
+ topic: ConfigValidationTopic.Error,
436
437
  message: `${currentPath}: ${key} should be inside a \`packageRule\` only`
437
438
  });
438
439
  } else errors.push({
439
- topic: "Configuration Error",
440
+ topic: ConfigValidationTopic.Error,
440
441
  message: `Configuration option \`${currentPath}\` should be a list (Array)`
441
442
  });
442
443
  else if (type === "string") {
443
444
  if (!isString(val)) errors.push({
444
- topic: "Configuration Error",
445
+ topic: ConfigValidationTopic.Error,
445
446
  message: `Configuration option \`${currentPath}\` should be a string`
446
447
  });
447
448
  } else if (type === "object") if (isPlainObject(val)) {
448
449
  if (key === "registryAliases") {
449
450
  const res = validatePlainObject(val);
450
451
  if (res !== true) errors.push({
451
- topic: "Configuration Error",
452
+ topic: ConfigValidationTopic.Error,
452
453
  message: `Invalid \`${currentPath}.${key}.${res}\` configuration: value is not a string`
453
454
  });
454
455
  } else if (key === "env") {
455
456
  const allowedEnvVars = configType === "global" ? config.allowedEnv ?? [] : GlobalConfig.get("allowedEnv");
456
457
  for (const [envVarName, envVarValue] of Object.entries(val)) {
457
458
  if (!isString(envVarValue)) errors.push({
458
- topic: "Configuration Error",
459
+ topic: ConfigValidationTopic.Error,
459
460
  message: `Invalid env variable value: \`${currentPath}.${envVarName}\` must be a string.`
460
461
  });
461
462
  if (!matchRegexOrGlobList(envVarName, allowedEnvVars)) errors.push({
462
- topic: "Configuration Error",
463
+ topic: ConfigValidationTopic.Error,
463
464
  message: `Env variable name \`${envVarName}\` is not allowed by this bot's \`allowedEnv\`.`
464
465
  });
465
466
  }
466
467
  } else if (key === "statusCheckNames") for (const [statusCheckKey, statusCheckValue] of Object.entries(val)) {
467
468
  if (!allowedStatusCheckStrings.includes(statusCheckKey)) errors.push({
468
- topic: "Configuration Error",
469
+ topic: ConfigValidationTopic.Error,
469
470
  message: `Invalid \`${currentPath}.${key}.${statusCheckKey}\` configuration: key is not allowed.`
470
471
  });
471
472
  if (!(isString(statusCheckValue) || null === statusCheckValue)) {
472
473
  errors.push({
473
- topic: "Configuration Error",
474
+ topic: ConfigValidationTopic.Error,
474
475
  message: `Invalid \`${currentPath}.${statusCheckKey}\` configuration: status check is not a string.`
475
476
  });
476
477
  continue;
@@ -484,12 +485,12 @@ async function validateConfig(configType, config, isPreset, parentPath) {
484
485
  ];
485
486
  for (const [statusCheckKey, statusCheckValue] of Object.entries(val)) {
486
487
  if (!allowedStatusCheckStrings.includes(statusCheckKey)) errors.push({
487
- topic: "Configuration Error",
488
+ topic: ConfigValidationTopic.Error,
488
489
  message: `Invalid \`${currentPath}.${key}.${statusCheckKey}\` configuration: key is not allowed.`
489
490
  });
490
491
  if (!isString(statusCheckValue) || !allowedWhenValues.includes(statusCheckValue)) {
491
492
  errors.push({
492
- topic: "Configuration Error",
493
+ topic: ConfigValidationTopic.Error,
493
494
  message: `Invalid \`${currentPath}.${statusCheckKey}\` configuration: value must be one of "always", "never", or "failed".`
494
495
  });
495
496
  continue;
@@ -505,33 +506,33 @@ async function validateConfig(configType, config, isPreset, parentPath) {
505
506
  for (const [customDatasourceName, customDatasourceValue] of Object.entries(val)) {
506
507
  if (!isPlainObject(customDatasourceValue)) {
507
508
  errors.push({
508
- topic: "Configuration Error",
509
+ topic: ConfigValidationTopic.Error,
509
510
  message: `Invalid \`${currentPath}.${customDatasourceName}\` configuration: customDatasource is not an object`
510
511
  });
511
512
  continue;
512
513
  }
513
514
  for (const [subKey, subValue] of Object.entries(customDatasourceValue)) if (!allowedKeys.includes(subKey)) errors.push({
514
- topic: "Configuration Error",
515
+ topic: ConfigValidationTopic.Error,
515
516
  message: `Invalid \`${currentPath}.${subKey}\` configuration: key is not allowed`
516
517
  });
517
518
  else if (subKey === "transformTemplates") {
518
519
  if (!isArray(subValue, isString)) errors.push({
519
- topic: "Configuration Error",
520
+ topic: ConfigValidationTopic.Error,
520
521
  message: `Invalid \`${currentPath}.${subKey}\` configuration: is not an array of string`
521
522
  });
522
523
  } else if (subKey === "description") {
523
524
  if (!(isString(subValue) || isArray(subValue, isString))) errors.push({
524
- topic: "Configuration Error",
525
+ topic: ConfigValidationTopic.Error,
525
526
  message: `Invalid \`${currentPath}.${subKey}\` configuration: is not an array of strings`
526
527
  });
527
528
  } else if (!isString(subValue)) errors.push({
528
- topic: "Configuration Error",
529
+ topic: ConfigValidationTopic.Error,
529
530
  message: `Invalid \`${currentPath}.${subKey}\` configuration: is a string`
530
531
  });
531
532
  }
532
533
  } else if (key === "installTools") {
533
534
  for (const toolName of Object.keys(val)) if (!isToolName(toolName)) warnings.push({
534
- topic: "Configuration Error",
535
+ topic: ConfigValidationTopic.Error,
535
536
  message: `Invalid \`${currentPath}.${toolName}\` configuration: not a valid tool name.`
536
537
  });
537
538
  } else if (key === "constraints") {
@@ -539,19 +540,19 @@ async function validateConfig(configType, config, isPreset, parentPath) {
539
540
  for (const [k, v] of Object.entries(val)) {
540
541
  if (!isString(v)) {
541
542
  errors.push({
542
- topic: "Configuration Error",
543
+ topic: ConfigValidationTopic.Error,
543
544
  message: `Configuration option \`${currentPath}.${k}\` should be an object of key-value pairs of constraints and their value`
544
545
  });
545
546
  break;
546
547
  }
547
548
  if (!isConstraintName(k)) warnings.push({
548
- topic: "Configuration Error",
549
+ topic: ConfigValidationTopic.Error,
549
550
  message: `Configuration option \`${currentPath}.${k}\`: \`${k}\` is not a supported constraint name`
550
551
  });
551
552
  else if (isToolName(k)) {
552
553
  const versioningId = getToolConfig(k).versioning;
553
554
  if (!getVersioning(versioningId).isValid(v)) warnings.push({
554
- topic: "Configuration Error",
555
+ topic: ConfigValidationTopic.Error,
555
556
  message: `Configuration option \`${currentPath}.${k}=${v}\` is not a valid tool version constraint, according to \`${versioningId}\` versioning`
556
557
  });
557
558
  }
@@ -559,23 +560,23 @@ async function validateConfig(configType, config, isPreset, parentPath) {
559
560
  } else if (key === "constraintsVersioning") for (const [k, v] of Object.entries(val)) {
560
561
  if (!isString(v)) {
561
562
  errors.push({
562
- topic: "Configuration Error",
563
+ topic: ConfigValidationTopic.Error,
563
564
  message: `Configuration option \`${currentPath}.${k}\` should be an object of key-value pairs of additional constraint names and their versioning`
564
565
  });
565
566
  break;
566
567
  }
567
568
  if (isToolName(k)) errors.push({
568
- topic: "Configuration Error",
569
+ topic: ConfigValidationTopic.Error,
569
570
  message: `Configuration option \`${currentPath}.${k}\` is not a valid additional constraint name, as \`${k}\` is a tool name, and \`constraintsVersioning\` can only override the versioning for a non-tool constraint`
570
571
  });
571
572
  else if (isConstraintName(k)) {
572
573
  const versioningName = v.split(":")[0];
573
574
  if (!AllVersioningsListLiteral.includes(versioningName)) errors.push({
574
- topic: "Configuration Error",
575
+ topic: ConfigValidationTopic.Error,
575
576
  message: `Configuration option \`${currentPath}.${k}=${v}\`: \`${v}\` is not a valid versioning scheme`
576
577
  });
577
578
  } else errors.push({
578
- topic: "Configuration Error",
579
+ topic: ConfigValidationTopic.Error,
579
580
  message: `Configuration option \`${currentPath}.${k}\`: \`${k}\` is not a known additional constraint name`
580
581
  });
581
582
  }
@@ -585,7 +586,7 @@ async function validateConfig(configType, config, isPreset, parentPath) {
585
586
  errors = errors.concat(subValidation.errors);
586
587
  }
587
588
  } else errors.push({
588
- topic: "Configuration Error",
589
+ topic: ConfigValidationTopic.Error,
589
590
  message: `Configuration option \`${currentPath}\` should be a json object`
590
591
  });
591
592
  else
@@ -598,21 +599,21 @@ async function validateConfig(configType, config, isPreset, parentPath) {
598
599
  for (const rule of val) {
599
600
  if (isNonEmptyString(rule.matchHost)) {
600
601
  if (rule.matchHost.includes("://") && parseUrl(rule.matchHost) === null) errors.push({
601
- topic: "Configuration Error",
602
+ topic: ConfigValidationTopic.Error,
602
603
  message: `hostRules matchHost \`${rule.matchHost}\` is not a valid URL.`
603
604
  });
604
605
  } else if (isEmptyString(rule.matchHost)) errors.push({
605
- topic: "Configuration Error",
606
+ topic: ConfigValidationTopic.Error,
606
607
  message: "Invalid value for hostRules matchHost. It cannot be an empty string."
607
608
  });
608
609
  if (!rule.headers) continue;
609
610
  for (const [header, value] of Object.entries(rule.headers)) {
610
611
  if (!isString(value)) errors.push({
611
- topic: "Configuration Error",
612
+ topic: ConfigValidationTopic.Error,
612
613
  message: `Invalid hostRules headers value configuration: header must be a string.`
613
614
  });
614
615
  if (!matchRegexOrGlobList(header, allowedHeaders)) errors.push({
615
- topic: "Configuration Error",
616
+ topic: ConfigValidationTopic.Error,
616
617
  message: `hostRules header \`${header}\` is not allowed by this bot's \`allowedHeaders\`.`
617
618
  });
618
619
  }
@@ -621,7 +622,7 @@ async function validateConfig(configType, config, isPreset, parentPath) {
621
622
  if (key === "matchJsonata" && isArray(val, isString)) for (const expression of val) {
622
623
  const res = getExpression(expression);
623
624
  if (res instanceof Error) errors.push({
624
- topic: "Configuration Error",
625
+ topic: ConfigValidationTopic.Error,
625
626
  message: `Invalid JSONata expression for ${currentPath}: ${res.message}`
626
627
  });
627
628
  }
@@ -644,11 +645,11 @@ async function validateConfig(configType, config, isPreset, parentPath) {
644
645
  async function validateGlobalConfig(key, val, type, warnings, errors, currentPath, config) {
645
646
  /* v8 ignore next 5 -- not testable yet */
646
647
  if (getDeprecationMessage(key)) warnings.push({
647
- topic: "Deprecation Warning",
648
+ topic: ConfigValidationTopic.Deprecation,
648
649
  message: getDeprecationMessage(key)
649
650
  });
650
651
  if (key === "binarySource" && val === "docker") warnings.push({
651
- topic: "Deprecation Warning",
652
+ topic: ConfigValidationTopic.Deprecation,
652
653
  message: "Usage of `binarySource=docker` is deprecated, and will be removed in the future. Please migrate to `binarySource=install`. Feedback on the usage of `binarySource=docker` is welcome at https://github.com/renovatebot/renovate/discussions/40742"
653
654
  });
654
655
  if (val !== null) {
@@ -658,7 +659,7 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
658
659
  configFileNames: config.configFileNames,
659
660
  platform: config.platform
660
661
  }).includes(val)) warnings.push({
661
- topic: "Configuration Error",
662
+ topic: ConfigValidationTopic.Error,
662
663
  message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${getPossibleConfigFileNames({
663
664
  configFileNames: config.configFileNames,
664
665
  platform: config.platform
@@ -669,7 +670,7 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
669
670
  "disabled",
670
671
  "reset"
671
672
  ].includes(val)) warnings.push({
672
- topic: "Configuration Error",
673
+ topic: ConfigValidationTopic.Error,
673
674
  message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${[
674
675
  "enabled",
675
676
  "disabled",
@@ -681,7 +682,7 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
681
682
  "lookup",
682
683
  "full"
683
684
  ].includes(val)) warnings.push({
684
- topic: "Configuration Error",
685
+ topic: ConfigValidationTopic.Error,
685
686
  message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${[
686
687
  "extract",
687
688
  "lookup",
@@ -694,7 +695,7 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
694
695
  "install",
695
696
  "hermit"
696
697
  ].includes(val)) warnings.push({
697
- topic: "Configuration Error",
698
+ topic: ConfigValidationTopic.Error,
698
699
  message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${[
699
700
  "docker",
700
701
  "global",
@@ -707,7 +708,7 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
707
708
  "optional",
708
709
  "ignored"
709
710
  ].includes(val)) warnings.push({
710
- topic: "Configuration Error",
711
+ topic: ConfigValidationTopic.Error,
711
712
  message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${[
712
713
  "required",
713
714
  "optional",
@@ -719,7 +720,7 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
719
720
  "ssh",
720
721
  "endpoint"
721
722
  ].includes(val)) warnings.push({
722
- topic: "Configuration Error",
723
+ topic: ConfigValidationTopic.Error,
723
724
  message: `Invalid value \`${val}\` for \`${currentPath}\`. The allowed values are ${[
724
725
  "default",
725
726
  "ssh",
@@ -727,11 +728,11 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
727
728
  ].join(", ")}.`
728
729
  });
729
730
  if (key === "reportType" && ["s3", "file"].includes(val) && !isString(config.reportPath)) errors.push({
730
- topic: "Configuration Error",
731
+ topic: ConfigValidationTopic.Error,
731
732
  message: `reportType '${val}' requires a configured reportPath`
732
733
  });
733
734
  } else warnings.push({
734
- topic: "Configuration Error",
735
+ topic: ConfigValidationTopic.Error,
735
736
  message: `Configuration option \`${currentPath}\` should be a string.`
736
737
  });
737
738
  else if (type === "integer") {
@@ -739,7 +740,7 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
739
740
  warnings.push(...validateNumber(key, val, allowsNegative, currentPath));
740
741
  } else if (type === "boolean") {
741
742
  if (val !== true && val !== false) warnings.push({
742
- topic: "Configuration Error",
743
+ topic: ConfigValidationTopic.Error,
743
744
  message: `Configuration option \`${currentPath}\` should be a boolean. Found: ${JSON.stringify(val)} (${typeof val}).`
744
745
  });
745
746
  } else if (type === "array") if (isArray(val) && key !== "repositories") {
@@ -757,7 +758,7 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
757
758
  for (const value of val)
758
759
  // v8 ignore else -- TODO: add test #40625
759
760
  if (!allowedValues.includes(value)) warnings.push({
760
- topic: "Configuration Error",
761
+ topic: ConfigValidationTopic.Error,
761
762
  message: `Invalid value for \`${currentPath}\`. The allowed values are ${allowedValues.join(", ")}.`
762
763
  });
763
764
  }
@@ -766,13 +767,13 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
766
767
  for (const value of val)
767
768
  // v8 ignore else -- TODO: add test #40625
768
769
  if (!allowedValues.includes(value)) warnings.push({
769
- topic: "Configuration Error",
770
+ topic: ConfigValidationTopic.Error,
770
771
  message: `Invalid value \`${value}\` for \`${currentPath}\`. The allowed values are ${allowedValues.join(", ")}.`
771
772
  });
772
773
  }
773
774
  } else if (isArray(val)) for (const [subIndex, subval] of val.entries()) if (isPlainObject(subval)) {
774
775
  if (!isNonEmptyString(subval.repository)) errors.push({
775
- topic: "Configuration Error",
776
+ topic: ConfigValidationTopic.Error,
776
777
  message: `${currentPath}[${subIndex}]: each repository object entry must have a \`repository\` string property`
777
778
  });
778
779
  const { repository: _, ...repoEntryConfig } = subval;
@@ -785,15 +786,15 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
785
786
  errors.push(...subValidation.errors);
786
787
  } else if (isString(subval)) {
787
788
  if (!isNonEmptyStringAndNotWhitespace(subval)) warnings.push({
788
- topic: "Configuration Error",
789
+ topic: ConfigValidationTopic.Error,
789
790
  message: `${currentPath}[${subIndex}]: each repository string entry entry must be a non-empty string`
790
791
  });
791
792
  } else warnings.push({
792
- topic: "Configuration Error",
793
+ topic: ConfigValidationTopic.Error,
793
794
  message: `${currentPath}[${subIndex}]: invalid type, should be either a string or an object`
794
795
  });
795
796
  else warnings.push({
796
- topic: "Configuration Error",
797
+ topic: ConfigValidationTopic.Error,
797
798
  message: `Configuration option \`${currentPath}\` should be a list (Array).`
798
799
  });
799
800
  else if (type === "object") if (isPlainObject(val)) if (key === "onboardingConfig") {
@@ -807,18 +808,18 @@ async function validateGlobalConfig(key, val, type, warnings, errors, currentPat
807
808
  warnings.push(...validateNumber(key, subValue, allowsNegative, currentPath, subKey));
808
809
  if (!packageCacheNamespaces.includes(subKey) && !anyMatchRegexOrGlobList(packageCacheNamespaces, [subKey])) errors.push({
809
810
  message: `${currentPath}: namespace \`${subKey}\` does not exist`,
810
- topic: "Configuration Error"
811
+ topic: ConfigValidationTopic.Error
811
812
  });
812
813
  }
813
814
  else {
814
815
  const res = validatePlainObject(val);
815
816
  if (res !== true) warnings.push({
816
- topic: "Configuration Error",
817
+ topic: ConfigValidationTopic.Error,
817
818
  message: `Invalid \`${currentPath}.${res}\` configuration: value must be a string.`
818
819
  });
819
820
  }
820
821
  else warnings.push({
821
- topic: "Configuration Error",
822
+ topic: ConfigValidationTopic.Error,
822
823
  message: `Configuration option \`${currentPath}\` should be a JSON object.`
823
824
  });
824
825
  }