Skip to content
Open
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
10 changes: 10 additions & 0 deletions src/main/java/org/kohsuke/github/GHPullRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,17 @@ public PagedIterable<GHPullRequestFileDetail> listFiles() {
/**
* Obtains all the review comments associated with this pull request.
*
* <p>
* This method uses the pull request comments endpoint which returns complete comment data including
* {@link GHPullRequestReviewComment#getLine() line}, {@link GHPullRequestReviewComment#getOriginalLine()
* originalLine}, {@link GHPullRequestReviewComment#getSide() side}, and other position-related fields.
*
* <p>
* If you need line number information, prefer this method over {@link GHPullRequestReview#listReviewComments()},
* which uses a different API endpoint that does not return line-related fields.
*
* @return the paged iterable
* @see GHPullRequestReview#listReviewComments()
*/
public PagedIterable<GHPullRequestReviewComment> listReviewComments() {
return root().createRequest()
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/kohsuke/github/GHPullRequestReview.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,19 @@ public GHUser getUser() throws IOException {
/**
* Obtains all the review comments associated with this pull request review.
*
* <p>
* <strong>Note:</strong> The GitHub API endpoint used by this method does not return line-related fields such as
* {@link GHPullRequestReviewComment#getLine() line}, {@link GHPullRequestReviewComment#getOriginalLine()
* originalLine}, {@link GHPullRequestReviewComment#getSide() side},
* {@link GHPullRequestReviewComment#getStartLine() startLine}, etc. These fields will return their default values
* (-1 or UNKNOWN).
*
* <p>
* If you need line number information, use {@link GHPullRequest#listReviewComments()} instead and filter by
* {@link GHPullRequestReviewComment#getPullRequestReviewId()} if needed.
*
* @return the paged iterable
* @see GHPullRequest#listReviewComments()
*/
public PagedIterable<GHPullRequestReviewComment> listReviewComments() {
return owner.root()
Expand Down
68 changes: 60 additions & 8 deletions src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
* @see GHPullRequest#createReviewComment(String, String, String, int) GHPullRequest#createReviewComment(String, String,
* String, int)
*/
public class GHPullRequestReviewComment extends GHObject implements Reactable {
public class GHPullRequestReviewComment extends GHObject implements Reactable, Refreshable {

/**
* The side of the diff to which the comment applies
Expand Down Expand Up @@ -218,7 +218,13 @@ public long getInReplyToId() {
/**
* Gets The line of the blob to which the comment applies. The last line of the range for a multi-line comment.
*
* @return the line to which the comment applies
* <p>
* <strong>Note:</strong> This field is only populated when comments are retrieved via
* {@link GHPullRequest#listReviewComments()}. When retrieved via {@link GHPullRequestReview#listReviewComments()},
* this method returns -1 due to limitations in the GitHub API.
*
* @return the line to which the comment applies, or -1 if not available
* @see GHPullRequest#listReviewComments()
*/
public int getLine() {
return line;
Expand All @@ -236,7 +242,13 @@ public String getOriginalCommitId() {
/**
* Gets The line of the blob to which the comment applies. The last line of the range for a multi-line comment.
*
* @return the line to which the comment applies
* <p>
* <strong>Note:</strong> This field is only populated when comments are retrieved via
* {@link GHPullRequest#listReviewComments()}. When retrieved via {@link GHPullRequestReview#listReviewComments()},
* this method returns -1 due to limitations in the GitHub API.
*
* @return the line to which the comment applies, or -1 if not available
* @see GHPullRequest#listReviewComments()
*/
public int getOriginalLine() {
return originalLine;
Expand All @@ -254,7 +266,13 @@ public int getOriginalPosition() {
/**
* Gets The first line of the range for a multi-line comment.
*
* @return the original start line
* <p>
* <strong>Note:</strong> This field is only populated when comments are retrieved via
* {@link GHPullRequest#listReviewComments()}. When retrieved via {@link GHPullRequestReview#listReviewComments()},
* this method returns -1 due to limitations in the GitHub API.
*
* @return the original start line, or -1 if not available or not a multi-line comment
* @see GHPullRequest#listReviewComments()
*/
public int getOriginalStartLine() {
return originalStartLine != null ? originalStartLine : -1;
Expand Down Expand Up @@ -318,9 +336,15 @@ public GHPullRequestReviewCommentReactions getReactions() {

/**
* Gets The side of the diff to which the comment applies. The side of the last line of the range for a multi-line
* comment
* comment.
*
* <p>
* <strong>Note:</strong> This field is only populated when comments are retrieved via
* {@link GHPullRequest#listReviewComments()}. When retrieved via {@link GHPullRequestReview#listReviewComments()},
* this method returns {@link Side#UNKNOWN} due to limitations in the GitHub API.
*
* @return {@link Side} the side if the diff to which the comment applies
* @return {@link Side} the side of the diff to which the comment applies, or {@link Side#UNKNOWN} if not available
* @see GHPullRequest#listReviewComments()
*/
public Side getSide() {
return Side.from(side);
Expand All @@ -329,7 +353,13 @@ public Side getSide() {
/**
* Gets The first line of the range for a multi-line comment.
*
* @return the start line
* <p>
* <strong>Note:</strong> This field is only populated when comments are retrieved via
* {@link GHPullRequest#listReviewComments()}. When retrieved via {@link GHPullRequestReview#listReviewComments()},
* this method returns -1 due to limitations in the GitHub API.
*
* @return the start line, or -1 if not available or not a multi-line comment
* @see GHPullRequest#listReviewComments()
*/
public int getStartLine() {
return startLine != null ? startLine : -1;
Expand All @@ -338,7 +368,13 @@ public int getStartLine() {
/**
* Gets The side of the first line of the range for a multi-line comment.
*
* @return {@link Side} the side of the first line
* <p>
* <strong>Note:</strong> This field is only populated when comments are retrieved via
* {@link GHPullRequest#listReviewComments()}. When retrieved via {@link GHPullRequestReview#listReviewComments()},
* this method returns {@link Side#UNKNOWN} due to limitations in the GitHub API.
*
* @return {@link Side} the side of the first line, or {@link Side#UNKNOWN} if not available
* @see GHPullRequest#listReviewComments()
*/
public Side getStartSide() {
return Side.from(startSide);
Expand Down Expand Up @@ -367,6 +403,22 @@ public PagedIterable<GHReaction> listReactions() {
.toIterable(GHReaction[].class, item -> owner.root());
}

/**
* Refreshes this comment by fetching the full data from the API.
*
* <p>
* This is useful when the comment was obtained via {@link GHPullRequestReview#listReviewComments()}, which uses a
* GitHub API endpoint that does not return line-related fields. After calling this method, fields like
* {@link #getLine()}, {@link #getOriginalLine()}, {@link #getSide()}, etc. will return their actual values.
*
* @throws IOException
* if an I/O error occurs
* @see GHPullRequest#listReviewComments()
*/
public void refresh() throws IOException {
owner.root().createRequest().withUrlPath(getApiRoute()).fetchInto(this).wrapUp(owner);
}

/**
* Create a new comment that replies to this comment.
*
Expand Down
9 changes: 9 additions & 0 deletions src/test/java/org/kohsuke/github/GHPullRequestTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,15 @@ public void pullRequestReviews() throws Exception {
assertThat(comments.size(), equalTo(3));
GHPullRequestReviewComment comment = comments.get(0);
assertThat(comment.getBody(), equalTo("Some niggle"));

// Verify that line is not available when fetched via review.listReviewComments()
// due to GitHub API limitation (the review comments endpoint doesn't return line field)
assertThat(comment.getLine(), equalTo(-1));

// After refresh(), line information should be available
comment.refresh();
assertThat(comment.getLine(), equalTo(1));

comment = comments.get(1);
assertThat(comment.getBody(), equalTo("A single line comment"));
assertThat(comment.getPosition(), equalTo(4));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"login": "Anonycoders",
"id": 40047636,
"node_id": "MDQ6VXNlcjQwMDQ3NjM2",
"avatar_url": "https://avatars.githubusercontent.com/u/40047636?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/Anonycoders",
"html_url": "https://github.com/Anonycoders",
"followers_url": "https://api.github.com/users/Anonycoders/followers",
"following_url": "https://api.github.com/users/Anonycoders/following{/other_user}",
"gists_url": "https://api.github.com/users/Anonycoders/gists{/gist_id}",
"starred_url": "https://api.github.com/users/Anonycoders/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/Anonycoders/subscriptions",
"organizations_url": "https://api.github.com/users/Anonycoders/orgs",
"repos_url": "https://api.github.com/users/Anonycoders/repos",
"events_url": "https://api.github.com/users/Anonycoders/events{/privacy}",
"received_events_url": "https://api.github.com/users/Anonycoders/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false,
"name": "Sorena Sarabadani",
"company": "@Adevinta",
"blog": "",
"location": "Berlin, Germany",
"email": "sorena.sarabadani@gmail.com",
"hireable": null,
"bio": "Ex-Shopifyer - Adevinta/Kleinanzeigen",
"twitter_username": "sorena_s",
"notification_email": "sorena.sarabadani@gmail.com",
"public_repos": 12,
"public_gists": 0,
"followers": 38,
"following": 4,
"created_at": "2018-06-08T02:07:15Z",
"updated_at": "2026-01-24T22:07:12Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"url": "https://api.github.com/repos/hub4j-test-org/github-api/pulls/comments/1641771497",
"pull_request_review_id": 2121304234,
"id": 1641771497,
"node_id": "PRRC_kwDODFTdCc5h23Hp",
"diff_hunk": "@@ -1,3 +1,4 @@\n-Java API for GitHub",
"path": "README.md",
"commit_id": "07374fe73aff1c2024a8d4114b32406c7a8e89b7",
"original_commit_id": "07374fe73aff1c2024a8d4114b32406c7a8e89b7",
"user": {
"login": "maximevw",
"id": 48218208,
"node_id": "MDQ6VXNlcjQ4MjE4MjA4",
"avatar_url": "https://avatars.githubusercontent.com/u/48218208?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/maximevw",
"html_url": "https://github.com/maximevw",
"followers_url": "https://api.github.com/users/maximevw/followers",
"following_url": "https://api.github.com/users/maximevw/following{/other_user}",
"gists_url": "https://api.github.com/users/maximevw/gists{/gist_id}",
"starred_url": "https://api.github.com/users/maximevw/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/maximevw/subscriptions",
"organizations_url": "https://api.github.com/users/maximevw/orgs",
"repos_url": "https://api.github.com/users/maximevw/repos",
"events_url": "https://api.github.com/users/maximevw/events{/privacy}",
"received_events_url": "https://api.github.com/users/maximevw/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"body": "Some niggle",
"created_at": "2024-06-16T09:55:53Z",
"updated_at": "2024-06-16T09:55:55Z",
"html_url": "https://github.com/hub4j-test-org/github-api/pull/482#discussion_r1641771497",
"pull_request_url": "https://api.github.com/repos/hub4j-test-org/github-api/pulls/482",
"_links": {
"self": {
"href": "https://api.github.com/repos/hub4j-test-org/github-api/pulls/comments/1641771497"
},
"html": {
"href": "https://github.com/hub4j-test-org/github-api/pull/482#discussion_r1641771497"
},
"pull_request": {
"href": "https://api.github.com/repos/hub4j-test-org/github-api/pulls/482"
}
},
"reactions": {
"url": "https://api.github.com/repos/hub4j-test-org/github-api/pulls/comments/1641771497/reactions",
"total_count": 0,
"+1": 0,
"-1": 0,
"laugh": 0,
"hooray": 0,
"confused": 0,
"heart": 0,
"rocket": 0,
"eyes": 0
},
"start_line": null,
"original_start_line": null,
"start_side": null,
"line": 1,
"original_line": 1,
"side": "LEFT",
"author_association": "MEMBER",
"original_position": 1,
"position": 1,
"subject_type": "line"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"id": "249d36bd-a54d-4106-a62f-f86c4f834d34",
"name": "user",
"request": {
"url": "/user",
"method": "GET",
"headers": {
"Accept": {
"equalTo": "application/vnd.github+json"
}
}
},
"response": {
"status": 200,
"bodyFileName": "12-user.json",
"headers": {
"Date": "Mon, 26 Jan 2026 22:10:52 GMT",
"Content-Type": "application/json; charset=utf-8",
"Cache-Control": "private, max-age=60, s-maxage=60",
"Vary": "Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With",
"ETag": "W/\"15d7e1ad92a3639b979fc55254902e63ee0bfa5c8f6766990bf989044d491ce1\"",
"Last-Modified": "Sat, 24 Jan 2026 22:07:12 GMT",
"X-OAuth-Scopes": "repo",
"X-Accepted-OAuth-Scopes": "",
"github-authentication-token-expiration": "2026-02-19 19:55:13 UTC",
"X-GitHub-Media-Type": "github.v3; format=json",
"x-github-api-version-selected": "2022-11-28",
"Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset",
"Access-Control-Allow-Origin": "*",
"Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
"X-Frame-Options": "deny",
"X-Content-Type-Options": "nosniff",
"X-XSS-Protection": "0",
"Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
"Content-Security-Policy": "default-src 'none'",
"Server": "github.com",
"X-RateLimit-Limit": "5000",
"X-RateLimit-Remaining": "4963",
"X-RateLimit-Reset": "1769467964",
"X-RateLimit-Used": "37",
"X-RateLimit-Resource": "core",
"X-GitHub-Request-Id": "D98D:30C18B:44C18DC:3CA8C0F:6977E66C"
}
},
"uuid": "249d36bd-a54d-4106-a62f-f86c4f834d34",
"persistent": true,
"insertionIndex": 12
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"id": "78aa6b0d-5dc4-4b90-8b1a-3864ad247264",
"name": "repos_hub4j-test-org_github-api_pulls_comments_1641771497",
"request": {
"url": "/repos/hub4j-test-org/github-api/pulls/comments/1641771497",
"method": "GET",
"headers": {
"Accept": {
"equalTo": "application/vnd.github+json"
}
}
},
"response": {
"status": 200,
"bodyFileName": "13-r_h_g_pulls_comments_1641771497.json",
"headers": {
"Date": "Mon, 26 Jan 2026 22:10:53 GMT",
"Content-Type": "application/json; charset=utf-8",
"Cache-Control": "private, max-age=60, s-maxage=60",
"Vary": "Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With",
"ETag": "W/\"089067a7341750dff9af7d18f68314ec595952d4062b8605e17e39a85285a435\"",
"Last-Modified": "Fri, 23 Jan 2026 05:51:42 GMT",
"X-OAuth-Scopes": "repo",
"X-Accepted-OAuth-Scopes": "",
"github-authentication-token-expiration": "2026-02-19 19:55:13 UTC",
"X-GitHub-Media-Type": "github.v3; format=json",
"x-github-api-version-selected": "2022-11-28",
"Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset",
"Access-Control-Allow-Origin": "*",
"Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
"X-Frame-Options": "deny",
"X-Content-Type-Options": "nosniff",
"X-XSS-Protection": "0",
"Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
"Content-Security-Policy": "default-src 'none'",
"Server": "github.com",
"X-RateLimit-Limit": "5000",
"X-RateLimit-Remaining": "4958",
"X-RateLimit-Reset": "1769467964",
"X-RateLimit-Used": "42",
"X-RateLimit-Resource": "core",
"X-GitHub-Request-Id": "D98F:31BF39:4380FA4:3B615A1:6977E66D"
}
},
"uuid": "78aa6b0d-5dc4-4b90-8b1a-3864ad247264",
"persistent": true,
"insertionIndex": 13
}
Loading