Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 45 additions & 16 deletions src/main/java/com/spotify/github/v3/clients/PullRequestClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,41 @@

package com.spotify.github.v3.clients;

import static com.spotify.github.v3.clients.GitHubClient.IGNORE_RESPONSE_CONSUMER;
import static com.spotify.github.v3.clients.GitHubClient.LIST_COMMIT_TYPE_REFERENCE;
import static com.spotify.github.v3.clients.GitHubClient.LIST_PR_TYPE_REFERENCE;
import static com.spotify.github.v3.clients.GitHubClient.LIST_REVIEW_REQUEST_TYPE_REFERENCE;
import static com.spotify.github.v3.clients.GitHubClient.LIST_REVIEW_TYPE_REFERENCE;
import static java.util.Objects.isNull;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.spotify.github.async.AsyncPage;
import com.spotify.github.v3.prs.*;
import com.spotify.github.v3.prs.requests.PullRequestCreate;
import com.spotify.github.v3.prs.requests.PullRequestParameters;
import com.spotify.github.v3.prs.requests.PullRequestUpdate;
import com.spotify.github.v3.repos.CommitItem;

import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.invoke.MethodHandles;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static java.util.Objects.isNull;
import java.util.concurrent.CompletableFuture;

import javax.ws.rs.core.HttpHeaders;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.spotify.github.async.AsyncPage;
import static com.spotify.github.v3.clients.GitHubClient.IGNORE_RESPONSE_CONSUMER;
import static com.spotify.github.v3.clients.GitHubClient.LIST_COMMIT_TYPE_REFERENCE;
import static com.spotify.github.v3.clients.GitHubClient.LIST_PR_TYPE_REFERENCE;
import static com.spotify.github.v3.clients.GitHubClient.LIST_REVIEW_REQUEST_TYPE_REFERENCE;
import static com.spotify.github.v3.clients.GitHubClient.LIST_REVIEW_TYPE_REFERENCE;
import com.spotify.github.v3.prs.Comment;
import com.spotify.github.v3.prs.MergeParameters;
import com.spotify.github.v3.prs.PullRequest;
import com.spotify.github.v3.prs.PullRequestItem;
import com.spotify.github.v3.prs.RequestReviewParameters;
import com.spotify.github.v3.prs.Review;
import com.spotify.github.v3.prs.ReviewParameters;
import com.spotify.github.v3.prs.ReviewRequests;
import com.spotify.github.v3.prs.requests.PullRequestCreate;
import com.spotify.github.v3.prs.requests.PullRequestParameters;
import com.spotify.github.v3.prs.requests.PullRequestUpdate;
import com.spotify.github.v3.repos.CommitItem;

/** Pull call API client */
public class PullRequestClient {

Expand All @@ -57,6 +65,8 @@ public class PullRequestClient {
private static final String PR_REVIEWS_TEMPLATE = "/repos/%s/%s/pulls/%s/reviews";
private static final String PR_REVIEW_REQUESTS_TEMPLATE =
"/repos/%s/%s/pulls/%s/requested_reviewers";
private static final String PR_COMMENT_REPLIES_TEMPLATE =
"/repos/%s/%s/pulls/%s/comments/%s/replies";

private final GitHubClient github;
private final String owner;
Expand Down Expand Up @@ -450,4 +460,23 @@ private CompletableFuture<List<PullRequestItem>> list(final String parameterPath
log.debug("Fetching pull requests from " + path);
return github.request(path, LIST_PR_TYPE_REFERENCE);
}

/**
* Creates a reply to a pull request review comment.
*
* @param prNumber pull request number
* @param commentId the ID of the comment to reply to
* @param body the reply message
* @return the created comment
* @see "https://docs.github.com/en/rest/pulls/comments#create-a-reply-for-a-review-comment"
*/
public CompletableFuture<Comment> createCommentReply(
final long prNumber, final long commentId, final String body) {
final String path =
String.format(PR_COMMENT_REPLIES_TEMPLATE, owner, repo, prNumber, commentId);
final Map<String, String> payload = ImmutableMap.of("body", body);
final String jsonPayload = github.json().toJsonUnchecked(payload);
log.debug("Creating reply to PR comment: " + path);
return github.post(path, jsonPayload, Comment.class);
}
}
37 changes: 36 additions & 1 deletion src/main/java/com/spotify/github/v3/prs/Comment.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ public interface Comment extends UpdateTracking {
/** Base commit sha. */
@Nullable
String originalCommitId();

/** Comment author. */
@Nullable
User user();
Expand All @@ -82,6 +81,38 @@ public interface Comment extends UpdateTracking {
@Nullable
String body();

/** The ID of the comment to reply to. */
@Nullable
Long inReplyToId();

/** The author association of the comment. */
@Nullable
String authorAssociation();

/** The starting line number in the diff. */
@Nullable
Integer startLine();

/** The starting line number in the original file. */
@Nullable
Integer originalStartLine();

/** The side of the diff where the starting line is from. */
@Nullable
String startSide();

/** The line number in the diff. */
@Nullable
Integer line();

/** The line number in the original file. */
@Nullable
Integer originalLine();

/** The side of the diff where the line is from. */
@Nullable
String side();

/** Comment URL. */
@Nullable
URI htmlUrl();
Expand All @@ -98,4 +129,8 @@ public interface Comment extends UpdateTracking {
/** Node ID */
@Nullable
String nodeId();

/** Pull request review ID. */
@Nullable
Long pullRequestReviewId();
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,16 @@ public void testDeserialization() throws IOException {
assertThat(event.comment().nodeId(), is("abc234"));
assertThat(event.pullRequest().nodeId(), is("abc123"));
assertThat(event.comment().body(), is("Maybe you should use more emojji on this line."));
assertThat(event.comment().originalCommitId(), is("0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c"));
assertThat(event.comment().originalLine(), is(1));
assertThat(event.comment().originalPosition(), is(1));
assertThat(event.comment().originalStartLine(), is(1));
assertThat(event.comment().line(), is(1));
assertThat(event.comment().side(), is("RIGHT"));
assertThat(event.comment().startLine(), is(1));
assertThat(event.comment().startSide(), is("RIGHT"));
assertThat(event.comment().authorAssociation(), is("NONE"));
assertThat(event.comment().pullRequestReviewId(), is(42L));
assertThat(event.comment().inReplyToId(), is(426899381L));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -20,34 +20,47 @@

package com.spotify.github.v3.clients;

import static com.google.common.io.Resources.getResource;
import java.io.IOException;
import java.io.Reader;
import java.net.URI;
import static java.nio.charset.Charset.defaultCharset;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import org.apache.commons.io.IOUtils;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.google.common.collect.ImmutableList;
import com.google.common.io.Resources;
import static com.google.common.io.Resources.getResource;
import com.spotify.github.v3.exceptions.RequestNotOkException;
import com.spotify.github.v3.prs.Comment;
import com.spotify.github.v3.prs.ImmutableRequestReviewParameters;
import com.spotify.github.v3.prs.PullRequest;
import com.spotify.github.v3.prs.ReviewRequests;
import com.spotify.github.v3.prs.requests.ImmutablePullRequestCreate;
import com.spotify.github.v3.prs.requests.ImmutablePullRequestUpdate;
import com.spotify.github.v3.prs.requests.PullRequestCreate;
import com.spotify.github.v3.prs.requests.PullRequestUpdate;
import java.io.IOException;
import java.io.Reader;
import java.net.URI;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import okhttp3.*;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class PullRequestClientTest {

Expand Down Expand Up @@ -309,4 +322,55 @@ public void testGetDiff() throws Throwable {

assertEquals(getFixture("diff.txt"), IOUtils.toString(diffReader));
}

@Test
public void testCreateCommentReply() throws Throwable {
final Call call = mock(Call.class);
final ArgumentCaptor<Callback> capture = ArgumentCaptor.forClass(Callback.class);
doNothing().when(call).enqueue(capture.capture());

final Response response =
new Response.Builder()
.code(201)
.protocol(Protocol.HTTP_1_1)
.message("Created")
.body(
ResponseBody.create(
MediaType.get("application/json"),
getFixture("pull_request_review_comment_reply.json")))
.request(new Request.Builder().url("http://localhost/").build())
.build();

when(client.newCall(any())).thenReturn(call);

final PullRequestClient pullRequestClient =
PullRequestClient.create(github, "owner", "repo");

final String replyBody = "Thanks for the feedback!";
final CompletableFuture<Comment> result =
pullRequestClient.createCommentReply(1L, 123L, replyBody);

capture.getValue().onResponse(call, response);

Comment comment = result.get();

assertThat(comment.body(), is("Great stuff!"));
assertThat(comment.id(), is(10L));
assertThat(comment.diffHunk(), is("@@ -16,33 +16,40 @@ public class Connection : IConnection..."));
assertThat(comment.path(), is("file1.txt"));
assertThat(comment.position(), is(1));
assertThat(comment.originalPosition(), is(4));
assertThat(comment.commitId(), is("6dcb09b5b57875f334f61aebed695e2e4193db5e"));
assertThat(comment.originalCommitId(), is("9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840"));
assertThat(comment.inReplyToId(), is(426899381L));
assertThat(comment.authorAssociation(), is("NONE"));
assertThat(comment.user().login(), is("octocat"));
assertThat(comment.startLine(), is(1));
assertThat(comment.originalStartLine(), is(1));
assertThat(comment.startSide(), is("RIGHT"));
assertThat(comment.line(), is(2));
assertThat(comment.originalLine(), is(2));
assertThat(comment.side(), is("RIGHT"));
assertThat(comment.pullRequestReviewId(), is(42L));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,19 @@
"diff_hunk": "@@ -1 +1 @@\n-# public-repo",
"path": "README.md",
"position": 1,
"original_position": 1,
"commit_id": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
"original_commit_id": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c",
"original_line": 1,
"original_position": 1,
"original_start_line": 1,
"line": 1,
"side": "RIGHT",
"start_line": 1,
"start_side": "RIGHT",
"author_association": "NONE",
"pull_request_review_id": 42,
"in_reply_to_id": 426899381,
"subject_type": "line",
"user": {
"login": "baxterthehacker",
"id": 6752317,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"url": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1",
"pull_request_review_id": 42,
"id": 10,
"node_id": "MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDEw",
"diff_hunk": "@@ -16,33 +16,40 @@ public class Connection : IConnection...",
"path": "file1.txt",
"position": 1,
"original_position": 4,
"commit_id": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
"original_commit_id": "9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840",
"in_reply_to_id": 426899381,
"user": {
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"body": "Great stuff!",
"created_at": "2011-04-14T16:00:49Z",
"updated_at": "2011-04-14T16:00:49Z",
"html_url": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1",
"pull_request_url": "https://api.github.com/repos/octocat/Hello-World/pulls/1",
"author_association": "NONE",
"_links": {
"self": {
"href": "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1"
},
"html": {
"href": "https://github.com/octocat/Hello-World/pull/1#discussion-diff-1"
},
"pull_request": {
"href": "https://api.github.com/repos/octocat/Hello-World/pulls/1"
}
},
"start_line": 1,
"original_start_line": 1,
"start_side": "RIGHT",
"line": 2,
"original_line": 2,
"side": "RIGHT"
}