From 19a99d2ca9ea382c3bff303a134a104d837aad05 Mon Sep 17 00:00:00 2001 From: Gabriel-Ladzaretti <97394622+Gabriel-Ladzaretti@users.noreply.github.com> Date: Tue, 7 Jan 2025 08:56:48 +0200 Subject: [PATCH] feat(config): add repo phase enviorment config (#33360) --- docs/usage/self-hosted-experimental.md | 7 ++++ lib/workers/global/config/parse/env.ts | 20 +++++----- lib/workers/repository/init/config.spec.ts | 46 ++++++++++++++++++++++ lib/workers/repository/init/config.ts | 22 ++++++++++- 4 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 lib/workers/repository/init/config.spec.ts diff --git a/docs/usage/self-hosted-experimental.md b/docs/usage/self-hosted-experimental.md index f80219fd96..78ea76a020 100644 --- a/docs/usage/self-hosted-experimental.md +++ b/docs/usage/self-hosted-experimental.md @@ -23,6 +23,13 @@ For more information see [the OpenTelemetry docs](opentelemetry.md). If set to any value, Renovate will always paginate requests to GitHub fully, instead of stopping after 10 pages. +## `RENOVATE_STATIC_REPO_CONFIG` + +If set to a _valid_ `JSON` string containing a _valid_ Renovate configuration, it will be applied to the repository config before resolving the actual configuration file within the repository. + +> [!warning] +> An invalid value will result in the scan being aborted. + ## `RENOVATE_X_DOCKER_HUB_DISABLE_LABEL_LOOKUP` If set to any value, Renovate will skip attempting to get release labels (e.g. gitRef, sourceUrl) from manifest annotations for `https://index.docker.io`. diff --git a/lib/workers/global/config/parse/env.ts b/lib/workers/global/config/parse/env.ts index a5543bb198..79ed110d6b 100644 --- a/lib/workers/global/config/parse/env.ts +++ b/lib/workers/global/config/parse/env.ts @@ -121,16 +121,10 @@ export async function getConfig( inputEnv: NodeJS.ProcessEnv, configEnvKey = 'RENOVATE_CONFIG', ): Promise<AllConfig> { - let env = normalizePrefixes(inputEnv, inputEnv.ENV_PREFIX); - env = massageConvertedExperimentalVars(env); - env = renameEnvKeys(env); - // massage the values of migrated configuration keys - env = massageEnvKeyValues(env); - - const options = getOptions(); - + const env = prepareEnv(inputEnv); const config = await parseAndValidateOrExit(env, configEnvKey); + const options = getOptions(); config.hostRules ??= []; for (const option of options) { @@ -235,7 +229,15 @@ export async function getConfig( return config; } -async function parseAndValidateOrExit( +export function prepareEnv(inputEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv { + let env = normalizePrefixes(inputEnv, inputEnv.ENV_PREFIX); + env = massageConvertedExperimentalVars(env); + env = renameEnvKeys(env); + // massage the values of migrated configuration keys + return massageEnvKeyValues(env); +} + +export async function parseAndValidateOrExit( env: NodeJS.ProcessEnv, configEnvKey: string, ): Promise<AllConfig> { diff --git a/lib/workers/repository/init/config.spec.ts b/lib/workers/repository/init/config.spec.ts new file mode 100644 index 0000000000..33cedcd071 --- /dev/null +++ b/lib/workers/repository/init/config.spec.ts @@ -0,0 +1,46 @@ +import type { AllConfig } from '../../../config/types'; +import { mergeStaticRepoEnvConfig } from './config'; + +describe('workers/repository/init/config', () => { + describe('mergeRepoEnvConfig()', () => { + type MergeRepoEnvTestCase = { + name: string; + env: NodeJS.ProcessEnv; + currentConfig: AllConfig; + wantConfig: AllConfig; + }; + + const testCases: MergeRepoEnvTestCase[] = [ + { + name: 'it does nothing', + env: {}, + currentConfig: { repositories: ['some/repo'] }, + wantConfig: { repositories: ['some/repo'] }, + }, + { + name: 'it merges env with the current config', + env: { RENOVATE_STATIC_REPO_CONFIG: '{"dependencyDashboard":true}' }, + currentConfig: { repositories: ['some/repo'] }, + wantConfig: { + dependencyDashboard: true, + repositories: ['some/repo'], + }, + }, + { + name: 'it ignores env with other renovate specific configuration options', + env: { RENOVATE_CONFIG: '{"dependencyDashboard":true}' }, + currentConfig: { repositories: ['some/repo'] }, + wantConfig: { repositories: ['some/repo'] }, + }, + ]; + + it.each(testCases)( + '$name', + async ({ env, currentConfig, wantConfig }: MergeRepoEnvTestCase) => { + const got = await mergeStaticRepoEnvConfig(currentConfig, env); + + expect(got).toEqual(wantConfig); + }, + ); + }); +}); diff --git a/lib/workers/repository/init/config.ts b/lib/workers/repository/init/config.ts index a8f9a14c6d..fe3122896b 100644 --- a/lib/workers/repository/init/config.ts +++ b/lib/workers/repository/init/config.ts @@ -1,4 +1,7 @@ -import type { RenovateConfig } from '../../../config/types'; +import is from '@sindresorhus/is'; +import { mergeChildConfig } from '../../../config'; +import type { AllConfig, RenovateConfig } from '../../../config/types'; +import { parseAndValidateOrExit } from '../../global/config/parse/env'; import { checkOnboardingBranch } from '../onboarding/branch'; import { mergeInheritedConfig } from './inherited'; import { mergeRenovateConfig } from './merge'; @@ -10,7 +13,24 @@ export async function getRepoConfig( let config = { ...config_ }; config.baseBranch = config.defaultBranch; config = await mergeInheritedConfig(config); + config = await mergeStaticRepoEnvConfig(config, process.env); config = await checkOnboardingBranch(config); config = await mergeRenovateConfig(config); return config; } + +export async function mergeStaticRepoEnvConfig( + config: AllConfig, + env: NodeJS.ProcessEnv, +): Promise<AllConfig> { + const repoEnvConfig = await parseAndValidateOrExit( + env, + 'RENOVATE_STATIC_REPO_CONFIG', + ); + + if (!is.nonEmptyObject(repoEnvConfig)) { + return config; + } + + return mergeChildConfig(config, repoEnvConfig); +} -- GitLab