From 43c3ea1acb41bfb45e3a78393ac174caae93ab32 Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@arkins.net> Date: Wed, 5 Oct 2022 14:16:38 +0200 Subject: [PATCH] fix(config)!: unify env and cli coercions (#13171) Unifies CLI and env coercions. BREAKING CHANGE: boolean variables must be true or false when configured in env, and errors will be thrown for invalid values. Previously invalided values were ignored and treated as false. --- lib/workers/global/config/parse/cli.ts | 40 +------------------ lib/workers/global/config/parse/coersions.ts | 41 ++++++++++++++++++++ lib/workers/global/config/parse/env.spec.ts | 12 ++++-- lib/workers/global/config/parse/env.ts | 13 +------ 4 files changed, 52 insertions(+), 54 deletions(-) create mode 100644 lib/workers/global/config/parse/coersions.ts diff --git a/lib/workers/global/config/parse/cli.ts b/lib/workers/global/config/parse/cli.ts index fb790c4315..019dc343e9 100644 --- a/lib/workers/global/config/parse/cli.ts +++ b/lib/workers/global/config/parse/cli.ts @@ -1,10 +1,10 @@ import { Command } from 'commander'; -import JSON5 from 'json5'; import { getOptions } from '../../../../config/options'; import type { AllConfig } from '../../../../config/types'; import { pkg } from '../../../../expose.cjs'; import { logger } from '../../../../logger'; import { regEx } from '../../../../util/regex'; +import { coersions } from './coersions'; import type { ParseConfigOptions } from './types'; export function getCliName(option: ParseConfigOptions): string { @@ -38,44 +38,6 @@ export function getConfig(input: string[]): AllConfig { const config: Record<string, any> = {}; - const coersions: Record<string, (arg: string) => unknown> = { - boolean: (val: string): boolean => { - if (val === 'true' || val === '') { - return true; - } - if (val === 'false') { - return false; - } - throw new Error( - "Invalid boolean value: expected 'true' or 'false', but got '" + - val + - "'" - ); - }, - array: (val: string): string[] => { - if (val === '') { - return []; - } - try { - return JSON5.parse(val); - } catch (err) { - return val.split(',').map((el) => el.trim()); - } - }, - object: (val: string): any => { - if (val === '') { - return {}; - } - try { - return JSON5.parse(val); - } catch (err) { - throw new Error("Invalid JSON value: '" + val + "'"); - } - }, - string: (val: string): string => val, - integer: parseInt, - }; - let program = new Command().arguments('[repositories...]'); options.forEach((option) => { diff --git a/lib/workers/global/config/parse/coersions.ts b/lib/workers/global/config/parse/coersions.ts new file mode 100644 index 0000000000..67432aac32 --- /dev/null +++ b/lib/workers/global/config/parse/coersions.ts @@ -0,0 +1,41 @@ +import is from '@sindresorhus/is'; +import JSON5 from 'json5'; + +export const coersions: Record<string, (arg: string) => unknown> = { + boolean: (val: string): boolean => { + if (val === 'true' || val === '') { + return true; + } + if (val === 'false') { + return false; + } + throw new Error( + "Invalid boolean value: expected 'true' or 'false', but got '" + val + "'" + ); + }, + array: (val: string): string[] => { + if (val === '') { + return []; + } + try { + return JSON5.parse(val); + } catch (err) { + return val + .split(',') + .map((el) => el.trim()) + .filter(is.nonEmptyString); + } + }, + object: (val: string): any => { + if (val === '') { + return {}; + } + try { + return JSON5.parse(val); + } catch (err) { + throw new Error("Invalid JSON value: '" + val + "'"); + } + }, + string: (val: string): string => val, + integer: parseInt, +}; diff --git a/lib/workers/global/config/parse/env.spec.ts b/lib/workers/global/config/parse/env.spec.ts index 01ad7f361e..fe3ec6fe23 100644 --- a/lib/workers/global/config/parse/env.spec.ts +++ b/lib/workers/global/config/parse/env.spec.ts @@ -20,9 +20,15 @@ describe('workers/global/config/parse/env', () => { expect(env.getConfig(envParam).recreateClosed).toBeFalse(); }); - it('supports boolean nonsense as false', () => { - const envParam: NodeJS.ProcessEnv = { RENOVATE_RECREATE_CLOSED: 'foo' }; - expect(env.getConfig(envParam).recreateClosed).toBeFalse(); + it('throws exception for invalid boolean value', () => { + const envParam: NodeJS.ProcessEnv = { + RENOVATE_RECREATE_CLOSED: 'badvalue', + }; + expect(() => env.getConfig(envParam)).toThrow( + Error( + "Invalid boolean value: expected 'true' or 'false', but got 'badvalue'" + ) + ); }); delete process.env.RENOVATE_RECREATE_CLOSED; diff --git a/lib/workers/global/config/parse/env.ts b/lib/workers/global/config/parse/env.ts index ed6592eb77..ca7e920191 100644 --- a/lib/workers/global/config/parse/env.ts +++ b/lib/workers/global/config/parse/env.ts @@ -4,6 +4,7 @@ import { getOptions } from '../../../../config/options'; import type { AllConfig } from '../../../../config/types'; import { PlatformId } from '../../../../constants'; import { logger } from '../../../../logger'; +import { coersions } from './coersions'; import type { ParseConfigOptions } from './types'; function normalizePrefixes( @@ -74,18 +75,6 @@ export function getConfig(inputEnv: NodeJS.ProcessEnv): AllConfig { config.hostRules ||= []; - const coersions = { - boolean: (val: string): boolean => val === 'true', - array: (val: string): string[] => - val - .split(',') - .map((el) => el.trim()) - .filter(is.nonEmptyString), - string: (val: string): string => val.replace(/\\n/g, '\n'), - object: (val: string): any => JSON5.parse(val), - integer: parseInt, - }; - options.forEach((option) => { if (option.env !== false) { const envName = getEnvName(option); -- GitLab