From 325cb70ff25719fcbb257b64532327affbde74f0 Mon Sep 17 00:00:00 2001 From: Justinas <12399634+justinas-b@users.noreply.github.com> Date: Wed, 4 Jan 2023 10:53:17 +0200 Subject: [PATCH] fix(platform/gitlab): resolve assignees/reviewers from groups (#19469) --- lib/modules/platform/gitlab/http.ts | 10 +++++++++- lib/modules/platform/gitlab/index.spec.ts | 24 +++++++++++++++++++++++ lib/modules/platform/gitlab/index.ts | 19 ++++++++++++++++-- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/lib/modules/platform/gitlab/http.ts b/lib/modules/platform/gitlab/http.ts index ab327ef20a..07cbd04ed9 100644 --- a/lib/modules/platform/gitlab/http.ts +++ b/lib/modules/platform/gitlab/http.ts @@ -1,6 +1,6 @@ import { logger } from '../../../logger'; import { GitlabHttp } from '../../../util/http/gitlab'; -import type { GitlabUserStatus } from './types'; +import type { GitLabUser, GitlabUserStatus } from './types'; export const gitlabApi = new GitlabHttp(); @@ -10,6 +10,14 @@ export async function getUserID(username: string): Promise<number> { ).body[0].id; } +export async function getMemberUserIDs(group: string): Promise<number[]> { + const groupEncoded = encodeURIComponent(group); + const members = ( + await gitlabApi.getJson<GitLabUser[]>(`groups/${groupEncoded}/members`) + ).body; + return members.map((u) => u.id); +} + export async function isUserBusy(user: string): Promise<boolean> { try { const url = `/users/${user}/status`; diff --git a/lib/modules/platform/gitlab/index.spec.ts b/lib/modules/platform/gitlab/index.spec.ts index be45fcb3ee..41375babfd 100644 --- a/lib/modules/platform/gitlab/index.spec.ts +++ b/lib/modules/platform/gitlab/index.spec.ts @@ -1118,12 +1118,36 @@ describe('modules/platform/gitlab/index', () => { .get('/api/v4/users?username=someuser') .reply(200, [{ id: 10 }]) .get('/api/v4/users?username=someotheruser') + .reply(404) + .get('/api/v4/groups/someotheruser/members') .reply(404); await gitlab.addReviewers(42, ['someuser', 'foo', 'someotheruser']); expect(scope.isDone()).toBeTrue(); }); + it('should add gitlab group members as reviewers to MR', async () => { + const scope = httpMock + .scope(gitlabApiHost) + .get( + '/api/v4/projects/undefined/merge_requests/42?include_diverged_commits_count=1' + ) + .reply(200, { reviewers: existingReviewers }) + .get('/api/v4/users?username=someuser') + .reply(200, [{ id: 10 }]) + .get('/api/v4/users?username=somegroup') + .reply(404) + .get('/api/v4/groups/somegroup/members') + .reply(200, [{ id: 11 }, { id: 12 }]) + .put('/api/v4/projects/undefined/merge_requests/42', { + reviewer_ids: [1, 2, 10, 11, 12], + }) + .reply(200); + + await gitlab.addReviewers(42, ['someuser', 'foo', 'somegroup']); + expect(scope.isDone()).toBeTrue(); + }); + it('should fail to add reviewers to the MR', async () => { const scope = httpMock .scope(gitlabApiHost) diff --git a/lib/modules/platform/gitlab/index.ts b/lib/modules/platform/gitlab/index.ts index 47a70abb0a..bc8de972fc 100644 --- a/lib/modules/platform/gitlab/index.ts +++ b/lib/modules/platform/gitlab/index.ts @@ -50,7 +50,7 @@ import type { } from '../types'; import { repoFingerprint } from '../util'; import { smartTruncate } from '../utils/pr-body'; -import { getUserID, gitlabApi, isUserBusy } from './http'; +import { getMemberUserIDs, getUserID, gitlabApi, isUserBusy } from './http'; import { getMR, updateMR } from './merge-request'; import type { GitLabMergeRequest, @@ -1013,12 +1013,27 @@ export async function addReviewers( // Gather the IDs for all the reviewers we want to add let newReviewerIDs: number[]; try { - newReviewerIDs = await p.all(newReviewers.map((r) => () => getUserID(r))); + newReviewerIDs = ( + await p.all( + newReviewers.map((r) => async () => { + try { + return [await getUserID(r)]; + } catch (err) { + // Unable to fetch userId, try resolve as a group + return getMemberUserIDs(r); + } + }) + ) + ).flat(); } catch (err) { logger.warn({ err }, 'Failed to get IDs of the new reviewers'); return; } + // Multiple groups may have the same members, so + // filter out non-distinct values + newReviewerIDs = [...new Set(newReviewerIDs)]; + try { await updateMR(config.repository, iid, { reviewer_ids: [...existingReviewerIDs, ...newReviewerIDs], -- GitLab