diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0f07f445..7544666b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4
- - uses: actions/setup-java@v3
+ - uses: actions/setup-java@v4
with:
java-version: 11
distribution: corretto
diff --git a/pom.xml b/pom.xml
index 02c1bc9a..344302b4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
github-client
- 0.2.18-SNAPSHOT
+ 0.3.2-SNAPSHOT
com.spotify
@@ -84,7 +84,7 @@
UTF-8
UTF-8
- 1710939443
+ 1720619003
spotbugsexclude.xml
error
checkstyle.xml
diff --git a/src/main/java/com/spotify/github/v3/clients/GithubAppClient.java b/src/main/java/com/spotify/github/v3/clients/GithubAppClient.java
index 9198fc60..e9150d96 100644
--- a/src/main/java/com/spotify/github/v3/clients/GithubAppClient.java
+++ b/src/main/java/com/spotify/github/v3/clients/GithubAppClient.java
@@ -45,6 +45,7 @@ public class GithubAppClient {
refer to the organisation in the installation endpoint
*/
private static final String GET_INSTALLATION_ORG_URL = "/orgs/%s/installation";
+ private static final String GET_INSTALLATION_USER_URL = "/users/%s/installation";
private final GitHubClient github;
private final String owner;
@@ -78,7 +79,7 @@ public CompletableFuture> getInstallations() {
}
/**
- * Get Installation
+ * Get Installation of repo or org
*
* @return an Installation
*/
@@ -114,6 +115,15 @@ private CompletableFuture getOrgInstallation() {
String.format(GET_INSTALLATION_ORG_URL, owner), Installation.class);
}
+ /**
+ * Get an installation of a user
+ * @return an Installation
+ */
+ public CompletableFuture getUserInstallation() {
+ return github.request(
+ String.format(GET_INSTALLATION_USER_URL, owner), Installation.class);
+ }
+
/**
* Authenticates as an installation
*
diff --git a/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java b/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java
index 97fd5bc1..c2c49c04 100644
--- a/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java
+++ b/src/main/java/com/spotify/github/v3/clients/RepositoryClient.java
@@ -85,6 +85,7 @@ public class RepositoryClient {
private static final String BRANCH_TEMPLATE = "/repos/%s/%s/branches/%s";
private static final String LIST_BRANCHES_TEMPLATE = "/repos/%s/%s/branches";
private static final String CREATE_COMMENT_TEMPLATE = "/repos/%s/%s/commits/%s/comments";
+ private static final String CREATE_REPOSITORY_DISPATCH_EVENT_TEMPLATE = "/repos/%s/%s/dispatches";
private static final String COMMENT_TEMPLATE = "/repos/%s/%s/comments/%s";
private static final String LANGUAGES_TEMPLATE = "/repos/%s/%s/languages";
private static final String MERGE_TEMPLATE = "/repos/%s/%s/merges";
@@ -698,4 +699,17 @@ private String getContentPath(final String path, final String query) {
}
return String.format(CONTENTS_URI_TEMPLATE, owner, repo, path, query);
}
+
+ /**
+ * Create a repository_dispatch event.
+ *
+ * @param request The repository dispatch request.
+ */
+
+ public CompletableFuture createRepositoryDispatchEvent(final RepositoryDispatch request) {
+ final String path = String.format(CREATE_REPOSITORY_DISPATCH_EVENT_TEMPLATE, owner, repo);
+ return github
+ .post(path, github.json().toJsonUnchecked(request))
+ .thenApply(response -> response.code() == NO_CONTENT); //should always return a 204
+ }
}
diff --git a/src/main/java/com/spotify/github/v3/clients/UserClient.java b/src/main/java/com/spotify/github/v3/clients/UserClient.java
index 3ea24979..0d48e027 100644
--- a/src/main/java/com/spotify/github/v3/clients/UserClient.java
+++ b/src/main/java/com/spotify/github/v3/clients/UserClient.java
@@ -27,15 +27,21 @@ public class UserClient {
public static final int NO_CONTENT = 204;
private final GitHubClient github;
+ private final String owner;
private static final String SUSPEND_USER_TEMPLATE = "/users/%s/suspended";
- UserClient(final GitHubClient github) {
+ UserClient(final GitHubClient github, final String owner) {
this.github = github;
+ this.owner = owner;
}
- static UserClient create(final GitHubClient github) {
- return new UserClient(github);
+ static UserClient create(final GitHubClient github, final String owner) {
+ return new UserClient(github, owner);
+ }
+
+ public GithubAppClient createGithubAppClient() {
+ return new GithubAppClient(this.github, this.owner);
}
/**
diff --git a/src/main/java/com/spotify/github/v3/repos/requests/RepositoryDispatch.java b/src/main/java/com/spotify/github/v3/repos/requests/RepositoryDispatch.java
new file mode 100644
index 00000000..5c7c79e1
--- /dev/null
+++ b/src/main/java/com/spotify/github/v3/repos/requests/RepositoryDispatch.java
@@ -0,0 +1,44 @@
+/*-
+ * -\-\-
+ * github-api
+ * --
+ * Copyright (C) 2016 - 2023 Spotify AB
+ * --
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * -/-/-
+ */
+
+package com.spotify.github.v3.repos.requests;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.spotify.github.GithubStyle;
+import java.util.Optional;
+import org.immutables.value.Value;
+
+@Value.Immutable
+@GithubStyle
+@JsonSerialize(as = ImmutableRepositoryDispatch.class)
+@JsonDeserialize(as = ImmutableRepositoryDispatch.class)
+public interface RepositoryDispatch {
+
+ /** The custom webhook event name */
+
+ String eventType();
+
+ /** JSON payload with extra information about the webhook event
+ * that your action or workflow may use. */
+ Optional clientPayload();
+
+}
diff --git a/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java b/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java
index 128ed61b..c9d24a1e 100644
--- a/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java
+++ b/src/test/java/com/spotify/github/v3/clients/RepositoryClientTest.java
@@ -42,6 +42,8 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.io.Resources;
@@ -73,6 +75,7 @@
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import com.spotify.github.v3.repos.requests.ImmutableAuthenticatedUserRepositoriesFilter;
@@ -722,4 +725,26 @@ public void shouldReturnEmptyOptionalWhenResponseBodyNotPresent() throws Excepti
Optional response = repoClient.downloadZipball("master").get();
assertThat(response, is(Optional.empty()));
}
+
+ @Test
+ public void shouldReturnEmptyResponseWhenRepositoryDispatchEndpointTriggered() throws Exception {
+ final Response response = mock(Response.class);
+ when(response.code()).thenReturn(204);
+
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode clientPayload = mapper.createObjectNode();
+ clientPayload.put("my-custom-true-property","true");
+ clientPayload.put("my-custom-false-property", "false");
+
+ RepositoryDispatch repositoryDispatchRequest = ImmutableRepositoryDispatch.builder()
+ .eventType("my-custom-event")
+ .clientPayload(clientPayload)
+ .build();
+
+ when(github.post("/repos/someowner/somerepo/dispatches", json.toJsonUnchecked(repositoryDispatchRequest))).thenReturn(completedFuture(response));
+
+ boolean repoDispatchResult = repoClient.createRepositoryDispatchEvent(repositoryDispatchRequest).get();
+ assertTrue(repoDispatchResult);
+ }
+
}
diff --git a/src/test/java/com/spotify/github/v3/clients/UserClientTest.java b/src/test/java/com/spotify/github/v3/clients/UserClientTest.java
index 0211769b..ce8e7259 100644
--- a/src/test/java/com/spotify/github/v3/clients/UserClientTest.java
+++ b/src/test/java/com/spotify/github/v3/clients/UserClientTest.java
@@ -19,16 +19,25 @@
*/
package com.spotify.github.v3.clients;
+import static com.google.common.io.Resources.getResource;
+import static java.nio.charset.Charset.defaultCharset;
import static java.util.concurrent.CompletableFuture.completedFuture;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import com.google.common.io.Resources;
import com.spotify.github.jackson.Json;
+import com.spotify.github.v3.checks.Installation;
import com.spotify.github.v3.user.requests.ImmutableSuspensionReason;
+
+import java.io.IOException;
import java.util.concurrent.CompletableFuture;
+
import okhttp3.Response;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -37,12 +46,17 @@ public class UserClientTest {
private GitHubClient github;
private UserClient userClient;
+ private String owner = "github";
+ private Json json;
+ private static String getFixture(String resource) throws IOException {
+ return Resources.toString(getResource(TeamClientTest.class, resource), defaultCharset());
+ }
@BeforeEach
public void setUp() {
github = mock(GitHubClient.class);
- userClient = new UserClient(github);
- Json json = Json.create();
+ userClient = new UserClient(github, owner);
+ json = Json.create();
when(github.json()).thenReturn(json);
}
@@ -81,4 +95,17 @@ public void testUnSuspendUserFailure() throws Exception {
final CompletableFuture result = userClient.unSuspendUser("username", ImmutableSuspensionReason.builder().reason("That's why").build());
assertFalse(result.get());
}
+
+ @Test
+ public void testAppClient() throws Exception {
+ final GithubAppClient githubAppClient = userClient.createGithubAppClient();
+ final CompletableFuture fixture =
+ completedFuture(json.fromJson(getFixture("../githubapp/installation.json"), Installation.class));
+ when(github.request("/users/github/installation", Installation.class)).thenReturn(fixture);
+
+ final Installation installation = githubAppClient.getUserInstallation().get();
+
+ assertThat(installation.id(), is(1));
+ assertThat(installation.account().login(), is("github"));
+ }
}