Skip to content

Commit bc76a8a

Browse files
Add asAppScopedClient() function for convenience
1 parent 55ad5a3 commit bc76a8a

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

src/main/java/com/spotify/github/async/Async.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
package com.spotify.github.async;
2222

23+
import java.util.concurrent.CompletableFuture;
24+
import java.util.function.Function;
2325
import java.util.stream.Stream;
2426

2527
import static java.util.stream.StreamSupport.stream;
@@ -34,4 +36,19 @@ public static <T> Stream<T> streamFromPaginatingIterable(final Iterable<AsyncPag
3436
return stream(iterable.spliterator(), false)
3537
.flatMap(page -> stream(page.spliterator(), false));
3638
}
39+
40+
public static <T> CompletableFuture<T> exceptionallyCompose(
41+
CompletableFuture<T> future, Function<Throwable, CompletableFuture<T>> handler) {
42+
43+
return future
44+
.handle(
45+
(result, throwable) -> {
46+
if (throwable != null) {
47+
return handler.apply(throwable);
48+
} else {
49+
return CompletableFuture.completedFuture(result);
50+
}
51+
})
52+
.thenCompose(Function.identity());
53+
}
3754
}

src/main/java/com/spotify/github/v3/clients/GitHubClient.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@
2525

2626
import com.fasterxml.jackson.core.type.TypeReference;
2727
import com.spotify.github.Tracer;
28+
import com.spotify.github.async.Async;
2829
import com.spotify.github.jackson.Json;
2930
import com.spotify.github.v3.Team;
3031
import com.spotify.github.v3.User;
3132
import com.spotify.github.v3.checks.AccessToken;
33+
import com.spotify.github.v3.checks.Installation;
3234
import com.spotify.github.v3.comment.Comment;
3335
import com.spotify.github.v3.exceptions.ReadOnlyRepositoryException;
3436
import com.spotify.github.v3.exceptions.RequestNotOkException;
@@ -54,6 +56,7 @@
5456
import java.util.Objects;
5557
import java.util.Optional;
5658
import java.util.concurrent.CompletableFuture;
59+
import java.util.concurrent.CompletionStage;
5760
import java.util.concurrent.atomic.AtomicBoolean;
5861
import java.util.function.Consumer;
5962
import javax.ws.rs.core.HttpHeaders;
@@ -367,6 +370,37 @@ public GitHubClient withScopeForInstallationId(final int installationId) {
367370
installationId);
368371
}
369372

373+
/**
374+
* This is for clients authenticated as a GitHub App: when performing operations,
375+
* the "installation" of the App must be specified.
376+
* This returns a {@code GitHubClient} that has been scoped to the
377+
* user's/organization's installation of the app, if any.
378+
*/
379+
public CompletionStage<Optional<GitHubClient>> asAppScopedClient(String owner) {
380+
return Async.exceptionallyCompose(this
381+
.createOrganisationClient(owner)
382+
.createGithubAppClient()
383+
.getInstallation()
384+
.thenApply(Installation::id), e -> {
385+
if (e.getCause() instanceof RequestNotOkException && ((RequestNotOkException) e).statusCode() == 404) {
386+
return this
387+
.createUserClient(owner)
388+
.createGithubAppClient()
389+
.getUserInstallation()
390+
.thenApply(Installation::id);
391+
}
392+
return CompletableFuture.failedFuture(e);
393+
})
394+
.thenApply(id -> Optional.of(this.withScopeForInstallationId(id)))
395+
.exceptionally(
396+
e -> {
397+
if (e.getCause() instanceof RequestNotOkException && ((RequestNotOkException) e).statusCode() == 404) {
398+
return Optional.empty();
399+
}
400+
throw new RuntimeException(e);
401+
});
402+
}
403+
370404
public GitHubClient withTracer(final Tracer tracer) {
371405
this.tracer = tracer;
372406
return this;

0 commit comments

Comments
 (0)