From e47cf724f98270b9b73bd4ffc94f302448b1e3bd Mon Sep 17 00:00:00 2001 From: Danek Duvall <duvall@comfychair.org> Date: Tue, 20 Jun 2023 04:37:32 -0700 Subject: [PATCH] feat: autodiscover repos by topic (#22876) --- docs/usage/self-hosted-configuration.md | 5 +++++ lib/config/options/index.ts | 10 ++++++++++ lib/config/types.ts | 1 + lib/modules/platform/gitlab/index.spec.ts | 18 ++++++++++++++++++ lib/modules/platform/gitlab/index.ts | 18 ++++++++++++++++-- lib/modules/platform/types.ts | 6 +++++- lib/workers/global/autodiscover.ts | 4 +++- 7 files changed, 58 insertions(+), 4 deletions(-) diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md index f3d6b09997..df2ac655a2 100644 --- a/docs/usage/self-hosted-configuration.md +++ b/docs/usage/self-hosted-configuration.md @@ -126,6 +126,11 @@ If using negations, all repositories except those who match the regex are added } ``` +## autodiscoverTopics + +Some platforms allow you to add tags, or topics, to repositories and retrieve repository lists by specifying those +topics. Set this variable to a list of strings, all of which will be topics for the autodiscovered repositories. + ## baseDir By default Renovate uses a temporary directory like `/tmp/renovate` to store its data. diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 061d434066..95761e5f55 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -765,6 +765,16 @@ const options: RenovateOptions[] = [ default: null, globalOnly: true, }, + { + name: 'autodiscoverTopics', + description: '', + stage: 'global', + type: 'array', + subType: 'string', + default: null, + globalOnly: true, + supportedPlatforms: ['gitlab'], + }, { name: 'prCommitsPerRunLimit', description: diff --git a/lib/config/types.ts b/lib/config/types.ts index ac915cd803..488ef1d8ad 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -94,6 +94,7 @@ export interface RenovateSharedConfig { export interface GlobalOnlyConfig { autodiscover?: boolean; autodiscoverFilter?: string[] | string; + autodiscoverTopics?: string[]; baseDir?: string; cacheDir?: string; containerbaseDir?: string; diff --git a/lib/modules/platform/gitlab/index.spec.ts b/lib/modules/platform/gitlab/index.spec.ts index 75959e84d2..0530d65e25 100644 --- a/lib/modules/platform/gitlab/index.spec.ts +++ b/lib/modules/platform/gitlab/index.spec.ts @@ -163,6 +163,24 @@ describe('modules/platform/gitlab/index', () => { const repos = await gitlab.getRepos(); expect(repos).toEqual(['a/b', 'c/d']); }); + + it('should encode the requested topics into the URL', async () => { + httpMock + .scope(gitlabApiHost) + .get( + '/api/v4/projects?membership=true&per_page=100&with_merge_requests_enabled=true&min_access_level=30&archived=false&topic=one%2Ctwo' + ) + .reply(200, [ + { + path_with_namespace: 'a/b', + }, + { + path_with_namespace: 'c/d', + }, + ]); + const repos = await gitlab.getRepos({ topics: ['one', 'two'] }); + expect(repos).toEqual(['a/b', 'c/d']); + }); }); async function initRepo( diff --git a/lib/modules/platform/gitlab/index.ts b/lib/modules/platform/gitlab/index.ts index 8817d5178d..88fbf9f1f0 100644 --- a/lib/modules/platform/gitlab/index.ts +++ b/lib/modules/platform/gitlab/index.ts @@ -31,6 +31,7 @@ import { } from '../../../util/url'; import { getPrBodyStruct } from '../pr-body'; import type { + AutodiscoverConfig, BranchStatusConfig, CreatePRConfig, EnsureCommentConfig, @@ -142,10 +143,23 @@ export async function initPlatform({ } // Get all repositories that the user has access to -export async function getRepos(): Promise<string[]> { +export async function getRepos(config?: AutodiscoverConfig): Promise<string[]> { logger.debug('Autodiscovering GitLab repositories'); + + const queryParams: Record<string, any> = { + membership: true, + per_page: 100, + with_merge_requests_enabled: true, + min_access_level: 30, + archived: false, + }; + if (config?.topics?.length) { + queryParams['topic'] = config.topics.join(','); + } + + const url = 'projects?' + getQueryString(queryParams); + try { - const url = `projects?membership=true&per_page=100&with_merge_requests_enabled=true&min_access_level=30&archived=false`; const res = await gitlabApi.getJson<RepoResponse[]>(url, { paginate: true, }); diff --git a/lib/modules/platform/types.ts b/lib/modules/platform/types.ts index d9bc8f84ca..e96f96286a 100644 --- a/lib/modules/platform/types.ts +++ b/lib/modules/platform/types.ts @@ -164,6 +164,10 @@ export type EnsureCommentRemovalConfig = export type EnsureIssueResult = 'updated' | 'created'; +export interface AutodiscoverConfig { + topics?: string[]; +} + export interface Platform { findIssue(title: string): Promise<Issue | null>; getIssueList(): Promise<Issue[]>; @@ -191,7 +195,7 @@ export interface Platform { addReviewers(number: number, reviewers: string[]): Promise<void>; addAssignees(number: number, assignees: string[]): Promise<void>; createPr(prConfig: CreatePRConfig): Promise<Pr | null>; - getRepos(): Promise<string[]>; + getRepos(config?: AutodiscoverConfig): Promise<string[]>; getRepoForceRebase(): Promise<boolean>; deleteLabel(number: number, label: string): Promise<void>; setBranchStatus(branchStatusConfig: BranchStatusConfig): Promise<void>; diff --git a/lib/workers/global/autodiscover.ts b/lib/workers/global/autodiscover.ts index 943f739d67..2ea7d7953c 100644 --- a/lib/workers/global/autodiscover.ts +++ b/lib/workers/global/autodiscover.ts @@ -35,7 +35,9 @@ export async function autodiscoverRepositories( return config; } // Autodiscover list of repositories - let discovered = await platform.getRepos(); + let discovered = await platform.getRepos({ + topics: config.autodiscoverTopics, + }); if (!discovered?.length) { // Soft fail (no error thrown) if no accessible repositories logger.debug( -- GitLab