From 67892fd4d9b5075ad97bcc5414e6f16f976404c0 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Tue, 14 Mar 2023 16:06:19 -0400 Subject: [PATCH] support multiple pages of group members Signed-off-by: Jamie Klassen --- .../src/lib/client.test.ts | 36 ++++++++++ .../src/lib/client.ts | 72 +++++++++++-------- .../GitlabOrgDiscoveryEntityProvider.test.ts | 4 ++ 3 files changed, 82 insertions(+), 30 deletions(-) diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts index 0a50742a27..a3bcd140ee 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts @@ -409,6 +409,10 @@ describe('GitLabClient', () => { group: { groupMembers: { nodes: [{ user: { id: 'gid://gitlab/User/1' } }], + pageInfo: { + endCursor: 'end', + hasNextPage: false, + }, }, }, }), @@ -446,6 +450,38 @@ describe('GitLabClient', () => { 'GraphQL errors: [{"message":"Unexpected end of document","locations":[]}]', ); }); + + it('traverses multi-page results', async () => { + server.use( + graphql + .link(`${MOCK_CONFIG.baseUrl}/api/graphql`) + .operation((req, res, ctx) => + res( + ctx.data({ + group: { + groupMembers: { + nodes: req.variables.endCursor + ? [{ user: { id: 'gid://gitlab/User/2' } }] + : [{ user: { id: 'gid://gitlab/User/1' } }], + pageInfo: { + endCursor: req.variables.endCursor ? 'end' : 'next', + hasNextPage: !req.variables.endCursor, + }, + }, + }, + }), + ), + ), + ); + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const members = await client.getGroupMembers('group1'); + + expect(members).toEqual([1, 2]); + }); }); }); diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.ts index a2d8ec971a..8f8c67895c 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.ts @@ -92,38 +92,50 @@ export class GitLabClient { } async getGroupMembers(groupPath: string): Promise { - const response: GitLabGroupMembersResponse = await fetch( - `${this.config.baseUrl}/api/graphql`, - { - method: 'POST', - headers: { - ...getGitLabRequestOptions(this.config).headers, - ['Content-Type']: 'application/json', - }, - body: JSON.stringify({ - variables: { group: groupPath }, - query: `query($group: ID!) { - group(fullPath: $group) { - groupMembers(first: 10, relations: [DIRECT]) { - nodes { - user { - id + const memberIds = []; + let hasNextPage: boolean = false; + let endCursor: string | null = null; + do { + const response: GitLabGroupMembersResponse = await fetch( + `${this.config.baseUrl}/api/graphql`, + { + method: 'POST', + headers: { + ...getGitLabRequestOptions(this.config).headers, + ['Content-Type']: 'application/json', + }, + body: JSON.stringify({ + variables: { group: groupPath, endCursor }, + query: `query($group: ID!, $endCursor: String) { + group(fullPath: $group) { + groupMembers(first: 100, relations: [DIRECT], after: $endCursor) { + nodes { + user { + id + } + } + pageInfo { + endCursor + hasNextPage + } } } - } - } - }`, - }), - }, - ).then(r => r.json()); - if (response.errors) { - throw new Error(`GraphQL errors: ${JSON.stringify(response.errors)}`); - } - - return response.data.group.groupMembers.nodes.map( - (node: { user: { id: string } }) => - Number(node.user.id.replace(/^gid:\/\/gitlab\/User\//, '')), - ); + }`, + }), + }, + ).then(r => r.json()); + if (response.errors) { + throw new Error(`GraphQL errors: ${JSON.stringify(response.errors)}`); + } + memberIds.push( + ...response.data.group.groupMembers.nodes.map( + (node: { user: { id: string } }) => + Number(node.user.id.replace(/^gid:\/\/gitlab\/User\//, '')), + ), + ); + ({ hasNextPage, endCursor } = response.data.group.groupMembers.pageInfo); + } while (hasNextPage); + return memberIds; } /** diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts index 88f8d58bf2..3d6ff0a91a 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts @@ -329,6 +329,10 @@ describe('GitlabOrgDiscoveryEntityProvider', () => { req.variables.group === 'group1/group2' ? [{ user: { id: 'gid://gitlab/User/1' } }] : [], + pageInfo: { + endCursor: 'end', + hasNextPage: false, + }, }, }, }),