Skip to content

Commit

Permalink
fix: Fix issues with urlFor method
Browse files Browse the repository at this point in the history
  • Loading branch information
Abhi347 committed May 23, 2024
1 parent 083b917 commit d86b494
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 113 deletions.
17 changes: 11 additions & 6 deletions src/main/java/com/spotify/github/http/AbstractGitHubApiClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.ws.rs.core.MediaType;
Expand Down Expand Up @@ -119,21 +120,25 @@ private String getInstallationToken(final String jwtToken, final int installatio
}

/**
* Create a URL for a given path to this Github server.
* Create a URL for a given path to this GitHub server.
*
* @param path relative URI
* @return URL to path on this server
*/
String urlFor(final String path) {
return clientConfig().baseUrl().toString().replaceAll("/+$", "")
+ "/"
+ path.replaceAll("^/+", "");
public Optional<String> urlFor(final String path) {
return clientConfig()
.baseUrl()
.map(
baseUrl -> baseUrl.toString().replaceAll("/+$", "") + "/" + path.replaceAll("^/+", ""));
}

private AccessToken generateInstallationToken(final String jwtToken, final int installationId)
throws Exception {
log.info("Got JWT Token. Now getting Github access_token for installation {}", installationId);
final String url = String.format(urlFor(GET_ACCESS_TOKEN_URL), installationId);
final String accessTokenUrl =
urlFor(GET_ACCESS_TOKEN_URL)
.orElseThrow(() -> new IllegalStateException("No baseUrl defined"));
final String url = String.format(accessTokenUrl, installationId);
final Request request =
new Request.Builder()
.addHeader("Accept", "application/vnd.github.machine-man-preview+json")
Expand Down
70 changes: 2 additions & 68 deletions src/main/java/com/spotify/github/v3/clients/GitHubClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
import java.io.*;
import java.lang.invoke.MethodHandles;
import java.net.URI;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -709,20 +708,11 @@ CompletableFuture<Response> delete(final String path, final String data) {
return call(request);
}

/**
* Create a URL for a given path to this Github server.
*
* @param path relative URI
* @return URL to path on this server
*/
String urlFor(final String path) {
return baseUrl.toString().replaceAll("/+$", "") + "/" + path.replaceAll("^/+", "");
}

private Request.Builder requestBuilder(final String path) {
String url = urlFor(path).orElseThrow(() -> new IllegalStateException("No baseUrl defined"));
final Request.Builder builder =
new Request.Builder()
.url(urlFor(path))
.url(url)
.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
builder.addHeader(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(path));
Expand All @@ -745,62 +735,6 @@ protected OkHttpClient client() {
return client;
}

private boolean isJwtRequest(final String path) {
return path.startsWith("/app/installation") || path.endsWith("installation");
}

private String getInstallationToken(final String jwtToken, final int installationId)
throws Exception {

AccessToken installationToken = installationTokens.get(installationId);

if (installationToken == null || isExpired(installationToken)) {
log.info(
"Github token for installation {} is either expired or null. Trying to get a new one.",
installationId);
installationToken = generateInstallationToken(jwtToken, installationId);
installationTokens.put(installationId, installationToken);
}
return installationToken.token();
}

private boolean isExpired(final AccessToken token) {
// Adds a few minutes to avoid making calls with an expired token due to clock differences
return token.expiresAt().isBefore(ZonedDateTime.now().plusMinutes(EXPIRY_MARGIN_IN_MINUTES));
}

private AccessToken generateInstallationToken(final String jwtToken, final int installationId)
throws Exception {
log.info("Got JWT Token. Now getting Github access_token for installation {}", installationId);
final String url = String.format(urlFor(GET_ACCESS_TOKEN_URL), installationId);
final Request request =
new Request.Builder()
.addHeader("Accept", "application/vnd.github.machine-man-preview+json")
.addHeader("Authorization", "Bearer " + jwtToken)
.url(url)
.method("POST", RequestBody.create(parse(MediaType.APPLICATION_JSON), ""))
.build();

final Response response = client.newCall(request).execute();

if (!response.isSuccessful()) {
throw new Exception(
String.format(
"Got non-2xx status %s when getting an access token from GitHub: %s",
response.code(), response.message()));
}

if (response.body() == null) {
throw new Exception(
String.format(
"Got empty response body when getting an access token from GitHub, HTTP status was: %s",
response.message()));
}
final String text = response.body().string();
response.body().close();
return Json.create().fromJson(text, AccessToken.class);
}

@Override
protected RequestNotOkException mapException(final Response res, final Request request)
throws IOException {
Expand Down
34 changes: 18 additions & 16 deletions src/main/java/com/spotify/github/v3/clients/GithubPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand Down Expand Up @@ -37,7 +37,6 @@
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
import okhttp3.ResponseBody;

/**
Expand Down Expand Up @@ -117,12 +116,14 @@ public CompletableFuture<Pagination> pagination() {
/** {@inheritDoc} */
@Override
public CompletableFuture<AsyncPage<T>> nextPage() {
String url =
github.urlFor("").orElseThrow(() -> new IllegalStateException("No baseUrl defined"));
return linkMapAsync()
.thenApply(
linkMap -> {
final String nextPath =
Optional.ofNullable(linkMap.get("next"))
.map(nextLink -> nextLink.url().toString().replaceAll(github.urlFor(""), ""))
.map(nextLink -> nextLink.url().toString().replaceAll(url, ""))
.orElseThrow(() -> new NoSuchElementException("Page iteration exhausted"));
return new GithubPage<>(github, nextPath, typeReference);
});
Expand Down Expand Up @@ -155,18 +156,19 @@ public Iterator<T> iterator() {
}

private CompletableFuture<Map<String, Link>> linkMapAsync() {
return github
.request(path)
.thenApply(
response -> {
Optional.ofNullable(response.body()).ifPresent(ResponseBody::close);
return Optional.ofNullable(response.headers().get("Link"))
.map(linkHeader -> stream(linkHeader.split(",")))
.orElseGet(Stream::empty)
.map(linkString -> Link.from(linkString.split(";")))
.filter(link -> link.rel().isPresent())
.collect(toMap(link -> link.rel().get(), identity()));
});
return Optional.ofNullable(github.request(path))
.map(
responseFuture ->
responseFuture.thenApply(
response -> {
Optional.ofNullable(response.body()).ifPresent(ResponseBody::close);
return Optional.ofNullable(response.headers().get("Link")).stream()
.flatMap(linkHeader -> stream(linkHeader.split(",")))
.map(linkString -> Link.from(linkString.split(";")))
.filter(link -> link.rel().isPresent())
.collect(toMap(link -> link.rel().get(), identity()));
}))
.orElse(CompletableFuture.completedFuture(Map.of()));
}

private Optional<Integer> pageNumberFromUri(final String uri) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public void setUp() {
GitHubClient.create(
ImmutableGitHubClientConfig.builder()
.client(client)
.baseUrl(URI.create("http://bogus"))
.baseUrl(URI.create("https://bogus"))
.accessToken("token")
.build());
}
Expand All @@ -91,7 +91,7 @@ public void withScopedInstallationIdShouldFailWhenMissingPrivateKey() {
public void testWithScopedInstallationId() throws URISyntaxException {
GitHubClient org =
GitHubClient.create(
new URI("http://apa.bepa.cepa"), "some_key_content".getBytes(), null, null);
new URI("https://apa.bepa.cepa"), "some_key_content".getBytes(), null, null);
GitHubClient scoped = org.withScopeForInstallationId(1);
Assertions.assertTrue(scoped.getPrivateKey().isPresent());
Assertions.assertEquals(org.getPrivateKey().get(), scoped.getPrivateKey().get());
Expand Down Expand Up @@ -202,7 +202,7 @@ public void testPutConvertsToClass() throws Throwable {

RepositoryInvitation invitation = future.get();
assertThat(requestCapture.getValue().method(), is("PUT"));
assertThat(requestCapture.getValue().url().toString(), is("http://bogus/collaborators/"));
assertThat(requestCapture.getValue().url().toString(), is("https://bogus/collaborators/"));
assertThat(invitation.id(), is(1));
}

Expand Down
21 changes: 16 additions & 5 deletions src/test/java/com/spotify/github/v3/clients/IssueClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -32,17 +32,21 @@
import static org.hamcrest.core.Is.is;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.when;

import com.google.common.collect.Lists;
import com.google.common.io.Resources;
import com.spotify.github.async.Async;
import com.spotify.github.async.AsyncPage;
import com.spotify.github.http.GitHubClientConfig;
import com.spotify.github.http.ImmutableGitHubClientConfig;
import com.spotify.github.jackson.Json;
import com.spotify.github.v3.comment.Comment;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand All @@ -54,9 +58,15 @@ public class IssueClientTest {

@BeforeEach
public void setUp() {
GitHubClientConfig config =
ImmutableGitHubClientConfig.builder()
.baseUrl(URI.create("https://github.com/api/v3"))
.client(mock(OkHttpClient.class))
.build();
github = mock(GitHubClient.class);
when(github.clientConfig()).thenReturn(config);
when(github.urlFor(anyString())).thenCallRealMethod();
when(github.json()).thenReturn(Json.create());
when(github.urlFor("")).thenReturn("https://github.com/api/v3");
issueClient = new IssueClient(github, "someowner", "somerepo");
}

Expand All @@ -81,7 +91,8 @@ public void testCommentPaginationSpliterator() throws IOException {
.thenReturn(completedFuture(lastPageResponse));

final Iterable<AsyncPage<Comment>> pageIterator = () -> issueClient.listComments(123);
final List<Comment> listComments = Async.streamFromPaginatingIterable(pageIterator).collect(toList());
final List<Comment> listComments =
Async.streamFromPaginatingIterable(pageIterator).collect(toList());

assertThat(listComments.size(), is(30));
assertThat(listComments.get(0).id(), is(1345268));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
import com.google.common.io.Resources;
import com.spotify.github.async.Async;
import com.spotify.github.async.AsyncPage;
import com.spotify.github.http.GitHubClientConfig;
import com.spotify.github.http.ImmutableGitHubClientConfig;
import com.spotify.github.jackson.Json;
import com.spotify.github.v3.comment.Comment;
import com.spotify.github.v3.prs.PullRequestItem;
Expand All @@ -64,19 +66,18 @@
import com.spotify.github.v3.repos.RepositoryTest;
import com.spotify.github.v3.repos.Status;
import com.spotify.github.v3.repos.requests.*;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import okhttp3.MediaType;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

import com.spotify.github.v3.repos.requests.ImmutableAuthenticatedUserRepositoriesFilter;
import com.spotify.github.v3.repos.requests.ImmutableRepositoryUpdate;
import okhttp3.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
Expand All @@ -94,7 +95,14 @@ private static String getFixture(String resource) throws IOException {

@BeforeEach
public void setUp() {
GitHubClientConfig config =
ImmutableGitHubClientConfig.builder()
.baseUrl(URI.create("https://github.com/api/v3"))
.client(mock(OkHttpClient.class))
.build();
github = mock(GitHubClient.class);
when(github.clientConfig()).thenReturn(config);
when(github.urlFor(anyString())).thenCallRealMethod();
repoClient = new RepositoryClient(github, "someowner", "somerepo");
json = Json.create();
when(github.json()).thenReturn(json);
Expand Down Expand Up @@ -565,7 +573,7 @@ public void testStatusesPaginationForeach() throws Exception {
final String lastPageBody = loadFixture("clients/statuses_page2.json");
final Response lastPageResponse = createMockResponse(lastPageLink, lastPageBody);

when(github.urlFor("")).thenReturn("https://github.com/api/v3");
when(github.urlFor("")).thenReturn(Optional.of("https://github.com/api/v3"));

when(github.request(
format(
Expand Down
Loading

0 comments on commit d86b494

Please sign in to comment.