diff --git a/lib/config/__snapshots__/validation.spec.ts.snap b/lib/config/__snapshots__/validation.spec.ts.snap index 9ffa915ec660c268e4dc20f1e350e5e331f6aa39..722813727ca51c237b9c5d0c8d68635cb5c97446 100644 --- a/lib/config/__snapshots__/validation.spec.ts.snap +++ b/lib/config/__snapshots__/validation.spec.ts.snap @@ -79,7 +79,7 @@ exports[`config/validation validateConfig(config) errors for unsafe fileMatches Array [ Object { "depName": "Configuration Error", - "message": "Invalid regExp for docker.fileMatch: \`x?+\`", + "message": "Invalid regExp for dockerfile.fileMatch: \`x?+\`", }, Object { "depName": "Configuration Error", @@ -106,6 +106,24 @@ Array [ ] `; +exports[`config/validation validateConfig(config) errors if fileMatch has wrong parent 1`] = ` +Array [ + Object { + "depName": "Config error", + "message": "\\"fileMatch\\" may not be defined at the top level of a config and must instead be within a manager block", + }, +] +`; + +exports[`config/validation validateConfig(config) errors if fileMatch has wrong parent 2`] = ` +Array [ + Object { + "depName": "Config warning", + "message": "\\"fileMatch\\" must be configured in a manager block and not here: npm.gradle", + }, +] +`; + exports[`config/validation validateConfig(config) errors if regexManager fields are missing 1`] = ` Array [ Object { @@ -169,4 +187,13 @@ Array [ ] `; +exports[`config/validation validateConfig(config) validates regEx for each fileMatch 1`] = ` +Array [ + Object { + "depName": "Configuration Error", + "message": "Invalid regExp for regexManagers[0].fileMatch: \`***$}{]][\`", + }, +] +`; + exports[`config/validation validateConfig(config) validates valid alias objects 1`] = `Array []`; diff --git a/lib/config/validation.spec.ts b/lib/config/validation.spec.ts index 583b5409e1f2a2b1f3393261c3f0341522e5c1d9..2f0c7d09bb4f7686f66d65c11292ece077d87c80 100644 --- a/lib/config/validation.spec.ts +++ b/lib/config/validation.spec.ts @@ -178,7 +178,7 @@ describe('config/validation', () => { npm: { fileMatch: ['abc ([a-z]+) ([a-z]+))'], }, - docker: { + dockerfile: { fileMatch: ['x?+'], }, }; @@ -192,7 +192,14 @@ describe('config/validation', () => { it('validates regEx for each fileMatch', async () => { const config = { - fileMatch: ['js', '***$}{]]['], + regexManagers: [ + { + fileMatch: ['js', '***$}{]]['], + matchStrings: ['^(?<depName>foo)(?<currentValue>bar)$'], + datasourceTemplate: 'maven', + versioningTemplate: 'gradle', + }, + ], }; const { warnings, errors } = await configValidation.validateConfig( config, @@ -200,6 +207,7 @@ describe('config/validation', () => { ); expect(warnings).toHaveLength(0); expect(errors).toHaveLength(1); + expect(errors).toMatchSnapshot(); }); it('errors if no regexManager matchStrings', async () => { const config = { @@ -382,5 +390,32 @@ describe('config/validation', () => { expect(errors).toHaveLength(1); expect(errors).toMatchSnapshot(); }); + + it('errors if fileMatch has wrong parent', async () => { + const config = { + fileMatch: ['foo'], + npm: { + fileMatch: ['package\\.json'], + gradle: { + fileMatch: ['bar'], + }, + }, + regexManagers: [ + { + fileMatch: ['build.gradle'], + matchStrings: ['^(?<depName>foo)(?<currentValue>bar)$'], + datasourceTemplate: 'maven', + versioningTemplate: 'gradle', + }, + ], + }; + const { warnings, errors } = await configValidation.validateConfig( + config + ); + expect(errors).toHaveLength(1); + expect(warnings).toHaveLength(1); + expect(errors).toMatchSnapshot(); + expect(warnings).toMatchSnapshot(); + }); }); }); diff --git a/lib/config/validation.ts b/lib/config/validation.ts index 814afa308577b0088e586173d92f77fccf48da57..42b712bb8c5ee322b500b1736920948c44bef4c0 100644 --- a/lib/config/validation.ts +++ b/lib/config/validation.ts @@ -1,4 +1,5 @@ import is from '@sindresorhus/is'; +import { getManagerList } from '../manager'; import { regEx } from '../util/regex'; import * as template from '../util/template'; import { hasValidSchedule, hasValidTimezone } from '../workers/branch/schedule'; @@ -16,6 +17,15 @@ export interface ValidationResult { warnings: ValidationMessage[]; } +const managerList = getManagerList(); + +function isManagerPath(parentPath: string): boolean { + return ( + /^regexManagers\[[0-9]+]$/.test(parentPath) || + managerList.includes(parentPath) + ); +} + export async function validateConfig( config: RenovateConfig, isPreset?: boolean, @@ -79,6 +89,19 @@ export async function validateConfig( }); continue; // eslint-disable-line } + if (key === 'fileMatch') { + if (parentPath === undefined) { + errors.push({ + depName: 'Config error', + message: `"fileMatch" may not be defined at the top level of a config and must instead be within a manager block`, + }); + } else if (!isManagerPath(parentPath)) { + warnings.push({ + depName: 'Config warning', + message: `"fileMatch" must be configured in a manager block and not here: ${parentPath}`, + }); + } + } if ( !isIgnored(key) && // We need to ignore some reserved keys !(is as any).function(val) // Ignore all functions