support multiple pages of group members

Signed-off-by: Jamie Klassen <jklassen@vmware.com>
This commit is contained in:
Jamie Klassen
2023-03-14 16:06:19 -04:00
parent c35eebedad
commit 67892fd4d9
3 changed files with 82 additions and 30 deletions
@@ -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]);
});
});
});
@@ -92,38 +92,50 @@ export class GitLabClient {
}
async getGroupMembers(groupPath: string): Promise<number[]> {
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;
}
/**
@@ -329,6 +329,10 @@ describe('GitlabOrgDiscoveryEntityProvider', () => {
req.variables.group === 'group1/group2'
? [{ user: { id: 'gid://gitlab/User/1' } }]
: [],
pageInfo: {
endCursor: 'end',
hasNextPage: false,
},
},
},
}),