listCommentReaction(final long commentId) {
+ final String path = String.format(COMMENTS_REACTION_TEMPLATE, owner, repo, commentId);
+ return new GithubPageIterator<>(
+ new GithubPage<>(github, path, LIST_COMMENT_REACTION_TYPE_REFERENCE));
+ }
}
diff --git a/src/main/java/com/spotify/github/v3/comment/CommentReaction.java b/src/main/java/com/spotify/github/v3/comment/CommentReaction.java
new file mode 100644
index 00000000..705d0dd2
--- /dev/null
+++ b/src/main/java/com/spotify/github/v3/comment/CommentReaction.java
@@ -0,0 +1,50 @@
+/*-
+ * -\-\-
+ * github-api
+ * --
+ * Copyright (C) 2016 - 2020 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.comment;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.spotify.github.GithubStyle;
+import com.spotify.github.UpdateTracking;
+import com.spotify.github.v3.User;
+import org.immutables.value.Value;
+
+/**
+ * Comment reaction object.
+ *
+ * See About
+ * GitHub Issue Comment reactions
+ */
+@Value.Immutable
+@GithubStyle
+@JsonSerialize(as = ImmutableCommentReaction.class)
+@JsonDeserialize(as = ImmutableCommentReaction.class)
+public interface CommentReaction extends UpdateTracking {
+
+ /** Reaction ID. */
+ long id();
+
+ /** Reaction user. */
+ User user();
+
+ /** Reaction content. */
+ CommentReactionContent content();
+}
diff --git a/src/main/java/com/spotify/github/v3/comment/CommentReactionContent.java b/src/main/java/com/spotify/github/v3/comment/CommentReactionContent.java
new file mode 100644
index 00000000..cc4f8727
--- /dev/null
+++ b/src/main/java/com/spotify/github/v3/comment/CommentReactionContent.java
@@ -0,0 +1,56 @@
+/*-
+ * -\-\-
+ * github-api
+ * --
+ * Copyright (C) 2016 - 2020 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.comment;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.spotify.github.jackson.CommentReactionContentDeserializer;
+import com.spotify.github.jackson.CommentReactionContentSerializer;
+
+/**
+ * Comment reaction content.
+ *
+ *
See About
+ * GitHub Issue Comment reactions
+ */
+@JsonDeserialize(using = CommentReactionContentDeserializer.class)
+@JsonSerialize(using = CommentReactionContentSerializer.class)
+public enum CommentReactionContent {
+ THUMBS_UP("+1"), // 👍
+ THUMBS_DOWN("-1"), // 👎
+ LAUGH("laugh"), // 😄
+ HOORAY("hooray"), // 🎉
+ CONFUSED("confused"), // 😕
+ HEART("heart"), // ❤️
+ ROCKET("rocket"), // 🚀
+ EYES("eyes"); // 👀
+
+ private final String reaction;
+
+ CommentReactionContent(final String reaction) {
+ this.reaction = reaction;
+ }
+
+ @Override
+ public String toString() {
+ return reaction;
+ }
+}
diff --git a/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java b/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java
index 473fe26f..b7e898d6 100644
--- a/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java
+++ b/src/test/java/com/spotify/github/v3/clients/IssueClientTest.java
@@ -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.
@@ -22,8 +22,7 @@
import static com.google.common.io.Resources.getResource;
import static com.spotify.github.FixtureHelper.loadFixture;
-import static com.spotify.github.v3.clients.IssueClient.COMMENTS_URI_NUMBER_TEMPLATE;
-import static com.spotify.github.v3.clients.IssueClient.ISSUES_URI_ID_TEMPLATE;
+import static com.spotify.github.v3.clients.IssueClient.*;
import static com.spotify.github.v3.clients.MockHelper.createMockResponse;
import static java.lang.String.format;
import static java.nio.charset.Charset.defaultCharset;
@@ -37,15 +36,19 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
+import com.google.common.collect.ImmutableMap;
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.jackson.Json;
+import com.spotify.github.v3.ImmutableUser;
import com.spotify.github.v3.comment.Comment;
+import com.spotify.github.v3.comment.CommentReaction;
+import com.spotify.github.v3.comment.CommentReactionContent;
+import com.spotify.github.v3.comment.ImmutableCommentReaction;
import com.spotify.github.v3.exceptions.RequestNotOkException;
import com.spotify.github.v3.issues.Issue;
import java.io.IOException;
@@ -56,6 +59,8 @@
import okhttp3.Response;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
public class IssueClientTest {
@@ -63,7 +68,6 @@ public class IssueClientTest {
private IssueClient issueClient;
private Json json;
-
@BeforeEach
public void setUp() {
json = Json.create();
@@ -94,7 +98,8 @@ public void testCommentPaginationSpliterator() throws IOException {
.thenReturn(completedFuture(lastPageResponse));
final Iterable> pageIterator = () -> issueClient.listComments(123);
- final List listComments = Async.streamFromPaginatingIterable(pageIterator).collect(toList());
+ final List listComments =
+ Async.streamFromPaginatingIterable(pageIterator).collect(toList());
assertThat(listComments.size(), is(30));
assertThat(listComments.get(0).id(), is(1345268));
@@ -161,10 +166,92 @@ public void testGetIssue() throws IOException {
assertThat(issue.labels().get(0).name(), is("bug"));
}
+ @ParameterizedTest
+ @EnumSource(CommentReactionContent.class)
+ public void testCreateIssueCommentReaction(CommentReactionContent reaction) {
+ long commentId = 22369886;
+ final CompletableFuture reactionResponse =
+ completedFuture(
+ ImmutableCommentReaction.builder()
+ .id(42L)
+ .content(reaction)
+ .user(ImmutableUser.builder().login("octocat").build())
+ .build());
+ final String path = format(COMMENTS_REACTION_TEMPLATE, "someowner", "somerepo", commentId);
+ final String requestBody =
+ github.json().toJsonUnchecked(ImmutableMap.of("content", reaction.toString()));
+ when(github.post(eq(path), eq(requestBody), eq(CommentReaction.class)))
+ .thenReturn(reactionResponse);
+
+ final var commentReaction = issueClient.createCommentReaction(commentId, reaction).join();
+
+ assertThat(commentReaction.id(), is(42L));
+ assertNotNull(commentReaction.user());
+ assertThat(commentReaction.user().login(), is("octocat"));
+ assertThat(commentReaction.content().toString(), is(reaction.toString()));
+ verify(github, times(1)).post(eq(path), eq(requestBody), eq(CommentReaction.class));
+ }
+
+ @Test
+ public void testDeleteIssueCommentReaction() {
+ long issueNumber = 42;
+ long reactionId = 385825;
+ final String path =
+ format(COMMENTS_REACTION_ID_TEMPLATE, "someowner", "somerepo", issueNumber, reactionId);
+ Response mockResponse = mock(Response.class);
+ when(mockResponse.code()).thenReturn(204);
+ when(github.delete(eq(path))).thenReturn(completedFuture(mockResponse));
+
+ final var response = issueClient.deleteCommentReaction(issueNumber, reactionId).join();
+
+ assertThat(response.code(), is(204));
+ assertThat(response, is(mockResponse));
+ verify(github, times(1)).delete(eq(path));
+ }
+
+ @Test
+ public void testListIssueCommentReaction() throws IOException {
+ long commentId = 22369886;
+ final CompletableFuture> listResponse =
+ completedFuture(
+ List.of(
+ (ImmutableCommentReaction.builder()
+ .id(42L)
+ .content(CommentReactionContent.HEART)
+ .user(ImmutableUser.builder().login("octocat").build())
+ .build())));
+ final String path = format(COMMENTS_REACTION_TEMPLATE, "someowner", "somerepo", commentId);
+
+ final String firstPageLink =
+ format(
+ "; rel=\"last\"",
+ commentId);
+ final String firstPageBody = github.json().toJsonUnchecked(listResponse.join().toArray());
+ final Response firstPageResponse = createMockResponse(firstPageLink, firstPageBody);
+
+ when(github.request(eq(path))).thenReturn(completedFuture(firstPageResponse));
+ final List listCommentReactions = Lists.newArrayList();
+ issueClient
+ .listCommentReaction(commentId)
+ .forEachRemaining(
+ page -> {
+ page.iterator().forEachRemaining(listCommentReactions::add);
+ });
+
+ assertThat(listCommentReactions.size(), is(1));
+ assertNotNull(listCommentReactions.get(0));
+ assertThat(listCommentReactions.get(0).user().login(), is("octocat"));
+ assertThat(
+ listCommentReactions.get(0).content().toString(),
+ is(CommentReactionContent.HEART.toString()));
+ verify(github, atLeastOnce()).request(eq(path));
+ }
+
@Test
public void testGetIssueNoIssue() {
final String path = format(ISSUES_URI_ID_TEMPLATE, "someowner", "somerepo", 2);
- when(github.request(eq(path), eq(Issue.class))).thenReturn(failedFuture(new RequestNotOkException("", "", 404, "", new HashMap<>())));
+ when(github.request(eq(path), eq(Issue.class)))
+ .thenReturn(failedFuture(new RequestNotOkException("", "", 404, "", new HashMap<>())));
assertThrows(CompletionException.class, () -> issueClient.getIssue(2).join());
}
diff --git a/src/test/java/com/spotify/github/v3/comment/CommentReactionContentTest.java b/src/test/java/com/spotify/github/v3/comment/CommentReactionContentTest.java
new file mode 100644
index 00000000..cade32ba
--- /dev/null
+++ b/src/test/java/com/spotify/github/v3/comment/CommentReactionContentTest.java
@@ -0,0 +1,40 @@
+/*-
+ * -\-\-
+ * github-api
+ * --
+ * Copyright (C) 2016 - 2020 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.comment;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+class CommentReactionContentTest {
+ @ParameterizedTest
+ @EnumSource(CommentReactionContent.class)
+ public void testDeserialize(CommentReactionContent reaction) throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+
+ String json = "\"" + reaction.toString() + "\"";
+
+ CommentReactionContent content = mapper.readValue(json, CommentReactionContent.class);
+
+ assertEquals(reaction, content);
+ }
+}