Skip to content

Commit 377eb0e

Browse files
committed
feat: Add Issue Comment Reaction functionality
1 parent c4a4e64 commit 377eb0e

File tree

4 files changed

+167
-9
lines changed

4 files changed

+167
-9
lines changed

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@
2626
import com.google.common.collect.ImmutableMap;
2727
import com.spotify.github.async.AsyncPage;
2828
import com.spotify.github.v3.comment.Comment;
29+
import com.spotify.github.v3.comment.CommentReaction;
30+
import com.spotify.github.v3.comment.CommentReactionContent;
2931
import com.spotify.github.v3.issues.Issue;
3032
import java.lang.invoke.MethodHandles;
3133
import java.util.Iterator;
3234
import java.util.concurrent.CompletableFuture;
35+
36+
import okhttp3.Response;
3337
import org.slf4j.Logger;
3438
import org.slf4j.LoggerFactory;
3539

@@ -39,6 +43,8 @@ public class IssueClient {
3943
static final String COMMENTS_URI_NUMBER_TEMPLATE = "/repos/%s/%s/issues/%s/comments";
4044
static final String COMMENTS_URI_TEMPLATE = "/repos/%s/%s/issues/comments";
4145
static final String COMMENTS_URI_ID_TEMPLATE = "/repos/%s/%s/issues/comments/%s";
46+
static final String COMMENTS_REACTION_TEMPLATE = "/repos/%s/%s/issues/comments/%s/reactions";
47+
static final String COMMENTS_REACTION_ID_TEMPLATE = "/repos/%s/%s/issues/%s/reactions/%s";
4248
static final String ISSUES_URI_ID_TEMPLATE = "/repos/%s/%s/issues/%s";
4349
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
4450

@@ -137,4 +143,23 @@ private Iterator<AsyncPage<Comment>> listComments(final String path) {
137143
public CompletableFuture<Issue> getIssue(final int id) {
138144
return github.request(String.format(ISSUES_URI_ID_TEMPLATE, owner, repo, id), Issue.class);
139145
}
146+
147+
/**
148+
* Create a reaction on a comment.
149+
*
150+
* @param commentId comment id
151+
* @param reaction reaction content
152+
* @return the Comment that was just created
153+
*/
154+
public CompletableFuture<CommentReaction> createCommentReaction(final long commentId, final CommentReactionContent reaction) {
155+
final String path = String.format(COMMENTS_REACTION_TEMPLATE, owner, repo, commentId);
156+
final String requestBody = github.json().toJsonUnchecked(ImmutableMap.of("content", reaction));
157+
return github.post(path, requestBody, CommentReaction.class);
158+
}
159+
160+
public CompletableFuture<Response> deleteCommentReaction(final long issueNumber, final long reactionId) {
161+
final String path = String.format(COMMENTS_REACTION_ID_TEMPLATE, owner, repo, issueNumber, reactionId);
162+
final String requestBody = github.json().toJsonUnchecked("");
163+
return github.delete(path, requestBody);
164+
}
140165
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*-
2+
* -\-\-
3+
* github-api
4+
* --
5+
* Copyright (C) 2016 - 2020 Spotify AB
6+
* --
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* -/-/-
19+
*/
20+
package com.spotify.github.v3.comment;
21+
22+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
23+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
24+
import com.spotify.github.GithubStyle;
25+
import com.spotify.github.UpdateTracking;
26+
import com.spotify.github.v3.User;
27+
import org.immutables.value.Value;
28+
29+
@Value.Immutable
30+
@GithubStyle
31+
@JsonSerialize(as = ImmutableComment.class)
32+
@JsonDeserialize(as = ImmutableComment.class)
33+
public interface CommentReaction extends UpdateTracking {
34+
35+
/** Reaction ID. */
36+
long id();
37+
38+
/** Reaction user. */
39+
User user();
40+
41+
/** Reaction content. */
42+
CommentReactionContent content();
43+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*-
2+
* -\-\-
3+
* github-api
4+
* --
5+
* Copyright (C) 2016 - 2020 Spotify AB
6+
* --
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* -/-/-
19+
*/
20+
package com.spotify.github.v3.comment;
21+
22+
public enum CommentReactionContent {
23+
THUMBS_UP("+1"), // 👍
24+
THUMBS_DOWN("-1"), // 👎
25+
LAUGH("laugh"), // 😄
26+
HOORAY("hooray"), // 🎉
27+
CONFUSED("confused"), // 😕
28+
HEART("heart"), // ❤️
29+
ROCKET("rocket"), // 🚀
30+
EYES("eyes"); // 👀
31+
32+
private final String reaction;
33+
34+
CommentReactionContent(final String reaction) {
35+
this.reaction = reaction;
36+
}
37+
38+
@Override
39+
public String toString() {
40+
return reaction;
41+
}
42+
}

src/test/java/com/spotify/github/v3/clients/IssueClientTest.java

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
* Licensed under the Apache License, Version 2.0 (the "License");
88
* you may not use this file except in compliance with the License.
99
* You may obtain a copy of the License at
10-
*
10+
*
1111
* http://www.apache.org/licenses/LICENSE-2.0
12-
*
12+
*
1313
* Unless required by applicable law or agreed to in writing, software
1414
* distributed under the License is distributed on an "AS IS" BASIS,
1515
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,8 +22,7 @@
2222

2323
import static com.google.common.io.Resources.getResource;
2424
import static com.spotify.github.FixtureHelper.loadFixture;
25-
import static com.spotify.github.v3.clients.IssueClient.COMMENTS_URI_NUMBER_TEMPLATE;
26-
import static com.spotify.github.v3.clients.IssueClient.ISSUES_URI_ID_TEMPLATE;
25+
import static com.spotify.github.v3.clients.IssueClient.*;
2726
import static com.spotify.github.v3.clients.MockHelper.createMockResponse;
2827
import static java.lang.String.format;
2928
import static java.nio.charset.Charset.defaultCharset;
@@ -37,15 +36,19 @@
3736
import static org.junit.jupiter.api.Assertions.assertThrows;
3837
import static org.mockito.ArgumentMatchers.anyString;
3938
import static org.mockito.ArgumentMatchers.eq;
40-
import static org.mockito.Mockito.mock;
41-
import static org.mockito.Mockito.when;
39+
import static org.mockito.Mockito.*;
4240

41+
import com.google.common.collect.ImmutableMap;
4342
import com.google.common.collect.Lists;
4443
import com.google.common.io.Resources;
4544
import com.spotify.github.async.Async;
4645
import com.spotify.github.async.AsyncPage;
4746
import com.spotify.github.jackson.Json;
47+
import com.spotify.github.v3.ImmutableUser;
4848
import com.spotify.github.v3.comment.Comment;
49+
import com.spotify.github.v3.comment.CommentReaction;
50+
import com.spotify.github.v3.comment.CommentReactionContent;
51+
import com.spotify.github.v3.comment.ImmutableCommentReaction;
4952
import com.spotify.github.v3.exceptions.RequestNotOkException;
5053
import com.spotify.github.v3.issues.Issue;
5154
import java.io.IOException;
@@ -63,7 +66,6 @@ public class IssueClientTest {
6366
private IssueClient issueClient;
6467
private Json json;
6568

66-
6769
@BeforeEach
6870
public void setUp() {
6971
json = Json.create();
@@ -94,7 +96,8 @@ public void testCommentPaginationSpliterator() throws IOException {
9496
.thenReturn(completedFuture(lastPageResponse));
9597

9698
final Iterable<AsyncPage<Comment>> pageIterator = () -> issueClient.listComments(123);
97-
final List<Comment> listComments = Async.streamFromPaginatingIterable(pageIterator).collect(toList());
99+
final List<Comment> listComments =
100+
Async.streamFromPaginatingIterable(pageIterator).collect(toList());
98101

99102
assertThat(listComments.size(), is(30));
100103
assertThat(listComments.get(0).id(), is(1345268));
@@ -161,10 +164,55 @@ public void testGetIssue() throws IOException {
161164
assertThat(issue.labels().get(0).name(), is("bug"));
162165
}
163166

167+
@Test
168+
public void testCreateIssueCommentReaction() {
169+
long commentId = 22369886;
170+
CommentReactionContent reaction = CommentReactionContent.HEART;
171+
final CompletableFuture<CommentReaction> reactionResponse =
172+
completedFuture(
173+
ImmutableCommentReaction.builder()
174+
.id(42L)
175+
.content(CommentReactionContent.HEART)
176+
.user(ImmutableUser.builder().login("octocat").build())
177+
.build());
178+
final String path = format(COMMENTS_REACTION_TEMPLATE, "someowner", "somerepo", commentId);
179+
final String requestBody = github.json().toJsonUnchecked(ImmutableMap.of("content", reaction));
180+
when(github.post(eq(path), eq(requestBody), eq(CommentReaction.class)))
181+
.thenReturn(reactionResponse);
182+
183+
final var commentReaction =
184+
issueClient.createCommentReaction(commentId, CommentReactionContent.HEART).join();
185+
186+
assertThat(commentReaction.id(), is(42L));
187+
assertNotNull(commentReaction.user());
188+
assertThat(commentReaction.user().login(), is("octocat"));
189+
assertThat(commentReaction.content().toString(), is(reaction.toString()));
190+
verify(github, times(1)).post(eq(path), eq(requestBody), eq(CommentReaction.class));
191+
}
192+
193+
@Test
194+
public void testDeleteIssueCommentReaction() {
195+
long issueNumber = 42;
196+
long reactionId = 385825;
197+
final String path =
198+
format(COMMENTS_REACTION_ID_TEMPLATE, "someowner", "somerepo", issueNumber, reactionId);
199+
final String requestBody = github.json().toJsonUnchecked("");
200+
Response mockResponse = mock(Response.class);
201+
when(mockResponse.code()).thenReturn(204);
202+
when(github.delete(eq(path), eq(requestBody))).thenReturn(completedFuture(mockResponse));
203+
204+
final var response = issueClient.deleteCommentReaction(issueNumber, reactionId).join();
205+
206+
assertThat(response.code(), is(204));
207+
assertThat(response, is(mockResponse));
208+
verify(github, times(1)).delete(eq(path), eq(requestBody));
209+
}
210+
164211
@Test
165212
public void testGetIssueNoIssue() {
166213
final String path = format(ISSUES_URI_ID_TEMPLATE, "someowner", "somerepo", 2);
167-
when(github.request(eq(path), eq(Issue.class))).thenReturn(failedFuture(new RequestNotOkException("", "", 404, "", new HashMap<>())));
214+
when(github.request(eq(path), eq(Issue.class)))
215+
.thenReturn(failedFuture(new RequestNotOkException("", "", 404, "", new HashMap<>())));
168216

169217
assertThrows(CompletionException.class, () -> issueClient.getIssue(2).join());
170218
}

0 commit comments

Comments
 (0)