diff --git a/src/main/java/cd/go/authorization/gitlab/client/GitLabClient.java b/src/main/java/cd/go/authorization/gitlab/client/GitLabClient.java index 3b9bcf6..0b23c19 100644 --- a/src/main/java/cd/go/authorization/gitlab/client/GitLabClient.java +++ b/src/main/java/cd/go/authorization/gitlab/client/GitLabClient.java @@ -26,6 +26,7 @@ import okhttp3.*; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -118,7 +119,7 @@ public List groups(String personalAccessToken) throws IOException { final String groupsUrl = apiUrlWithPersonalAccessToken(gitLabConfiguration.gitLabBaseURL(), "groups"); final Request request = getRequestWithAccessToken(groupsUrl,personalAccessToken); - return executeRequest(request, response -> GitLabGroup.fromJSONArray(response.body().string())); + return executeRequestRepeated(request, response -> GitLabGroup.fromJSONArray(response.body().string())); } public List projects(String personalAccessToken) throws IOException { @@ -127,7 +128,7 @@ public List projects(String personalAccessToken) throws IOExcepti final String projectsUrl = apiUrlWithPersonalAccessToken(gitLabConfiguration.gitLabBaseURL(), "projects"); final Request request = getRequestWithAccessToken(projectsUrl,personalAccessToken); - return executeRequest(request, response -> GitLabProject.fromJSONArray(response.body().string())); + return executeRequestRepeated(request, response -> GitLabProject.fromJSONArray(response.body().string())); } public MembershipInfo groupMembershipInfo(String personalAccessToken, long groupId, long memberId) throws IOException { @@ -175,6 +176,42 @@ private T executeRequest(Request request, Callback callback) throws IOExc return callback.onResponse(response); } + /** + * Repeatedly execute the request until all pages are loaded + */ + private > List executeRequestRepeated(Request request, Callback callback) throws IOException { + HttpUrl originalUrl = request.url(); + List result = new ArrayList<>(); + do { + final Response response = httpClient.newCall(request).execute(); + + if (!response.isSuccessful()) { + final String responseBody = response.body().string(); + final String errorMessage = isNotBlank(responseBody) ? responseBody : response.message(); + throw new RuntimeException(format(API_ERROR_MSG, request.url().encodedPath(), errorMessage)); + } + + result.addAll(callback.onResponse(response)); + + // Check if there are more pages to load + String nextPage = response.header("x-next-page"); + if (nextPage != null && !nextPage.trim().isEmpty()) { + HttpUrl url = originalUrl + .newBuilder() + .addQueryParameter("page", nextPage.trim()) + .build(); + request = request + .newBuilder() + .url(url) + .build(); + continue; + } + break; + } while (true); + + return result; + } + private void validateTokenInfo(TokenInfo tokenInfo) { if (tokenInfo == null) { throw new RuntimeException("TokenInfo must not be null."); diff --git a/src/test/java/cd/go/authorization/gitlab/client/GitLabClientTest.java b/src/test/java/cd/go/authorization/gitlab/client/GitLabClientTest.java index f4f27cb..c81b16a 100644 --- a/src/test/java/cd/go/authorization/gitlab/client/GitLabClientTest.java +++ b/src/test/java/cd/go/authorization/gitlab/client/GitLabClientTest.java @@ -147,6 +147,33 @@ public void shouldFetchGroupsForAUser() throws Exception { assertEquals(personalAccessToken, request.getHeaders().get("Private-Token")); } + @Test + public void shouldFetchPagedGroupsForAUser() throws Exception { + final String personalAccessToken = "some-random-token"; + server.enqueue(new MockResponse() + .setResponseCode(200) + .addHeader("x-next-page", "2") + .setBody(GSON.toJson(asList(new GitLabGroup(1L, "foo-group"))))); + server.enqueue(new MockResponse() + .setResponseCode(200) + .addHeader("x-next-page", "") + .setBody(GSON.toJson(asList(new GitLabGroup(2L, "bar-group"))))); + + when(gitLabConfiguration.gitLabBaseURL()).thenReturn(server.url("/").toString()); + + final List gitLabGroups = gitLabClient.groups(personalAccessToken); + + assertThat(gitLabGroups, hasSize(2)); + assertThat(gitLabGroups.get(0).getName(), is("foo-group")); + assertThat(gitLabGroups.get(1).getName(), is("bar-group")); + + RecordedRequest request = server.takeRequest(); + assertEquals("GET /api/v4/groups HTTP/1.1", request.getRequestLine()); + assertNotNull(request.getHeaders().get("Private-Token")); + assertEquals(personalAccessToken, request.getHeaders().get("Private-Token")); + } + + @Test public void shouldFetchProjectsForAUser() throws Exception { final String personalAccessToken = "some-random-token"; @@ -167,6 +194,34 @@ public void shouldFetchProjectsForAUser() throws Exception { assertEquals(personalAccessToken, request.getHeaders().get("Private-Token")); } + @Test + public void shouldFetchPagedProjectsForAUser() throws Exception { + final String personalAccessToken = "some-random-token"; + server.enqueue(new MockResponse() + .setResponseCode(200) + .addHeader("x-next-page", "2") + .setBody(GSON.toJson(asList(new GitLabProject(1L, "foo-project"))))); + server.enqueue(new MockResponse() + .setResponseCode(200) + .addHeader("x-next-page", "") + .setBody(GSON.toJson(asList(new GitLabProject(2L, "bar-project"))))); + + + when(gitLabConfiguration.gitLabBaseURL()).thenReturn(server.url("/").toString()); + + final List gitLabProjects = gitLabClient.projects(personalAccessToken); + + assertThat(gitLabProjects, hasSize(2)); + assertThat(gitLabProjects.get(0).getName(), is("foo-project")); + assertThat(gitLabProjects.get(1).getName(), is("bar-project")); + + RecordedRequest request = server.takeRequest(); + assertEquals("GET /api/v4/projects HTTP/1.1", request.getRequestLine()); + assertNotNull(request.getHeaders().get("Private-Token")); + assertEquals(personalAccessToken, request.getHeaders().get("Private-Token")); + } + + @Test public void shouldFetchGroupMembershipForAUser() throws Exception { final String personalAccessToken = "some-random-token";