diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md index b1b8a67bd311bca185b299442897f74276e9f72e..0971b51cb36b8d353989d10b1b009bd095e4b9e6 100644 --- a/docs/usage/self-hosted-configuration.md +++ b/docs/usage/self-hosted-configuration.md @@ -85,7 +85,7 @@ e.g. ```json { - "autodiscoverFilter": "project/*" + "autodiscoverFilter": ["project/*"] } ``` diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 84b34978c2f00ef70c942ff9151834b76c1a21cd..885ed89e86897672997854c0bb196f3653d0a276 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -668,7 +668,9 @@ const options: RenovateOptions[] = [ name: 'autodiscoverFilter', description: 'Filter the list of autodiscovered repositories.', stage: 'global', - type: 'string', + type: 'array', + subType: 'string', + allowString: true, default: null, }, { diff --git a/lib/config/types.ts b/lib/config/types.ts index cd4e2e32aef47d5c1a2a3bebdde75939811f81d7..151f9de951bc09413914b854d337baf91630b0e4 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -72,7 +72,7 @@ export interface RenovateSharedConfig { // The below should contain config options where stage=global export interface GlobalOnlyConfig { autodiscover?: boolean; - autodiscoverFilter?: string; + autodiscoverFilter?: string[]; baseDir?: string; cacheDir?: string; detectHostRulesFromEnv?: boolean; diff --git a/lib/workers/global/autodiscover.spec.ts b/lib/workers/global/autodiscover.spec.ts index 076d179cc3fa9c0975c37f99154ec7f23d6931e2..e3953c343756af90e2c92dae65b896ae09bd8d2a 100644 --- a/lib/workers/global/autodiscover.spec.ts +++ b/lib/workers/global/autodiscover.spec.ts @@ -1,4 +1,4 @@ -import type { RenovateConfig } from '../../config/types'; +import type { AllConfig } from '../../config/types'; import { PlatformId } from '../../constants'; import * as platform from '../../platform'; import * as _ghApi from '../../platform/github'; @@ -13,7 +13,7 @@ const hostRules = _hostRules; const ghApi: jest.Mocked<typeof _ghApi> = _ghApi as never; describe('workers/global/autodiscover', () => { - let config: RenovateConfig; + let config: AllConfig; beforeEach(async () => { jest.resetAllMocks(); config = {}; @@ -48,7 +48,7 @@ describe('workers/global/autodiscover', () => { }); it('filters autodiscovered github repos', async () => { config.autodiscover = true; - config.autodiscoverFilter = 'project/re*'; + config.autodiscoverFilter = ['project/re*']; config.platform = PlatformId.Github; hostRules.find = jest.fn(() => ({ token: 'abc', @@ -61,7 +61,7 @@ describe('workers/global/autodiscover', () => { }); it('filters autodiscovered github repos but nothing matches', async () => { config.autodiscover = true; - config.autodiscoverFilter = 'project/re*'; + config.autodiscoverFilter = ['project/re*']; config.platform = 'github'; hostRules.find = jest.fn(() => ({ token: 'abc', @@ -72,4 +72,21 @@ describe('workers/global/autodiscover', () => { const res = await autodiscoverRepositories(config); expect(res).toEqual(config); }); + it('filters autodiscovered github repos with multiple values', async () => { + config.autodiscover = true; + config.autodiscoverFilter = ['another-project/re*', 'department/dev/*']; + config.platform = 'github'; + hostRules.find = jest.fn(() => ({ + token: 'abc', + })); + const expectedRepositories = [ + 'another-project/repo', + 'department/dev/aProject', + ]; + ghApi.getRepos = jest.fn(() => + Promise.resolve(['another-project/another-repo', ...expectedRepositories]) + ); + const res = await autodiscoverRepositories(config); + expect(res.repositories).toEqual(expectedRepositories); + }); }); diff --git a/lib/workers/global/autodiscover.ts b/lib/workers/global/autodiscover.ts index 03b66b293acdf0c0c79b0b29e98005be2e0e945d..128d7bb0d60d11781397223886b09c0247698964 100644 --- a/lib/workers/global/autodiscover.ts +++ b/lib/workers/global/autodiscover.ts @@ -30,7 +30,15 @@ export async function autodiscoverRepositories( return config; } if (config.autodiscoverFilter) { - discovered = discovered.filter(minimatch.filter(config.autodiscoverFilter)); + const matched = new Set<string>(); + for (const filter of config.autodiscoverFilter) { + const res = minimatch.match(discovered, filter); + for (const repository of res) { + matched.add(repository); + } + } + discovered = [...matched]; + if (!discovered.length) { // Soft fail (no error thrown) if no accessible repositories match the filter logger.debug('None of the discovered repositories matched the filter'); diff --git a/lib/workers/global/config/parse/env.ts b/lib/workers/global/config/parse/env.ts index ca969854314faf99307f6c744b7dbb6c34f021f1..d747f113f3feb4ad7c94d2d0ddf196beef126e03 100644 --- a/lib/workers/global/config/parse/env.ts +++ b/lib/workers/global/config/parse/env.ts @@ -1,4 +1,5 @@ import is from '@sindresorhus/is'; +import { massageConfig } from '../../../../config/massage'; import { getOptions } from '../../../../config/options'; import type { AllConfig, RenovateOptions } from '../../../../config/types'; import { PlatformId } from '../../../../constants'; @@ -132,5 +133,5 @@ export function getConfig(inputEnv: NodeJS.ProcessEnv): AllConfig { unsupportedEnv.forEach((val) => delete env[val]); - return config; + return massageConfig(config); } diff --git a/lib/workers/global/config/parse/file.ts b/lib/workers/global/config/parse/file.ts index 24a0e31df7d6c0adf61ebff5c9f814f6c1ea24ef..aa738acc72a7296ce7febe1f7b7e18d80e7e47d7 100644 --- a/lib/workers/global/config/parse/file.ts +++ b/lib/workers/global/config/parse/file.ts @@ -2,6 +2,7 @@ import is from 'is'; import { load } from 'js-yaml'; import JSON5 from 'json5'; import upath from 'upath'; +import { massageConfig } from '../../../../config/massage'; import { migrateConfig } from '../../../../config/migration'; import type { AllConfig, RenovateConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; @@ -64,5 +65,5 @@ export async function getConfig(env: NodeJS.ProcessEnv): Promise<AllConfig> { ); config = migratedConfig; } - return config; + return massageConfig(config); }