From fe83cf914e7ad1491a93ca9033733340e5a75060 Mon Sep 17 00:00:00 2001 From: Sergio Zharinov Date: Tue, 10 Nov 2020 13:12:03 +0400 Subject: [PATCH] refactor(config): Generalize allowedVersions regex (#7683) --- lib/config/validation.ts | 29 ++------------- lib/util/regex.ts | 36 +++++++++++++++++++ .../repository/process/lookup/filter.ts | 27 +++----------- .../repository/process/lookup/index.spec.ts | 2 +- 4 files changed, 45 insertions(+), 49 deletions(-) diff --git a/lib/config/validation.ts b/lib/config/validation.ts index a61a2805c4..8af02bc81f 100644 --- a/lib/config/validation.ts +++ b/lib/config/validation.ts @@ -1,6 +1,6 @@ import is from '@sindresorhus/is'; import { getManagerList } from '../manager'; -import { regEx } from '../util/regex'; +import { configRegexPredicate, isConfigRegex, regEx } from '../util/regex'; import * as template from '../util/template'; import { hasValidSchedule, hasValidTimezone } from '../workers/branch/schedule'; import { RenovateConfig, ValidationMessage } from './common'; @@ -144,31 +144,8 @@ export async function validateConfig( message: `Invalid ${currentPath}: \`${errorMessage}\``, }); } - } else if ( - key === 'allowedVersions' && - is.string(val) && - val.length > 1 && - val.startsWith('/') && - val.endsWith('/') - ) { - try { - regEx(val.slice(1, -1)); - } catch (err) { - errors.push({ - depName: 'Configuration Error', - message: `Invalid regExp for ${currentPath}: \`${val}\``, - }); - } - } else if ( - key === 'allowedVersions' && - is.string(val) && - val.length > 2 && - val.startsWith('!/') && - val.endsWith('/') - ) { - try { - regEx(val.slice(2, -1)); - } catch (err) { + } else if (key === 'allowedVersions' && isConfigRegex(val)) { + if (!configRegexPredicate(val)) { errors.push({ depName: 'Configuration Error', message: `Invalid regExp for ${currentPath}: \`${val}\``, diff --git a/lib/util/regex.ts b/lib/util/regex.ts index 64bdbb6b7f..e4c9be2fb0 100644 --- a/lib/util/regex.ts +++ b/lib/util/regex.ts @@ -1,3 +1,4 @@ +import is from '@sindresorhus/is'; import { CONFIG_VALIDATION } from '../constants/error-messages'; import { logger } from '../logger'; @@ -29,3 +30,38 @@ export function regEx(pattern: string, flags?: string): RegExp { export function escapeRegExp(input: string): string { return input.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string } + +const configValStart = /^!?\//; +const configValEnd = /\/$/; + +export function isConfigRegex(input: unknown): input is string { + return ( + is.string(input) && configValStart.test(input) && configValEnd.test(input) + ); +} + +function parseConfigRegex(input: string): RegExp | null { + try { + const regexString = input + .replace(configValStart, '') + .replace(configValEnd, ''); + return regEx(regexString); + } catch (err) { + // no-op + } + return null; +} + +type ConfigRegexPredicate = (string) => boolean; + +export function configRegexPredicate(input: string): ConfigRegexPredicate { + const configRegex = parseConfigRegex(input); + if (configRegex) { + const isPositive = !input.startsWith('!'); + return (x: string): boolean => { + const res = configRegex.test(x); + return isPositive ? res : !res; + }; + } + return null; +} diff --git a/lib/workers/repository/process/lookup/filter.ts b/lib/workers/repository/process/lookup/filter.ts index af92486c3a..7f6c8be91f 100644 --- a/lib/workers/repository/process/lookup/filter.ts +++ b/lib/workers/repository/process/lookup/filter.ts @@ -2,7 +2,7 @@ import * as semver from 'semver'; import { CONFIG_VALIDATION } from '../../../../constants/error-messages'; import { Release } from '../../../../datasource'; import { logger } from '../../../../logger'; -import { regEx } from '../../../../util/regex'; +import { configRegexPredicate, isConfigRegex } from '../../../../util/regex'; import * as allVersioning from '../../../../versioning'; import * as npmVersioning from '../../../../versioning/npm'; import * as pep440 from '../../../../versioning/pep440'; @@ -18,8 +18,6 @@ export interface FilterConfig { versioning: string; } -const regexes: Record = {}; - export function filterVersions( config: FilterConfig, fromVersion: string, @@ -74,25 +72,10 @@ export function filterVersions( } if (allowedVersions) { - if ( - allowedVersions.length > 1 && - allowedVersions.startsWith('/') && - allowedVersions.endsWith('/') - ) { - regexes[allowedVersions] = - regexes[allowedVersions] || regEx(allowedVersions.slice(1, -1)); - filteredVersions = filteredVersions.filter((v) => - regexes[allowedVersions].test(v.version) - ); - } else if ( - allowedVersions.length > 2 && - allowedVersions.startsWith('!/') && - allowedVersions.endsWith('/') - ) { - regexes[allowedVersions] = - regexes[allowedVersions] || regEx(allowedVersions.slice(2, -1)); - filteredVersions = filteredVersions.filter( - (v) => !regexes[allowedVersions].test(v.version) + if (isConfigRegex(allowedVersions)) { + const isAllowed = configRegexPredicate(allowedVersions); + filteredVersions = filteredVersions.filter(({ version }) => + isAllowed(version) ); } else if (versioning.isValid(allowedVersions)) { filteredVersions = filteredVersions.filter((v) => diff --git a/lib/workers/repository/process/lookup/index.spec.ts b/lib/workers/repository/process/lookup/index.spec.ts index accb10cceb..f0614a7af9 100644 --- a/lib/workers/repository/process/lookup/index.spec.ts +++ b/lib/workers/repository/process/lookup/index.spec.ts @@ -161,7 +161,7 @@ describe('workers/repository/process/lookup', () => { nock('https://registry.npmjs.org').get('/q').reply(200, qJson); expect((await lookup.lookupUpdates(config)).updates).toHaveLength(1); }); - it('enforces allowedVersions with negativee regex', async () => { + it('enforces allowedVersions with negative regex', async () => { config.currentValue = '0.4.0'; config.allowedVersions = '!/^1/'; config.depName = 'q';