diff --git a/lib/platform/gitlab/__snapshots__/index.spec.ts.snap b/lib/platform/gitlab/__snapshots__/index.spec.ts.snap index 8b2dae9b1d8a59fbda8027287ee1c5902c6bec39..070545ca4a4af3406190f8c0893d5b718288a702 100644 --- a/lib/platform/gitlab/__snapshots__/index.spec.ts.snap +++ b/lib/platform/gitlab/__snapshots__/index.spec.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`platform/gitlab/index addAssignees(issueNo, assignees) should add the given assignees to the issue 1`] = ` +exports[`platform/gitlab/index addAssignees(issueNo, assignees) should add the given assignee to the issue 1`] = ` Array [ Object { "headers": Object { @@ -22,12 +22,12 @@ Array [ "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", }, "method": "PUT", - "url": "https://gitlab.com/api/v4/projects/undefined/merge_requests/42?assignee_id=123", + "url": "https://gitlab.com/api/v4/projects/undefined/merge_requests/42?assignee_ids%5B%5D=123", }, ] `; -exports[`platform/gitlab/index addAssignees(issueNo, assignees) should add the given assignees to the issue if supported 1`] = ` +exports[`platform/gitlab/index addAssignees(issueNo, assignees) should add the given assignees to the issue 1`] = ` Array [ Object { "headers": Object { @@ -40,17 +40,6 @@ Array [ "method": "GET", "url": "https://gitlab.com/api/v4/users?username=someuser", }, - Object { - "headers": Object { - "accept": "application/json", - "accept-encoding": "gzip, deflate, br", - "authorization": "Bearer 123test", - "host": "gitlab.com", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "PUT", - "url": "https://gitlab.com/api/v4/projects/undefined/merge_requests/42?assignee_id=123", - }, Object { "headers": Object { "accept": "application/json", @@ -71,7 +60,7 @@ Array [ "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", }, "method": "PUT", - "url": "https://gitlab.com/api/v4/projects/undefined/merge_requests/42?assignee_ids[]=123&assignee_ids[]=124", + "url": "https://gitlab.com/api/v4/projects/undefined/merge_requests/42?assignee_ids%5B%5D=123&assignee_ids%5B%5D=124", }, ] `; @@ -92,55 +81,6 @@ Array [ ] `; -exports[`platform/gitlab/index addAssignees(issueNo, assignees) should warn if more than one assignee 1`] = ` -Array [ - Object { - "headers": Object { - "accept": "application/json", - "accept-encoding": "gzip, deflate, br", - "authorization": "Bearer 123test", - "host": "gitlab.com", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "GET", - "url": "https://gitlab.com/api/v4/users?username=someuser", - }, - Object { - "headers": Object { - "accept": "application/json", - "accept-encoding": "gzip, deflate, br", - "authorization": "Bearer 123test", - "host": "gitlab.com", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "PUT", - "url": "https://gitlab.com/api/v4/projects/undefined/merge_requests/42?assignee_id=123", - }, - Object { - "headers": Object { - "accept": "application/json", - "accept-encoding": "gzip, deflate, br", - "authorization": "Bearer 123test", - "host": "gitlab.com", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "GET", - "url": "https://gitlab.com/api/v4/users?username=someotheruser", - }, - Object { - "headers": Object { - "accept": "application/json", - "accept-encoding": "gzip, deflate, br", - "authorization": "Bearer 123test", - "host": "gitlab.com", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "PUT", - "url": "https://gitlab.com/api/v4/projects/undefined/merge_requests/42?assignee_ids[]=123&assignee_ids[]=124", - }, -] -`; - exports[`platform/gitlab/index createPr(branchName, title, body) adds approval rule to ignore all approvals 1`] = ` Array [ Object { diff --git a/lib/platform/gitlab/index.md b/lib/platform/gitlab/index.md index e39eef5c6bee1afd39c33fc5f04a1def157e6b71..094ff3e670d8472b9c9b1d975bdda82c2a742254 100644 --- a/lib/platform/gitlab/index.md +++ b/lib/platform/gitlab/index.md @@ -13,3 +13,8 @@ By setting the server version yourself, you save a API call that fetches the ser - Use `Draft:` MR prefix instead of `WIP:` prefix since `v13.2.0` - Do not truncate Markdown body to 25K chars since `v13.4.0` - Allow configure reviewers since `v13.9.0` + +## Multiple merge request assignees + +Due to licensing restrictions [multiple assignees](https://docs.gitlab.com/ee/user/project/issues/multiple_assignees_for_issues.html) are only available in GitLab Premium self-managed, GitLab Premium SaaS, and higher tiers. +Because of a safeguard in [GitLab's API](https://github.com/renovatebot/renovate/pull/14212#issuecomment-1040189712) if multiple assignees are set, but not available to the project, only the first assignee will be applied. diff --git a/lib/platform/gitlab/index.spec.ts b/lib/platform/gitlab/index.spec.ts index 6f60cc5dbba71bbc6c9cd2079fd1e2a7e03f6557..3f15537d52f6337103aa047e8b618e6738efbe48 100644 --- a/lib/platform/gitlab/index.spec.ts +++ b/lib/platform/gitlab/index.spec.ts @@ -959,30 +959,29 @@ describe('platform/gitlab/index', () => { expect(httpMock.getTrace()).toMatchSnapshot(); }); }); + describe('addAssignees(issueNo, assignees)', () => { - it('should add the given assignees to the issue', async () => { + it('should add the given assignee to the issue', async () => { httpMock .scope(gitlabApiHost) .get('/api/v4/users?username=someuser') .reply(200, [{ id: 123 }]) - .put('/api/v4/projects/undefined/merge_requests/42?assignee_id=123') + .put('/api/v4/projects/undefined/merge_requests/42?assignee_ids[]=123') .reply(200); await gitlab.addAssignees(42, ['someuser']); expect(httpMock.getTrace()).toMatchSnapshot(); }); - it('should warn if more than one assignee', async () => { + it('should add the given assignees to the issue', async () => { httpMock .scope(gitlabApiHost) .get('/api/v4/users?username=someuser') .reply(200, [{ id: 123 }]) .get('/api/v4/users?username=someotheruser') .reply(200, [{ id: 124 }]) - .put('/api/v4/projects/undefined/merge_requests/42?assignee_id=123') - .reply(200) .put( '/api/v4/projects/undefined/merge_requests/42?assignee_ids[]=123&assignee_ids[]=124' ) - .replyWithError('error'); + .reply(200); await gitlab.addAssignees(42, ['someuser', 'someotheruser']); expect(httpMock.getTrace()).toMatchSnapshot(); }); @@ -994,22 +993,6 @@ describe('platform/gitlab/index', () => { await gitlab.addAssignees(42, ['someuser', 'someotheruser']); expect(httpMock.getTrace()).toMatchSnapshot(); }); - it('should add the given assignees to the issue if supported', async () => { - httpMock - .scope(gitlabApiHost) - .get('/api/v4/users?username=someuser') - .reply(200, [{ id: 123 }]) - .get('/api/v4/users?username=someotheruser') - .reply(200, [{ id: 124 }]) - .put('/api/v4/projects/undefined/merge_requests/42?assignee_id=123') - .reply(200) - .put( - '/api/v4/projects/undefined/merge_requests/42?assignee_ids[]=123&assignee_ids[]=124' - ) - .reply(200); - await gitlab.addAssignees(42, ['someuser', 'someotheruser']); - expect(httpMock.getTrace()).toMatchSnapshot(); - }); }); describe('addReviewers(iid, reviewers)', () => { diff --git a/lib/platform/gitlab/index.ts b/lib/platform/gitlab/index.ts index dff78ae7b100aa84ddf29d9bcb0e9d271cd0af5f..b11444d241b62a3b5203d571c4d601644bbc11d4 100644 --- a/lib/platform/gitlab/index.ts +++ b/lib/platform/gitlab/index.ts @@ -934,23 +934,18 @@ export async function addAssignees( iid: number, assignees: string[] ): Promise<void> { - logger.debug(`Adding assignees '${assignees.join(', ')}' to #${iid}`); try { - let assigneeId = await getUserID(assignees[0]); - let url = `projects/${config.repository}/merge_requests/${iid}?assignee_id=${assigneeId}`; - await gitlabApi.putJson(url); - try { - if (assignees.length > 1) { - url = `projects/${config.repository}/merge_requests/${iid}?assignee_ids[]=${assigneeId}`; - for (let i = 1; i < assignees.length; i += 1) { - assigneeId = await getUserID(assignees[i]); - url += `&assignee_ids[]=${assigneeId}`; - } - await gitlabApi.putJson(url); - } - } catch (error) { - logger.error({ iid, assignees }, 'Failed to add multiple assignees'); + logger.debug(`Adding assignees '${assignees.join(', ')}' to #${iid}`); + const assigneeIds = []; + for (const assignee of assignees) { + assigneeIds.push(await getUserID(assignee)); } + const url = `projects/${ + config.repository + }/merge_requests/${iid}?${getQueryString({ + 'assignee_ids[]': assigneeIds, + })}`; + await gitlabApi.putJson(url); } catch (err) { logger.debug({ err }, 'addAssignees error'); logger.warn({ iid, assignees }, 'Failed to add assignees');