diff --git a/lib/workers/global/config/parse/env.spec.ts b/lib/workers/global/config/parse/env.spec.ts index 3961e8d3dd..0dae85326e 100644 --- a/lib/workers/global/config/parse/env.spec.ts +++ b/lib/workers/global/config/parse/env.spec.ts @@ -306,7 +306,11 @@ describe('workers/global/config/parse/env', () => { it('crashes', async () => { const envParam: NodeJS.ProcessEnv = { RENOVATE_CONFIG: '!@#' }; - await env.getConfig(envParam); + processExit.mockImplementationOnce(() => { + throw new Error('terminate function to simulate process.exit call'); + }); + + await expect(env.getConfig(envParam)).toReject(); expect(processExit).toHaveBeenCalledWith(1); }); diff --git a/lib/workers/global/config/parse/env.ts b/lib/workers/global/config/parse/env.ts index 3467b1ec1a..a5543bb198 100644 --- a/lib/workers/global/config/parse/env.ts +++ b/lib/workers/global/config/parse/env.ts @@ -3,6 +3,7 @@ import JSON5 from 'json5'; import { getOptions } from '../../../../config/options'; import type { AllConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; +import { parseJson } from '../../../../util/common'; import { coersions } from './coersions'; import type { ParseConfigOptions } from './types'; import { migrateAndValidateConfig } from './util'; @@ -118,9 +119,9 @@ function massageConvertedExperimentalVars( export async function getConfig( inputEnv: NodeJS.ProcessEnv, + configEnvKey = 'RENOVATE_CONFIG', ): Promise { - let env = inputEnv; - env = normalizePrefixes(inputEnv, inputEnv.ENV_PREFIX); + let env = normalizePrefixes(inputEnv, inputEnv.ENV_PREFIX); env = massageConvertedExperimentalVars(env); env = renameEnvKeys(env); // massage the values of migrated configuration keys @@ -128,92 +129,82 @@ export async function getConfig( const options = getOptions(); - let config: AllConfig = {}; - - if (env.RENOVATE_CONFIG) { - try { - config = JSON5.parse(env.RENOVATE_CONFIG); - logger.debug({ config }, 'Detected config in env RENOVATE_CONFIG'); - - config = await migrateAndValidateConfig(config, 'RENOVATE_CONFIG'); - } catch (err) { - logger.fatal({ err }, 'Could not parse RENOVATE_CONFIG'); - process.exit(1); - } - } + const config = await parseAndValidateOrExit(env, configEnvKey); config.hostRules ??= []; - options.forEach((option) => { - if (option.env !== false) { - const envName = getEnvName(option); - const envVal = env[envName]; - if (envVal) { - if (option.type === 'array' && option.subType === 'object') { - try { - const parsed = JSON5.parse(envVal); - if (is.array(parsed)) { - config[option.name] = parsed; - } else { - logger.debug( - { val: envVal, envName }, - 'Could not parse object array', - ); - } - } catch { - logger.debug( - { val: envVal, envName }, - 'Could not parse environment variable', - ); - } + for (const option of options) { + if (option.env === false) { + continue; + } + + const envName = getEnvName(option); + const envVal = env[envName]; + if (!envVal) { + continue; + } + + if (option.type === 'array' && option.subType === 'object') { + try { + const parsed = JSON5.parse(envVal); + if (is.array(parsed)) { + config[option.name] = parsed; } else { - const coerce = coersions[option.type]; - config[option.name] = coerce(envVal); - if (option.name === 'dryRun') { - if ((config[option.name] as string) === 'true') { - logger.warn( - 'env config dryRun property has been changed to full', - ); - config[option.name] = 'full'; - } else if ((config[option.name] as string) === 'false') { - logger.warn( - 'env config dryRun property has been changed to null', - ); - delete config[option.name]; - } else if ((config[option.name] as string) === 'null') { - delete config[option.name]; - } - } - if (option.name === 'requireConfig') { - if ((config[option.name] as string) === 'true') { - logger.warn( - 'env config requireConfig property has been changed to required', - ); - config[option.name] = 'required'; - } else if ((config[option.name] as string) === 'false') { - logger.warn( - 'env config requireConfig property has been changed to optional', - ); - config[option.name] = 'optional'; - } - } - if (option.name === 'platformCommit') { - if ((config[option.name] as string) === 'true') { - logger.warn( - 'env config platformCommit property has been changed to enabled', - ); - config[option.name] = 'enabled'; - } else if ((config[option.name] as string) === 'false') { - logger.warn( - 'env config platformCommit property has been changed to disabled', - ); - config[option.name] = 'disabled'; - } - } + logger.debug( + { val: envVal, envName }, + 'Could not parse object array', + ); + } + } catch { + logger.debug( + { val: envVal, envName }, + 'Could not parse environment variable', + ); + } + } else { + const coerce = coersions[option.type]; + config[option.name] = coerce(envVal); + if (option.name === 'dryRun') { + if ((config[option.name] as string) === 'true') { + logger.warn('env config dryRun property has been changed to full'); + config[option.name] = 'full'; + } else if ((config[option.name] as string) === 'false') { + logger.warn('env config dryRun property has been changed to null'); + delete config[option.name]; + } else if ((config[option.name] as string) === 'null') { + delete config[option.name]; + } + } + + if (option.name === 'requireConfig') { + if ((config[option.name] as string) === 'true') { + logger.warn( + 'env config requireConfig property has been changed to required', + ); + config[option.name] = 'required'; + } else if ((config[option.name] as string) === 'false') { + logger.warn( + 'env config requireConfig property has been changed to optional', + ); + config[option.name] = 'optional'; + } + } + + if (option.name === 'platformCommit') { + if ((config[option.name] as string) === 'true') { + logger.warn( + 'env config platformCommit property has been changed to enabled', + ); + config[option.name] = 'enabled'; + } else if ((config[option.name] as string) === 'false') { + logger.warn( + 'env config platformCommit property has been changed to disabled', + ); + config[option.name] = 'disabled'; } } } - }); + } if (env.GITHUB_COM_TOKEN) { logger.debug(`Converting GITHUB_COM_TOKEN into a global host rule`); @@ -237,7 +228,31 @@ export async function getConfig( 'VSTS_TOKEN', ]; - unsupportedEnv.forEach((val) => delete env[val]); + for (const val of unsupportedEnv) { + delete env[val]; + } return config; } + +async function parseAndValidateOrExit( + env: NodeJS.ProcessEnv, + configEnvKey: string, +): Promise { + if (!env[configEnvKey]) { + return {}; + } + + try { + const config = parseJson( + env[configEnvKey], + `${configEnvKey}.env.json5`, + ) as AllConfig; + logger.debug({ config }, `Detected config in env ${configEnvKey}`); + + return await migrateAndValidateConfig(config, `${configEnvKey}`); + } catch (err) { + logger.fatal({ err }, `Could not parse ${configEnvKey}`); + process.exit(1); + } +}