diff options
Diffstat (limited to 'lib/config/validation.ts')
-rw-r--r-- | lib/config/validation.ts | 151 |
1 files changed, 19 insertions, 132 deletions
diff --git a/lib/config/validation.ts b/lib/config/validation.ts index d139cb42c10..551c07ba9f0 100644 --- a/lib/config/validation.ts +++ b/lib/config/validation.ts @@ -1,11 +1,6 @@ import is from '@sindresorhus/is'; -import { logger } from '../logger'; import { allManagersList, getManagerList } from '../modules/manager'; import { isCustomManager } from '../modules/manager/custom'; -import type { - RegexManagerConfig, - RegexManagerTemplates, -} from '../modules/manager/custom/regex/types'; import type { CustomManager } from '../modules/manager/custom/types'; import type { HostRule } from '../types'; import { getExpression } from '../util/jsonata'; @@ -39,6 +34,13 @@ import { allowedStatusCheckStrings } from './types'; import * as managerValidator from './validation-helpers/managers'; import * as matchBaseBranchesValidator from './validation-helpers/match-base-branches'; import * as regexOrGlobValidator from './validation-helpers/regex-glob-matchers'; +import { + getParentName, + isFalseGlobal, + validateNumber, + validatePlainObject, + validateRegexManagerFields, +} from './validation-helpers/utils'; const options = getOptions(); @@ -84,42 +86,6 @@ function isIgnored(key: string): boolean { return ignoredNodes.includes(key); } -function validatePlainObject(val: Record<string, unknown>): true | string { - for (const [key, value] of Object.entries(val)) { - if (!is.string(value)) { - return key; - } - } - return true; -} - -function validateNumber( - key: string, - val: unknown, - currentPath?: string, - subKey?: string, -): ValidationMessage[] { - const errors: ValidationMessage[] = []; - const path = `${currentPath}${subKey ? '.' + subKey : ''}`; - if (is.number(val)) { - if (val < 0 && !optionAllowsNegativeIntegers.has(key)) { - errors.push({ - topic: 'Configuration Error', - message: `Configuration option \`${path}\` should be a positive integer. Found negative value instead.`, - }); - } - } else { - errors.push({ - topic: 'Configuration Error', - message: `Configuration option \`${path}\` should be an integer. Found: ${JSON.stringify( - val, - )} (${typeof val}).`, - }); - } - - return errors; -} - function getUnsupportedEnabledManagers(enabledManagers: string[]): string[] { return enabledManagers.filter( (manager) => !allManagersList.includes(manager.replace('custom.', '')), @@ -186,16 +152,6 @@ function initOptions(): void { optionsInitialized = true; } -export function getParentName(parentPath: string | undefined): string { - return parentPath - ? parentPath - .replace(regEx(/\.?encrypted$/), '') - .replace(regEx(/\[\d+\]$/), '') - .split('.') - .pop()! - : '.'; -} - export async function validateConfig( configType: 'global' | 'inherit' | 'repo', config: RenovateConfig, @@ -370,7 +326,8 @@ export async function validateConfig( }); } } else if (type === 'integer') { - errors.push(...validateNumber(key, val, currentPath)); + const allowsNegative = optionAllowsNegativeIntegers.has(key); + errors.push(...validateNumber(key, val, allowsNegative, currentPath)); } else if (type === 'array' && val) { if (is.array(val)) { for (const [subIndex, subval] of val.entries()) { @@ -865,65 +822,6 @@ export async function validateConfig( return { errors, warnings }; } -function hasField( - customManager: Partial<RegexManagerConfig>, - field: string, -): boolean { - const templateField = `${field}Template` as keyof RegexManagerTemplates; - return !!( - customManager[templateField] ?? - customManager.matchStrings?.some((matchString) => - matchString.includes(`(?<${field}>`), - ) - ); -} - -function validateRegexManagerFields( - customManager: Partial<RegexManagerConfig>, - currentPath: string, - errors: ValidationMessage[], -): void { - if (is.nonEmptyArray(customManager.matchStrings)) { - for (const matchString of customManager.matchStrings) { - try { - regEx(matchString); - } catch (err) { - logger.debug( - { err }, - 'customManager.matchStrings regEx validation error', - ); - errors.push({ - topic: 'Configuration Error', - message: `Invalid regExp for ${currentPath}: \`${matchString}\``, - }); - } - } - } else { - errors.push({ - topic: 'Configuration Error', - message: `Each Custom Manager must contain a non-empty matchStrings array`, - }); - } - - const mandatoryFields = ['currentValue', 'datasource']; - for (const field of mandatoryFields) { - if (!hasField(customManager, field)) { - errors.push({ - topic: 'Configuration Error', - message: `Regex Managers must contain ${field}Template configuration or regex group named ${field}`, - }); - } - } - - const nameFields = ['depName', 'packageName']; - if (!nameFields.some((field) => hasField(customManager, field))) { - errors.push({ - topic: 'Configuration Error', - message: `Regex Managers must contain depName or packageName regex groups or templates`, - }); - } -} - /** * Basic validation for global config options */ @@ -1013,7 +911,8 @@ async function validateGlobalConfig( }); } } else if (type === 'integer') { - warnings.push(...validateNumber(key, val, currentPath)); + const allowsNegative = optionAllowsNegativeIntegers.has(key); + warnings.push(...validateNumber(key, val, allowsNegative, currentPath)); } else if (type === 'boolean') { if (val !== true && val !== false) { warnings.push({ @@ -1079,8 +978,15 @@ async function validateGlobalConfig( } } else if (key === 'cacheTtlOverride') { for (const [subKey, subValue] of Object.entries(val)) { + const allowsNegative = optionAllowsNegativeIntegers.has(key); warnings.push( - ...validateNumber(key, subValue, currentPath, subKey), + ...validateNumber( + key, + subValue, + allowsNegative, + currentPath, + subKey, + ), ); } } else { @@ -1101,22 +1007,3 @@ async function validateGlobalConfig( } } } - -/** An option is a false global if it has the same name as a global only option - * but is actually just the field of a non global option or field an children of the non global option - * eg. token: it's global option used as the bot's token as well and - * also it can be the token used for a platform inside the hostRules configuration - */ -function isFalseGlobal(optionName: string, parentPath?: string): boolean { - if (parentPath?.includes('hostRules')) { - if ( - optionName === 'token' || - optionName === 'username' || - optionName === 'password' - ) { - return true; - } - } - - return false; -} |