Skip to content

Commit 56c95b3

Browse files
javoireclaude
andauthored
feat: add issue reaction methods and fix comment reaction template (#250)
* feat: add issue reaction methods and fix comment reaction template - Add createIssueReaction() and deleteIssueReaction() methods - Fix COMMENTS_REACTION_ID_TEMPLATE to use correct comment endpoint - Add comprehensive tests for issue reaction functionality - Update deleteCommentReaction method signature to use commentId 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * use the right template constant in test --------- Co-authored-by: Claude <[email protected]>
1 parent cce9012 commit 56c95b3

File tree

2 files changed

+83
-8
lines changed

2 files changed

+83
-8
lines changed

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

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ public class IssueClient {
4343
static final String COMMENTS_URI_TEMPLATE = "/repos/%s/%s/issues/comments";
4444
static final String COMMENTS_URI_ID_TEMPLATE = "/repos/%s/%s/issues/comments/%s";
4545
static final String COMMENTS_REACTION_TEMPLATE = "/repos/%s/%s/issues/comments/%s/reactions";
46-
static final String COMMENTS_REACTION_ID_TEMPLATE = "/repos/%s/%s/issues/%s/reactions/%s";
46+
static final String COMMENTS_REACTION_ID_TEMPLATE = "/repos/%s/%s/issues/comments/%s/reactions/%s";
47+
static final String ISSUES_REACTION_TEMPLATE = "/repos/%s/%s/issues/%s/reactions";
48+
static final String ISSUES_REACTION_ID_TEMPLATE = "/repos/%s/%s/issues/%s/reactions/%s";
4749
static final String ISSUES_URI_ID_TEMPLATE = "/repos/%s/%s/issues/%s";
4850
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
4951

@@ -53,7 +55,6 @@ public class IssueClient {
5355

5456
/**
5557
* Constructs an IssueClient.
56-
*
5758
* @param github the GitHub client
5859
* @param owner the repository owner
5960
* @param repo the repository name
@@ -260,14 +261,14 @@ public CompletableFuture<CommentReaction> createCommentReaction(
260261
* href="https://docs.github.com/en/rest/reactions/reactions?apiVersion=2022-11-28#delete-an-issue-comment-reaction">List
261262
* reactions for an issue comment</a>
262263
*
263-
* @param issueNumber the issue number
264+
* @param commentId the comment id
264265
* @param reactionId the reaction id
265266
* @return a CompletableFuture containing the HTTP response
266267
*/
267268
public CompletableFuture<HttpResponse> deleteCommentReaction(
268-
final long issueNumber, final long reactionId) {
269+
final long commentId, final long reactionId) {
269270
final String path =
270-
String.format(COMMENTS_REACTION_ID_TEMPLATE, owner, repo, issueNumber, reactionId);
271+
String.format(COMMENTS_REACTION_ID_TEMPLATE, owner, repo, commentId, reactionId);
271272
return github.delete(path);
272273
}
273274

@@ -284,4 +285,35 @@ public GithubPageIterator<CommentReaction> listCommentReaction(final long commen
284285
return new GithubPageIterator<>(
285286
new GithubPage<>(github, path, LIST_COMMENT_REACTION_TYPE_REFERENCE));
286287
}
288+
289+
/**
290+
* Creates a reaction on an issue.
291+
*
292+
* @param issueNumber the issue number
293+
* @param reaction the reaction content
294+
* @return a CompletableFuture containing the created reaction
295+
*/
296+
public CompletableFuture<CommentReaction> createIssueReaction(
297+
final long issueNumber, final CommentReactionContent reaction) {
298+
final String path = String.format(ISSUES_REACTION_TEMPLATE, owner, repo, issueNumber);
299+
final String requestBody =
300+
github.json().toJsonUnchecked(ImmutableMap.of("content", reaction.toString()));
301+
return github.post(path, requestBody, CommentReaction.class);
302+
}
303+
304+
/**
305+
* Deletes a reaction on an issue. See <a
306+
* href="https://docs.github.com/en/rest/reactions/reactions?apiVersion=2022-11-28#delete-an-issue-reaction">Delete
307+
* an issue reaction</a>
308+
*
309+
* @param issueNumber the issue number
310+
* @param reactionId the reaction id
311+
* @return a CompletableFuture containing the HTTP response
312+
*/
313+
public CompletableFuture<HttpResponse> deleteIssueReaction(
314+
final long issueNumber, final long reactionId) {
315+
final String path =
316+
String.format(ISSUES_REACTION_ID_TEMPLATE, owner, repo, issueNumber, reactionId);
317+
return github.delete(path);
318+
}
287319
}

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

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,15 +217,15 @@ public void testCreateIssueCommentReaction(CommentReactionContent reaction) {
217217

218218
@Test
219219
public void testDeleteIssueCommentReaction() {
220-
long issueNumber = 42;
220+
long commentId = 42;
221221
long reactionId = 385825;
222222
final String path =
223-
format(COMMENTS_REACTION_ID_TEMPLATE, "someowner", "somerepo", issueNumber, reactionId);
223+
format(COMMENTS_REACTION_ID_TEMPLATE, "someowner", "somerepo", commentId, reactionId);
224224
HttpResponse mockResponse = mock(HttpResponse.class);
225225
when(mockResponse.statusCode()).thenReturn(204);
226226
when(github.delete(eq(path))).thenReturn(completedFuture(mockResponse));
227227

228-
final var response = issueClient.deleteCommentReaction(issueNumber, reactionId).join();
228+
final var response = issueClient.deleteCommentReaction(commentId, reactionId).join();
229229

230230
assertThat(response.statusCode(), is(204));
231231
assertThat(response, is(mockResponse));
@@ -271,6 +271,49 @@ public void testListIssueCommentReaction() throws IOException {
271271
verify(github, atLeastOnce()).request(eq(path));
272272
}
273273

274+
@ParameterizedTest
275+
@EnumSource(CommentReactionContent.class)
276+
public void testCreateIssueReaction(CommentReactionContent reaction) {
277+
long issueNumber = 42;
278+
final CompletableFuture<CommentReaction> reactionResponse =
279+
completedFuture(
280+
ImmutableCommentReaction.builder()
281+
.id(123L)
282+
.content(reaction)
283+
.user(ImmutableUser.builder().login("octocat").build())
284+
.build());
285+
final String path = format(ISSUES_REACTION_TEMPLATE, "someowner", "somerepo", issueNumber);
286+
final String requestBody =
287+
github.json().toJsonUnchecked(ImmutableMap.of("content", reaction.toString()));
288+
when(github.post(eq(path), eq(requestBody), eq(CommentReaction.class)))
289+
.thenReturn(reactionResponse);
290+
291+
final var issueReaction = issueClient.createIssueReaction(issueNumber, reaction).join();
292+
293+
assertThat(issueReaction.id(), is(123L));
294+
assertNotNull(issueReaction.user());
295+
assertThat(issueReaction.user().login(), is("octocat"));
296+
assertThat(issueReaction.content().toString(), is(reaction.toString()));
297+
verify(github, times(1)).post(eq(path), eq(requestBody), eq(CommentReaction.class));
298+
}
299+
300+
@Test
301+
public void testDeleteIssueReaction() {
302+
long issueNumber = 42;
303+
long reactionId = 385825;
304+
final String path =
305+
format(ISSUES_REACTION_ID_TEMPLATE, "someowner", "somerepo", issueNumber, reactionId);
306+
HttpResponse mockResponse = mock(HttpResponse.class);
307+
when(mockResponse.statusCode()).thenReturn(204);
308+
when(github.delete(eq(path))).thenReturn(completedFuture(mockResponse));
309+
310+
final var response = issueClient.deleteIssueReaction(issueNumber, reactionId).join();
311+
312+
assertThat(response.statusCode(), is(204));
313+
assertThat(response, is(mockResponse));
314+
verify(github, times(1)).delete(eq(path));
315+
}
316+
274317
@Test
275318
public void testGetIssueNoIssue() {
276319
final String path = format(ISSUES_URI_ID_TEMPLATE, "someowner", "somerepo", 2);

0 commit comments

Comments
 (0)