Skip to content

Commit f6e6a77

Browse files
authored
fix: GHPullRequestReviewComment.getLine() returning -1 (#2188)
* fix: GHPullRequestReviewComment.getLine() returning -1 * chore: address review comments * fix: add ReviewComment reflection/serialization * fix: cover more methods in thest * fix: cover more methods in test * fix: remove getUser method call due to missing stub
1 parent ec6a822 commit f6e6a77

10 files changed

Lines changed: 480 additions & 12 deletions

File tree

src/main/java/org/kohsuke/github/GHPullRequest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,13 @@ public PagedIterable<GHPullRequestFileDetail> listFiles() {
530530
/**
531531
* Obtains all the review comments associated with this pull request.
532532
*
533+
* <p>
534+
* Unlike {@link GHPullRequestReview#listReviewComments()}, this method returns full
535+
* {@link GHPullRequestReviewComment} objects including line-related fields such as
536+
* {@link GHPullRequestReviewComment#getLine() line}, {@link GHPullRequestReviewComment#getSide() side}, etc.
537+
*
533538
* @return the paged iterable
539+
* @see GHPullRequestReview#listReviewComments()
534540
*/
535541
public PagedIterable<GHPullRequestReviewComment> listReviewComments() {
536542
return root().createRequest()

src/main/java/org/kohsuke/github/GHPullRequestReview.java

Lines changed: 194 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,190 @@
4343
@SuppressFBWarnings(value = { "UWF_UNWRITTEN_FIELD" }, justification = "JSON API")
4444
public class GHPullRequestReview extends GHObject {
4545

46+
/**
47+
* Represents a review comment as returned by the review comments endpoint. This is a limited view that does not
48+
* include line-related fields such as {@code line}, {@code originalLine}, {@code side}, etc.
49+
*
50+
* <p>
51+
* To obtain the full {@link GHPullRequestReviewComment} with all fields, call
52+
* {@link #readPullRequestReviewComment()}.
53+
*
54+
* @see GHPullRequest#listReviewComments()
55+
*/
56+
@SuppressFBWarnings(value = { "UWF_UNWRITTEN_FIELD" }, justification = "JSON API")
57+
public static class ReviewComment extends GHObject {
58+
59+
private GHCommentAuthorAssociation authorAssociation;
60+
private String body;
61+
private String commitId;
62+
private String diffHunk;
63+
private String htmlUrl;
64+
private String originalCommitId;
65+
private int originalPosition = -1;
66+
private String path;
67+
private int position = -1;
68+
private Long pullRequestReviewId = -1L;
69+
private String pullRequestUrl;
70+
private GHPullRequestReviewCommentReactions reactions;
71+
private GHUser user;
72+
73+
GHPullRequest owner;
74+
75+
/**
76+
* Create default ReviewComment instance
77+
*/
78+
public ReviewComment() {
79+
}
80+
81+
/**
82+
* Gets the author association to the project.
83+
*
84+
* @return the author association to the project
85+
*/
86+
public GHCommentAuthorAssociation getAuthorAssociation() {
87+
return authorAssociation;
88+
}
89+
90+
/**
91+
* The comment itself.
92+
*
93+
* @return the body
94+
*/
95+
public String getBody() {
96+
return body;
97+
}
98+
99+
/**
100+
* Gets commit id.
101+
*
102+
* @return the commit id
103+
*/
104+
public String getCommitId() {
105+
return commitId;
106+
}
107+
108+
/**
109+
* Gets diff hunk.
110+
*
111+
* @return the diff hunk
112+
*/
113+
public String getDiffHunk() {
114+
return diffHunk;
115+
}
116+
117+
/**
118+
* Gets the html url.
119+
*
120+
* @return the html url
121+
*/
122+
public URL getHtmlUrl() {
123+
return GitHubClient.parseURL(htmlUrl);
124+
}
125+
126+
/**
127+
* Gets commit id.
128+
*
129+
* @return the original commit id
130+
*/
131+
public String getOriginalCommitId() {
132+
return originalCommitId;
133+
}
134+
135+
/**
136+
* Gets original position.
137+
*
138+
* @return the original position
139+
*/
140+
public int getOriginalPosition() {
141+
return originalPosition;
142+
}
143+
144+
/**
145+
* Gets path.
146+
*
147+
* @return the path
148+
*/
149+
public String getPath() {
150+
return path;
151+
}
152+
153+
/**
154+
* Gets position.
155+
*
156+
* @return the position
157+
*/
158+
public int getPosition() {
159+
return position;
160+
}
161+
162+
/**
163+
* Gets The ID of the pull request review to which the comment belongs.
164+
*
165+
* @return {@link Long} the ID of the pull request review
166+
*/
167+
public Long getPullRequestReviewId() {
168+
return pullRequestReviewId != null ? pullRequestReviewId : -1;
169+
}
170+
171+
/**
172+
* Gets URL for the pull request that the review comment belongs to.
173+
*
174+
* @return {@link URL} the URL of the pull request
175+
*/
176+
public URL getPullRequestUrl() {
177+
return GitHubClient.parseURL(pullRequestUrl);
178+
}
179+
180+
/**
181+
* Gets the Reaction Rollup.
182+
*
183+
* @return {@link GHPullRequestReviewCommentReactions} the reaction rollup
184+
*/
185+
public GHPullRequestReviewCommentReactions getReactions() {
186+
return reactions;
187+
}
188+
189+
/**
190+
* Gets the user who posted this comment.
191+
*
192+
* @return the user
193+
* @throws IOException
194+
* the io exception
195+
*/
196+
public GHUser getUser() throws IOException {
197+
return owner.root().getUser(user.getLogin());
198+
}
199+
200+
/**
201+
* Fetches the full {@link GHPullRequestReviewComment} from the API, which includes all fields such as
202+
* {@link GHPullRequestReviewComment#getLine() line}, {@link GHPullRequestReviewComment#getOriginalLine()
203+
* originalLine}, {@link GHPullRequestReviewComment#getSide() side}, etc.
204+
*
205+
* @return the full {@link GHPullRequestReviewComment}
206+
* @throws IOException
207+
* if an I/O error occurs
208+
*/
209+
public GHPullRequestReviewComment readPullRequestReviewComment() throws IOException {
210+
return owner.root()
211+
.createRequest()
212+
.withUrlPath("/repos/" + owner.getRepository().getFullName() + "/pulls/comments/" + getId())
213+
.fetch(GHPullRequestReviewComment.class)
214+
.wrapUp(owner);
215+
}
216+
217+
/**
218+
* Wrap up.
219+
*
220+
* @param owner
221+
* the owner
222+
* @return the review comment
223+
*/
224+
ReviewComment wrapUp(GHPullRequest owner) {
225+
this.owner = owner;
226+
return this;
227+
}
228+
}
229+
46230
private String body;
47231

48232
private String commitId;
@@ -171,13 +355,20 @@ public GHUser getUser() throws IOException {
171355
/**
172356
* Obtains all the review comments associated with this pull request review.
173357
*
174-
* @return the paged iterable
358+
* <p>
359+
* The GitHub API endpoint used by this method returns a limited set of fields. To obtain full comment data
360+
* including line numbers, use {@link ReviewComment#readPullRequestReviewComment()} on individual comments, or use
361+
* {@link GHPullRequest#listReviewComments()} instead.
362+
*
363+
* @return the paged iterable of {@link ReviewComment} objects
364+
* @see GHPullRequest#listReviewComments()
365+
* @see ReviewComment#readPullRequestReviewComment()
175366
*/
176-
public PagedIterable<GHPullRequestReviewComment> listReviewComments() {
367+
public PagedIterable<ReviewComment> listReviewComments() {
177368
return owner.root()
178369
.createRequest()
179370
.withUrlPath(getApiRoute() + "/comments")
180-
.toIterable(GHPullRequestReviewComment[].class, item -> item.wrapUp(owner));
371+
.toIterable(ReviewComment[].class, item -> item.wrapUp(owner));
181372
}
182373

183374
/**

src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,13 @@ public long getInReplyToId() {
218218
/**
219219
* Gets The line of the blob to which the comment applies. The last line of the range for a multi-line comment.
220220
*
221-
* @return the line to which the comment applies
221+
* <p>
222+
* This field is not available on {@link GHPullRequestReview.ReviewComment} objects returned by
223+
* {@link GHPullRequestReview#listReviewComments()}. Use
224+
* {@link GHPullRequestReview.ReviewComment#readPullRequestReviewComment()} or
225+
* {@link GHPullRequest#listReviewComments()} to obtain this value.
226+
*
227+
* @return the line to which the comment applies, or -1 if not available
222228
*/
223229
public int getLine() {
224230
return line;
@@ -236,7 +242,13 @@ public String getOriginalCommitId() {
236242
/**
237243
* Gets The line of the blob to which the comment applies. The last line of the range for a multi-line comment.
238244
*
239-
* @return the line to which the comment applies
245+
* <p>
246+
* This field is not available on {@link GHPullRequestReview.ReviewComment} objects returned by
247+
* {@link GHPullRequestReview#listReviewComments()}. Use
248+
* {@link GHPullRequestReview.ReviewComment#readPullRequestReviewComment()} or
249+
* {@link GHPullRequest#listReviewComments()} to obtain this value.
250+
*
251+
* @return the line to which the comment applies, or -1 if not available
240252
*/
241253
public int getOriginalLine() {
242254
return originalLine;
@@ -254,7 +266,13 @@ public int getOriginalPosition() {
254266
/**
255267
* Gets The first line of the range for a multi-line comment.
256268
*
257-
* @return the original start line
269+
* <p>
270+
* This field is not available on {@link GHPullRequestReview.ReviewComment} objects returned by
271+
* {@link GHPullRequestReview#listReviewComments()}. Use
272+
* {@link GHPullRequestReview.ReviewComment#readPullRequestReviewComment()} or
273+
* {@link GHPullRequest#listReviewComments()} to obtain this value.
274+
*
275+
* @return the original start line, or -1 if not available or not a multi-line comment
258276
*/
259277
public int getOriginalStartLine() {
260278
return originalStartLine != null ? originalStartLine : -1;
@@ -318,9 +336,15 @@ public GHPullRequestReviewCommentReactions getReactions() {
318336

319337
/**
320338
* Gets The side of the diff to which the comment applies. The side of the last line of the range for a multi-line
321-
* comment
339+
* comment.
322340
*
323-
* @return {@link Side} the side if the diff to which the comment applies
341+
* <p>
342+
* This field is not available on {@link GHPullRequestReview.ReviewComment} objects returned by
343+
* {@link GHPullRequestReview#listReviewComments()}. Use
344+
* {@link GHPullRequestReview.ReviewComment#readPullRequestReviewComment()} or
345+
* {@link GHPullRequest#listReviewComments()} to obtain this value.
346+
*
347+
* @return {@link Side} the side of the diff to which the comment applies, or {@link Side#UNKNOWN} if not available
324348
*/
325349
public Side getSide() {
326350
return Side.from(side);
@@ -329,7 +353,13 @@ public Side getSide() {
329353
/**
330354
* Gets The first line of the range for a multi-line comment.
331355
*
332-
* @return the start line
356+
* <p>
357+
* This field is not available on {@link GHPullRequestReview.ReviewComment} objects returned by
358+
* {@link GHPullRequestReview#listReviewComments()}. Use
359+
* {@link GHPullRequestReview.ReviewComment#readPullRequestReviewComment()} or
360+
* {@link GHPullRequest#listReviewComments()} to obtain this value.
361+
*
362+
* @return the start line, or -1 if not available or not a multi-line comment
333363
*/
334364
public int getStartLine() {
335365
return startLine != null ? startLine : -1;
@@ -338,7 +368,13 @@ public int getStartLine() {
338368
/**
339369
* Gets The side of the first line of the range for a multi-line comment.
340370
*
341-
* @return {@link Side} the side of the first line
371+
* <p>
372+
* This field is not available on {@link GHPullRequestReview.ReviewComment} objects returned by
373+
* {@link GHPullRequestReview#listReviewComments()}. Use
374+
* {@link GHPullRequestReview.ReviewComment#readPullRequestReviewComment()} or
375+
* {@link GHPullRequest#listReviewComments()} to obtain this value.
376+
*
377+
* @return {@link Side} the side of the first line, or {@link Side#UNKNOWN} if not available
342378
*/
343379
public Side getStartSide() {
344380
return Side.from(startSide);

src/main/resources/META-INF/native-image/org.kohsuke/github-api/reflect-config.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4334,6 +4334,21 @@
43344334
"allPublicClasses": true,
43354335
"allDeclaredClasses": true
43364336
},
4337+
{
4338+
"name": "org.kohsuke.github.GHPullRequestReview$ReviewComment",
4339+
"allPublicFields": true,
4340+
"allDeclaredFields": true,
4341+
"queryAllPublicConstructors": true,
4342+
"queryAllDeclaredConstructors": true,
4343+
"allPublicConstructors": true,
4344+
"allDeclaredConstructors": true,
4345+
"queryAllPublicMethods": true,
4346+
"queryAllDeclaredMethods": true,
4347+
"allPublicMethods": true,
4348+
"allDeclaredMethods": true,
4349+
"allPublicClasses": true,
4350+
"allDeclaredClasses": true
4351+
},
43374352
{
43384353
"name": "org.kohsuke.github.GHPullRequestReviewBuilder",
43394354
"allPublicFields": true,

src/main/resources/META-INF/native-image/org.kohsuke/github-api/serialization-config.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,9 @@
869869
{
870870
"name": "org.kohsuke.github.GHPullRequestReview"
871871
},
872+
{
873+
"name": "org.kohsuke.github.GHPullRequestReview$ReviewComment"
874+
},
872875
{
873876
"name": "org.kohsuke.github.GHPullRequestReviewBuilder"
874877
},

src/test/java/org/kohsuke/github/GHPullRequestTest.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -739,16 +739,32 @@ public void pullRequestReviews() throws Exception {
739739
assertThat(review.getBody(), is("Some draft review"));
740740
assertThat(review.getCommitId(), notNullValue());
741741
draftReview.submit("Some review comment", GHPullRequestReviewEvent.COMMENT);
742-
List<GHPullRequestReviewComment> comments = review.listReviewComments().toList();
742+
List<GHPullRequestReview.ReviewComment> comments = review.listReviewComments().toList();
743743
assertThat(comments.size(), equalTo(3));
744-
GHPullRequestReviewComment comment = comments.get(0);
744+
GHPullRequestReview.ReviewComment comment = comments.get(0);
745745
assertThat(comment.getBody(), equalTo("Some niggle"));
746+
assertThat(comment.getPath(), equalTo("README.md"));
747+
assertThat(comment.getCommitId(), equalTo("07374fe73aff1c2024a8d4114b32406c7a8e89b7"));
748+
assertThat(comment.getOriginalCommitId(), equalTo("07374fe73aff1c2024a8d4114b32406c7a8e89b7"));
749+
assertThat(comment.getDiffHunk(), notNullValue());
750+
assertThat(comment.getAuthorAssociation(), equalTo(GHCommentAuthorAssociation.MEMBER));
751+
assertThat(comment.getOriginalPosition(), equalTo(1));
752+
assertThat(comment.getHtmlUrl(), notNullValue());
753+
assertThat(comment.getPullRequestReviewId(), equalTo(2121304234L));
754+
assertThat(comment.getPullRequestUrl(), notNullValue());
755+
assertThat(comment.getReactions(), notNullValue());
746756
comment = comments.get(1);
747757
assertThat(comment.getBody(), equalTo("A single line comment"));
748758
assertThat(comment.getPosition(), equalTo(4));
749759
comment = comments.get(2);
750760
assertThat(comment.getBody(), equalTo("A multiline comment"));
751761
assertThat(comment.getPosition(), equalTo(5));
762+
763+
// Verify that readPullRequestReviewComment() fetches the full comment with line data
764+
GHPullRequestReviewComment fullComment = comments.get(0).readPullRequestReviewComment();
765+
assertThat(fullComment.getBody(), equalTo("Some niggle"));
766+
assertThat(fullComment.getLine(), equalTo(1));
767+
752768
draftReview = p.createReview().body("Some new review").comment("Some niggle", "README.md", 1).create();
753769
draftReview.delete();
754770
}

0 commit comments

Comments
 (0)