From 09c2b39530d3f128da1a2393df7f345fa50c61f0 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 13 Sep 2017 15:14:42 -0400 Subject: [PATCH 01/25] bridge-method-annotation should be an optional dep. --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index ff898cccd0..50d535cf67 100644 --- a/pom.xml +++ b/pom.xml @@ -131,6 +131,7 @@ com.infradna.tool bridge-method-annotation 1.14 + true org.kohsuke.stapler From ae1ec8b5580c33f7fc6bf19a580541980969ee35 Mon Sep 17 00:00:00 2001 From: Anton Zagorskii Date: Wed, 20 Sep 2017 13:22:30 +0100 Subject: [PATCH 02/25] Roles for team members --- src/main/java/org/kohsuke/github/GHTeam.java | 26 ++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHTeam.java b/src/main/java/org/kohsuke/github/GHTeam.java index ae950aed70..a2f9a87ae4 100644 --- a/src/main/java/org/kohsuke/github/GHTeam.java +++ b/src/main/java/org/kohsuke/github/GHTeam.java @@ -18,6 +18,12 @@ public class GHTeam { protected /*final*/ GHOrganization org; + /** Member's role in a team */ + public enum ROLE { + MEMBER, // A normal member of the team + MAINTAINER // Able to add/remove other team members, promote other team members to team maintainer, and edit the team's name and description. + }; + /*package*/ GHTeam wrapUp(GHOrganization owner) { this.org = owner; return this; @@ -116,6 +122,22 @@ public void add(GHUser u) throws IOException { org.root.retrieve().method("PUT").to(api("/memberships/" + u.getLogin()), null); } + /** + * Adds a member to the team + * + * The user will be invited to the organization if required. + * + * @param user github user + * @param role role for the new member + * + * @throws IOException + */ + public void add(GHUser user, ROLE role) throws IOException { + org.root.retrieve().method("PUT") + .with("role", role.name()) + .to(api("/memberships/" + user.getLogin()), null); + } + /** * Removes a member to the team. */ @@ -129,7 +151,7 @@ public void add(GHRepository r) throws IOException { public void add(GHRepository r, GHOrganization.Permission permission) throws IOException { org.root.retrieve().method("PUT") - .with("permission",permission) + .with("permission", permission) .to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null); } @@ -145,7 +167,7 @@ public void delete() throws IOException { } private String api(String tail) { - return "/teams/"+id+tail; + return "/teams/" + id + tail; } public GHOrganization getOrganization() { From 0f81d1dbb35f4a7a34791c188ef6abd256025564 Mon Sep 17 00:00:00 2001 From: Matt Nelson Date: Thu, 5 Oct 2017 18:14:15 -0500 Subject: [PATCH 03/25] Add support for pr review/review comment events --- .../org/kohsuke/github/GHEventPayload.java | 89 +++++++++++++++++++ .../kohsuke/github/GHPullRequestReview.java | 8 +- .../github/GHPullRequestReviewState.java | 2 +- .../kohsuke/github/GHEventPayloadTest.java | 60 +++++++++++-- 4 files changed, 148 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHEventPayload.java b/src/main/java/org/kohsuke/github/GHEventPayload.java index 3d23973fd5..b01b32e432 100644 --- a/src/main/java/org/kohsuke/github/GHEventPayload.java +++ b/src/main/java/org/kohsuke/github/GHEventPayload.java @@ -85,6 +85,95 @@ void wrapUp(GitHub root) { } } + + /** + * A review was added to a pull request + * + * @see authoritative source + */ + public static class PullRequestReview extends GHEventPayload { + private String action; + private GHPullRequestReview review; + private GHPullRequest pull_request; + private GHRepository repository; + + public String getAction() { + return action; + } + + public GHPullRequestReview getReview() { + return review; + } + + public GHPullRequest getPullRequest() { + return pull_request; + } + + public GHRepository getRepository() { + return repository; + } + + @Override + void wrapUp(GitHub root) { + super.wrapUp(root); + if (review==null) + throw new IllegalStateException("Expected pull_request_review payload, but got something else. Maybe we've got another type of event?"); + + review.wrapUp(pull_request); + + if (repository!=null) { + repository.wrap(root); + pull_request.wrapUp(repository); + } else { + pull_request.wrapUp(root); + } + } + } + + /** + * A review comment was added to a pull request + * + * @see authoritative source + */ + public static class PullRequestReviewComment extends GHEventPayload { + private String action; + private GHPullRequestReviewComment comment; + private GHPullRequest pull_request; + private GHRepository repository; + + public String getAction() { + return action; + } + + public GHPullRequestReviewComment getComment() { + return comment; + } + + public GHPullRequest getPullRequest() { + return pull_request; + } + + public GHRepository getRepository() { + return repository; + } + + @Override + void wrapUp(GitHub root) { + super.wrapUp(root); + if (comment==null) + throw new IllegalStateException("Expected pull_request_review_comment payload, but got something else. Maybe we've got another type of event?"); + + comment.wrapUp(pull_request); + + if (repository!=null) { + repository.wrap(root); + pull_request.wrapUp(repository); + } else { + pull_request.wrapUp(root); + } + } + } + /** * A comment was added to an issue * diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReview.java b/src/main/java/org/kohsuke/github/GHPullRequestReview.java index d7afe59aad..8aa00c4b54 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReview.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReview.java @@ -40,7 +40,7 @@ public class GHPullRequestReview extends GHObject { private String body; private GHUser user; private String commit_id; - private GHPullRequestReviewState state; + private String state; /*package*/ GHPullRequestReview wrapUp(GHPullRequest owner) { this.owner = owner; @@ -73,7 +73,7 @@ public String getCommitId() { } public GHPullRequestReviewState getState() { - return state; + return GHPullRequestReviewState.valueOf(state.toUpperCase()); } @Override @@ -97,7 +97,7 @@ public void submit(String body, GHPullRequestReviewState event) throws IOExcepti .withPreview("application/vnd.github.black-cat-preview+json") .to(getApiRoute()+"/events",this); this.body = body; - this.state = event; + this.state = event.name(); } /** @@ -121,7 +121,7 @@ public void dismiss(String message) throws IOException { .with("message", message) .withPreview(BLACK_CAT) .to(getApiRoute()+"/dismissals"); - state = GHPullRequestReviewState.DISMISSED; + state = GHPullRequestReviewState.DISMISSED.name(); } /** diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java index fca3fabfb3..e909e54450 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java @@ -3,7 +3,7 @@ public enum GHPullRequestReviewState { PENDING(null), APPROVED("APPROVE"), - REQUEST_CHANGES("REQUEST_CHANGES"), + CHANGES_REQUESTED("REQUEST_CHANGES"), COMMENTED("COMMENT"), DISMISSED(null); diff --git a/src/test/java/org/kohsuke/github/GHEventPayloadTest.java b/src/test/java/org/kohsuke/github/GHEventPayloadTest.java index 07758d1a03..d2ff30012f 100644 --- a/src/test/java/org/kohsuke/github/GHEventPayloadTest.java +++ b/src/test/java/org/kohsuke/github/GHEventPayloadTest.java @@ -187,13 +187,61 @@ public void pull_request() throws Exception { assertThat(event.getSender().getLogin(), is("baxterthehacker")); } -// TODO implement support classes and write test -// @Test -// public void pull_request_review() throws Exception {} + @Test + public void pull_request_review() throws Exception { + GHEventPayload.PullRequestReview event = + GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.PullRequestReview.class); + assertThat(event.getAction(), is("submitted")); + + assertThat(event.getReview().getId(), is(2626884)); + assertThat(event.getReview().getBody(), is("Looks great!")); + assertThat(event.getReview().getState(), is(GHPullRequestReviewState.APPROVED)); + + assertThat(event.getPullRequest().getNumber(), is(8)); + assertThat(event.getPullRequest().getTitle(), is("Add a README description")); + assertThat(event.getPullRequest().getBody(), is("Just a few more details")); + assertThat(event.getPullRequest().getUser().getLogin(), is("skalnik")); + assertThat(event.getPullRequest().getHead().getUser().getLogin(), is("skalnik")); + assertThat(event.getPullRequest().getHead().getRef(), is("patch-2")); + assertThat(event.getPullRequest().getHead().getLabel(), is("skalnik:patch-2")); + assertThat(event.getPullRequest().getHead().getSha(), is("b7a1f9c27caa4e03c14a88feb56e2d4f7500aa63")); + assertThat(event.getPullRequest().getBase().getUser().getLogin(), is("baxterthehacker")); + assertThat(event.getPullRequest().getBase().getRef(), is("master")); + assertThat(event.getPullRequest().getBase().getLabel(), is("baxterthehacker:master")); + assertThat(event.getPullRequest().getBase().getSha(), is("9049f1265b7d61be4a8904a9a27120d2064dab3b")); + + assertThat(event.getRepository().getName(), is("public-repo")); + assertThat(event.getRepository().getOwner().getLogin(), is("baxterthehacker")); + + assertThat(event.getSender().getLogin(), is("baxterthehacker")); + } -// TODO implement support classes and write test -// @Test -// public void pull_request_review_comment() throws Exception {} + @Test + public void pull_request_review_comment() throws Exception { + GHEventPayload.PullRequestReviewComment event = + GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.PullRequestReviewComment.class); + assertThat(event.getAction(), is("created")); + + assertThat(event.getComment().getBody(), is("Maybe you should use more emojji on this line.")); + + assertThat(event.getPullRequest().getNumber(), is(1)); + assertThat(event.getPullRequest().getTitle(), is("Update the README with new information")); + assertThat(event.getPullRequest().getBody(), is("This is a pretty simple change that we need to pull into master.")); + assertThat(event.getPullRequest().getUser().getLogin(), is("baxterthehacker")); + assertThat(event.getPullRequest().getHead().getUser().getLogin(), is("baxterthehacker")); + assertThat(event.getPullRequest().getHead().getRef(), is("changes")); + assertThat(event.getPullRequest().getHead().getLabel(), is("baxterthehacker:changes")); + assertThat(event.getPullRequest().getHead().getSha(), is("0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c")); + assertThat(event.getPullRequest().getBase().getUser().getLogin(), is("baxterthehacker")); + assertThat(event.getPullRequest().getBase().getRef(), is("master")); + assertThat(event.getPullRequest().getBase().getLabel(), is("baxterthehacker:master")); + assertThat(event.getPullRequest().getBase().getSha(), is("9049f1265b7d61be4a8904a9a27120d2064dab3b")); + + assertThat(event.getRepository().getName(), is("public-repo")); + assertThat(event.getRepository().getOwner().getLogin(), is("baxterthehacker")); + + assertThat(event.getSender().getLogin(), is("baxterthehacker")); + } @Test public void push() throws Exception { From e25ae27a153e7462bd6fa56bd4da9da0918f5a5c Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 28 Oct 2017 15:54:44 -0700 Subject: [PATCH 04/25] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bc4e873120..dfdc0e7289 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.90 + 1.91-SNAPSHOT GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java @@ -16,7 +16,7 @@ scm:git:git@github.com/kohsuke/${project.artifactId}.git scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git http://${project.artifactId}.kohsuke.org/ - github-api-1.90 + HEAD From ab24e6e1c12b9ecbdbe83fad8fbbe22a43780b2f Mon Sep 17 00:00:00 2001 From: sg012265 Date: Mon, 30 Oct 2017 15:32:25 -0500 Subject: [PATCH 05/25] Add get for all orgs --- src/main/java/org/kohsuke/github/GitHub.java | 32 +++++++++++++++++++ .../java/org/kohsuke/github/GitHubTest.java | 17 ++++++++-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 67fc1f8fe4..1013508c01 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -424,6 +424,9 @@ protected GHUser getUser(GHUser orig) { return u; } + /** + * Gets {@link GHOrganization} specified by name. + */ public GHOrganization getOrganization(String name) throws IOException { GHOrganization o = orgs.get(name); if (o==null) { @@ -433,6 +436,35 @@ public GHOrganization getOrganization(String name) throws IOException { return o; } + /** + * Gets a list of all organizations. + */ + public PagedIterable getOrganizations() { + return getOrganizations(null); + } + + /** + * Gets a list of all organizations starting after the organization identifier specified by 'since'. + * + * @see List All Orgs - Parameters + */ + public PagedIterable getOrganizations(final String since) { + return new PagedIterable() { + @Override + public PagedIterator _iterator(int pageSize) { + System.out.println("page size: " + pageSize); + return new PagedIterator(retrieve().with("since",since) + .asIterator("/organizations", GHOrganization[].class, pageSize)) { + @Override + protected void wrapUp(GHOrganization[] page) { + for (GHOrganization c : page) + c.wrapUp(GitHub.this); + } + }; + } + }; + } + /** * Gets the repository object from 'user/reponame' string that GitHub calls as "repository name" * diff --git a/src/test/java/org/kohsuke/github/GitHubTest.java b/src/test/java/org/kohsuke/github/GitHubTest.java index a418db5fde..9b30d31b6e 100644 --- a/src/test/java/org/kohsuke/github/GitHubTest.java +++ b/src/test/java/org/kohsuke/github/GitHubTest.java @@ -3,13 +3,12 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Field; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import com.google.common.collect.Iterables; import org.junit.Test; +import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; @@ -155,4 +154,16 @@ public void listUsers() throws IOException { System.out.println(u.getName()); } } + + @Test + public void getOrgs() throws IOException { + GitHub hub = GitHub.connect(); + int iterations = 10; + Set orgIds = new HashSet(); + for (GHOrganization org : Iterables.limit(hub.getOrganizations().withPageSize(2), iterations)) { + orgIds.add(org.getId()); + System.out.println(org.getName()); + } + assertThat(orgIds.size(), equalTo(iterations)); + } } From 35ba2671155953278e7e491466b3a379d6cd087e Mon Sep 17 00:00:00 2001 From: sg012265 Date: Mon, 30 Oct 2017 15:38:19 -0500 Subject: [PATCH 06/25] Revert wildcard usage for imports --- src/test/java/org/kohsuke/github/GitHubTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/kohsuke/github/GitHubTest.java b/src/test/java/org/kohsuke/github/GitHubTest.java index 9b30d31b6e..c6e1e4113a 100644 --- a/src/test/java/org/kohsuke/github/GitHubTest.java +++ b/src/test/java/org/kohsuke/github/GitHubTest.java @@ -3,7 +3,11 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Field; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import com.google.common.collect.Iterables; import org.junit.Test; From ab6253cbd0a0d82c72ce5e212a799c7d40c36755 Mon Sep 17 00:00:00 2001 From: Rechi Date: Thu, 9 Nov 2017 22:41:49 +0100 Subject: [PATCH 07/25] [fix] GHPerson: check if root is null --- src/main/java/org/kohsuke/github/GHPerson.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHPerson.java b/src/main/java/org/kohsuke/github/GHPerson.java index f9872699ce..87cb8efaa7 100644 --- a/src/main/java/org/kohsuke/github/GHPerson.java +++ b/src/main/java/org/kohsuke/github/GHPerson.java @@ -41,7 +41,7 @@ protected synchronized void populate() throws IOException { if (created_at!=null) { return; // already populated } - if (root.isOffline()) { + if (root == null || root.isOffline()) { return; // cannot populate, will have to live with what we have } root.retrieve().to(url, this); From c80b8f60f820db6ee1af17305308a9db62b55781 Mon Sep 17 00:00:00 2001 From: Michiaki Mizoguchi Date: Thu, 16 Nov 2017 12:36:31 +0900 Subject: [PATCH 08/25] Add GHIssue#setMilestone --- src/main/java/org/kohsuke/github/GHIssue.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GHIssue.java b/src/main/java/org/kohsuke/github/GHIssue.java index 117c06f8d8..186ea16719 100644 --- a/src/main/java/org/kohsuke/github/GHIssue.java +++ b/src/main/java/org/kohsuke/github/GHIssue.java @@ -203,6 +203,10 @@ public void setBody(String body) throws IOException { edit("body",body); } + public void setMilestone(GHMilestone milestone) throws IOException { + edit("milestone",milestone.getNumber()); + } + public void assignTo(GHUser user) throws IOException { setAssignees(user); } From 15991fd2f763a40dd21c2a7715735abd87de9423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lesaint?= Date: Thu, 30 Nov 2017 14:38:47 +0100 Subject: [PATCH 09/25] PullRequest review state and event do not have same values this fixes parsing of response of WS call submitting a review to fail when event of new review is REQUEST_CHANGES also, specifying event when creating a pending PR review is useless and providing it when submitting the review is enough --- .../org/kohsuke/github/GHPullRequest.java | 15 +++---- .../kohsuke/github/GHPullRequestReview.java | 7 ++-- .../github/GHPullRequestReviewEvent.java | 41 +++++++++++++++++++ .../github/GHPullRequestReviewState.java | 20 +++------ .../org/kohsuke/github/PullRequestTest.java | 2 +- 5 files changed, 56 insertions(+), 29 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/GHPullRequestReviewEvent.java diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 9342623829..99db3bf32c 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -23,7 +23,6 @@ */ package org.kohsuke.github; -import javax.annotation.CheckForNull; import java.io.IOException; import java.net.URL; import java.util.ArrayList; @@ -298,23 +297,19 @@ protected void wrapUp(GHPullRequestCommitDetail[] page) { @Preview @Deprecated - public GHPullRequestReview createReview(String body, @CheckForNull GHPullRequestReviewState event, - GHPullRequestReviewComment... comments) + public GHPullRequestReview createReview(String body, GHPullRequestReviewComment... comments) throws IOException { - return createReview(body, event, Arrays.asList(comments)); + return createReview(body, Arrays.asList(comments)); } @Preview @Deprecated - public GHPullRequestReview createReview(String body, @CheckForNull GHPullRequestReviewState event, - List comments) + public GHPullRequestReview createReview(String body, List comments) throws IOException { -// if (event == null) { -// event = GHPullRequestReviewState.PENDING; -// } List draftComments = new ArrayList(comments.size()); for (GHPullRequestReviewComment c : comments) { - draftComments.add(new DraftReviewComment(c.getBody(), c.getPath(), c.getPosition())); + Integer position = c.getPosition(); + draftComments.add(new DraftReviewComment(c.getBody(), c.getPath(), position == null ? 0 : position /*FIXME do not use GHPullRequestReviewComment for new comments*/)); } return new Requester(root).method("POST") .with("body", body) diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReview.java b/src/main/java/org/kohsuke/github/GHPullRequestReview.java index d7afe59aad..c96e8f1491 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReview.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReview.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.net.URL; +import javax.annotation.CheckForNull; import static org.kohsuke.github.Previews.*; @@ -32,7 +33,7 @@ * Review to the pull request * * @see GHPullRequest#listReviews() - * @see GHPullRequest#createReview(String, GHPullRequestReviewState, GHPullRequestReviewComment...) + * @see GHPullRequest#createReview(String, GHPullRequestReviewComment...) */ public class GHPullRequestReview extends GHObject { GHPullRequest owner; @@ -72,6 +73,7 @@ public String getCommitId() { return commit_id; } + @CheckForNull public GHPullRequestReviewState getState() { return state; } @@ -90,14 +92,13 @@ protected String getApiRoute() { */ @Preview @Deprecated - public void submit(String body, GHPullRequestReviewState event) throws IOException { + public void submit(String body, GHPullRequestReviewEvent event) throws IOException { new Requester(owner.root).method("POST") .with("body", body) .with("event", event.action()) .withPreview("application/vnd.github.black-cat-preview+json") .to(getApiRoute()+"/events",this); this.body = body; - this.state = event; } /** diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewEvent.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewEvent.java new file mode 100644 index 0000000000..4a5d66094f --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewEvent.java @@ -0,0 +1,41 @@ +/* + * The MIT License + * + * Copyright (c) 2011, Eric Maupin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.kohsuke.github; + +public enum GHPullRequestReviewEvent { + PENDING(null), + APPROVE("APPROVE"), + REQUEST_CHANGES("REQUEST_CHANGES"), + COMMENT("COMMENT"); + + private final String _action; + + GHPullRequestReviewEvent(String action) { + _action = action; + } + + public String action() { + return _action; + } +} diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java index fca3fabfb3..eff7fbf60b 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java @@ -1,19 +1,9 @@ package org.kohsuke.github; public enum GHPullRequestReviewState { - PENDING(null), - APPROVED("APPROVE"), - REQUEST_CHANGES("REQUEST_CHANGES"), - COMMENTED("COMMENT"), - DISMISSED(null); - - private final String _action; - - GHPullRequestReviewState(String action) { - _action = action; - } - - public String action() { - return _action; - } + PENDING, + APPROVED, + CHANGES_REQUESTED, + COMMENTED, + DISMISSED } diff --git a/src/test/java/org/kohsuke/github/PullRequestTest.java b/src/test/java/org/kohsuke/github/PullRequestTest.java index 5ea2628303..bf45e35c46 100644 --- a/src/test/java/org/kohsuke/github/PullRequestTest.java +++ b/src/test/java/org/kohsuke/github/PullRequestTest.java @@ -45,7 +45,7 @@ public void testPullRequestReviews() throws Exception { assertThat(review.getState(), is(GHPullRequestReviewState.PENDING)); assertThat(review.getBody(), is("Some draft review")); assertThat(review.getCommitId(), notNullValue()); - review.submit("Some review comment", GHPullRequestReviewState.COMMENTED); + review.submit("Some review comment", GHPullRequestReviewEvent.COMMENT); List comments = review.listReviewComments().asList(); assertEquals(1, comments.size()); GHPullRequestReviewComment comment = comments.get(0); From fa16261d7a7e96552b5694c0c24120da5afba1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lesaint?= Date: Thu, 30 Nov 2017 14:39:16 +0100 Subject: [PATCH 10/25] position of pr comment can be null and original_position is not parsed position of pr comment is null when comment is outdated (ie. not located in diff patch anymore) --- .../kohsuke/github/GHPullRequestReviewComment.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java index 33097bc29d..f1a2c603da 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.net.URL; +import javax.annotation.CheckForNull; import static org.kohsuke.github.Previews.*; @@ -41,8 +42,8 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable { private String body; private GHUser user; private String path; - private int position; - private int originalPosition; + private int position = -1; + private int original_position = -1; public static GHPullRequestReviewComment draft(String body, String path, int position) { GHPullRequestReviewComment result = new GHPullRequestReviewComment(); @@ -82,12 +83,14 @@ public String getPath() { return path; } - public int getPosition() { - return position; + @CheckForNull + public Integer getPosition() { + return position == -1 ? null : position; } + @CheckForNull public int getOriginalPosition() { - return originalPosition; + return original_position == -1 ? null : original_position; } @Override From 892d30516546be46f7cebd3a0f920db0801b3e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lesaint?= Date: Mon, 8 Jan 2018 15:29:22 +0100 Subject: [PATCH 11/25] add Requester#with override for long value --- src/main/java/org/kohsuke/github/Requester.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index 00f11f2426..73a8bfb34e 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -134,6 +134,10 @@ public Requester with(String key, int value) { return _with(key, value); } + public Requester with(String key, long value) { + return _with(key, value); + } + public Requester with(String key, Integer value) { if (value!=null) _with(key, value); From 6961c467a64a43584e026b2438e7a254fcc8f481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lesaint?= Date: Fri, 1 Dec 2017 17:37:27 +0100 Subject: [PATCH 12/25] create review comment reply from GHPullRequest --- .../java/org/kohsuke/github/GHPullRequest.java | 15 +++++++++++++-- .../github/GHPullRequestReviewComment.java | 11 +++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 99db3bf32c..369dff911b 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -90,7 +90,7 @@ protected String getApiRoute() { public URL getPatchUrl() { return GitHub.parseURL(patch_url); } - + /** * The URL of the patch file. * like https://github.com/jenkinsci/jenkins/pull/100.patch @@ -113,7 +113,7 @@ public GHCommitPointer getBase() { public GHCommitPointer getHead() { return head; } - + @Deprecated public Date getIssueUpdatedAt() throws IOException { return super.getUpdatedAt(); @@ -328,6 +328,17 @@ public GHPullRequestReviewComment createReviewComment(String body, String sha, S .to(getApiRoute() + "/comments", GHPullRequestReviewComment.class).wrapUp(this); } + /** + * Create a reply to the current comment. + */ + public GHPullRequestReviewComment createReviewCommentReply(GHPullRequestReviewComment comment, String body) throws IOException { + return new Requester(owner.root).method("POST") + .with("body", body) + .with("in_reply_to", comment.getId()) + .to(getApiRoute() + "/comments", GHPullRequestReviewComment.class) + .wrapUp(this); + } + /** * Merge this pull request. * diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java index f1a2c603da..5ab8861f8d 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java @@ -44,6 +44,8 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable { private String path; private int position = -1; private int original_position = -1; + private long in_reply_to_id = -1L; + public static GHPullRequestReviewComment draft(String body, String path, int position) { GHPullRequestReviewComment result = new GHPullRequestReviewComment(); @@ -89,10 +91,15 @@ public Integer getPosition() { } @CheckForNull - public int getOriginalPosition() { + public Integer getOriginalPosition() { return original_position == -1 ? null : original_position; } + @CheckForNull + public Long getInReplyToId() { + return in_reply_to_id == -1 ? null : in_reply_to_id; + } + @Override public URL getHtmlUrl() { return null; @@ -129,7 +136,7 @@ public GHReaction createReaction(ReactionContent content) throws IOException { public PagedIterable listReactions() { return new PagedIterable() { public PagedIterator _iterator(int pageSize) { - return new PagedIterator(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute()+"/reactions", GHReaction[].class, pageSize)) { + return new PagedIterator(owner.root.retrieve().withPreview(SQUIRREL_GIRL).asIterator(getApiRoute() + "/reactions", GHReaction[].class, pageSize)) { @Override protected void wrapUp(GHReaction[] page) { for (GHReaction c : page) From e74346fed6d5206d8ab54e4dab5542df597ddd87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lesaint?= Date: Mon, 4 Dec 2017 11:11:58 +0100 Subject: [PATCH 13/25] support create PR review in single API call & remove @Preview --- .../org/kohsuke/github/GHPullRequest.java | 72 ++++++++---- .../kohsuke/github/GHPullRequestReview.java | 109 ++---------------- .../github/GHPullRequestReviewAbstract.java | 101 ++++++++++++++++ .../github/GHPullRequestReviewDraft.java | 53 +++++++++ .../org/kohsuke/github/PullRequestTest.java | 8 +- 5 files changed, 214 insertions(+), 129 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/GHPullRequestReviewAbstract.java create mode 100644 src/main/java/org/kohsuke/github/GHPullRequestReviewDraft.java diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 369dff911b..5a62936f8d 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -23,6 +23,7 @@ */ package org.kohsuke.github; +import javax.annotation.Nullable; import java.io.IOException; import java.net.URL; import java.util.ArrayList; @@ -35,13 +36,16 @@ /** * A pull request. - * + * * @author Kohsuke Kawaguchi * @see GHRepository#getPullRequest(int) */ @SuppressWarnings({"UnusedDeclaration"}) public class GHPullRequest extends GHIssue { + private static final String COMMENTS_ACTION = "/comments"; + private static final String COMMIT_ID_FIELD = "commit_id"; + private String patch_url, diff_url, issue_url; private GHCommitPointer base; private String merged_at; @@ -245,7 +249,6 @@ public PagedIterable listReviews() { return new PagedIterable() { public PagedIterator _iterator(int pageSize) { return new PagedIterator(root.retrieve() - .withPreview(BLACK_CAT) .asIterator(String.format("%s/reviews", getApiRoute()), GHPullRequestReview[].class, pageSize)) { @Override @@ -265,7 +268,7 @@ protected void wrapUp(GHPullRequestReview[] page) { public PagedIterable listReviewComments() throws IOException { return new PagedIterable() { public PagedIterator _iterator(int pageSize) { - return new PagedIterator(root.retrieve().asIterator(getApiRoute() + "/comments", + return new PagedIterator(root.retrieve().asIterator(getApiRoute() + COMMENTS_ACTION, GHPullRequestReviewComment[].class, pageSize)) { protected void wrapUp(GHPullRequestReviewComment[] page) { for (GHPullRequestReviewComment c : page) @@ -295,37 +298,58 @@ protected void wrapUp(GHPullRequestCommitDetail[] page) { }; } - @Preview - @Deprecated - public GHPullRequestReview createReview(String body, GHPullRequestReviewComment... comments) + public GHPullRequestReview createReview(@Nullable String commitId, String body, GHPullRequestReviewEvent event, + GHPullRequestReviewComment... comments) throws IOException { + return createReview(commitId, body, event, Arrays.asList(comments)); + } + + public GHPullRequestReview createReview(@Nullable String commitId, String body, GHPullRequestReviewEvent event, + List comments) throws IOException { + List draftComments = toDraftReviewComments(comments); + return new Requester(root).method("POST") + .with(COMMIT_ID_FIELD, commitId) + .with("body", body) + .with("event", event.action()) + ._with("comments", draftComments) + .to(getApiRoute() + "/reviews", GHPullRequestReview.class) + .wrapUp(this); + } + + public GHPullRequestReviewDraft newDraftReview(@Nullable String commitId, String body, GHPullRequestReviewComment... comments) throws IOException { - return createReview(body, Arrays.asList(comments)); + return newDraftReview(commitId, body, Arrays.asList(comments)); } - @Preview - @Deprecated - public GHPullRequestReview createReview(String body, List comments) + public GHPullRequestReviewDraft newDraftReview(@Nullable String commitId, String body, List comments) throws IOException { + List draftComments = toDraftReviewComments(comments); + return new Requester(root).method("POST") + .with(COMMIT_ID_FIELD, commitId) + .with("body", body) + ._with("comments", draftComments) + .to(getApiRoute() + "/reviews", GHPullRequestReviewDraft.class) + .wrapUp(this); + } + + private static List toDraftReviewComments(List comments) { List draftComments = new ArrayList(comments.size()); for (GHPullRequestReviewComment c : comments) { Integer position = c.getPosition(); - draftComments.add(new DraftReviewComment(c.getBody(), c.getPath(), position == null ? 0 : position /*FIXME do not use GHPullRequestReviewComment for new comments*/)); + if (position == null) { + throw new IllegalArgumentException("GHPullRequestReviewComment must have a position"); + } + draftComments.add(new DraftReviewComment(c.getBody(), c.getPath(), position)); } - return new Requester(root).method("POST") - .with("body", body) - //.with("event", event.name()) - ._with("comments", draftComments) - .withPreview(BLACK_CAT) - .to(getApiRoute() + "/reviews", GHPullRequestReview.class).wrapUp(this); + return draftComments; } public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position) throws IOException { return new Requester(root).method("POST") .with("body", body) - .with("commit_id", sha) + .with(COMMIT_ID_FIELD, sha) .with("path", path) .with("position", position) - .to(getApiRoute() + "/comments", GHPullRequestReviewComment.class).wrapUp(this); + .to(getApiRoute() + COMMENTS_ACTION, GHPullRequestReviewComment.class).wrapUp(this); } /** @@ -335,7 +359,7 @@ public GHPullRequestReviewComment createReviewCommentReply(GHPullRequestReviewCo return new Requester(owner.root).method("POST") .with("body", body) .with("in_reply_to", comment.getId()) - .to(getApiRoute() + "/comments", GHPullRequestReviewComment.class) + .to(getApiRoute() + COMMENTS_ACTION, GHPullRequestReviewComment.class) .wrapUp(this); } @@ -377,10 +401,10 @@ public void merge(String msg, String sha) throws IOException { */ public void merge(String msg, String sha, MergeMethod method) throws IOException { new Requester(root).method("PUT") - .with("commit_message",msg) - .with("sha",sha) - .with("merge_method",method) - .to(getApiRoute()+"/merge"); + .with("commit_message", msg) + .with("sha", sha) + .with("merge_method", method) + .to(getApiRoute() + "/merge"); } public enum MergeMethod{ MERGE, SQUASH, REBASE } diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReview.java b/src/main/java/org/kohsuke/github/GHPullRequestReview.java index c96e8f1491..3bb155b881 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReview.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReview.java @@ -24,127 +24,34 @@ package org.kohsuke.github; import java.io.IOException; -import java.net.URL; -import javax.annotation.CheckForNull; - -import static org.kohsuke.github.Previews.*; +import java.util.List; /** * Review to the pull request * * @see GHPullRequest#listReviews() - * @see GHPullRequest#createReview(String, GHPullRequestReviewComment...) + * @see GHPullRequest#createReview(String, String, GHPullRequestReviewEvent, List) */ -public class GHPullRequestReview extends GHObject { - GHPullRequest owner; - - private String body; - private GHUser user; - private String commit_id; +public class GHPullRequestReview extends GHPullRequestReviewAbstract { private GHPullRequestReviewState state; - /*package*/ GHPullRequestReview wrapUp(GHPullRequest owner) { - this.owner = owner; - return this; - } - - /** - * Gets the pull request to which this review is associated. - */ - public GHPullRequest getParent() { - return owner; - } - - /** - * The comment itself. - */ - public String getBody() { - return body; - } - - /** - * Gets the user who posted this review. - */ - public GHUser getUser() throws IOException { - return owner.root.getUser(user.getLogin()); - } - - public String getCommitId() { - return commit_id; - } - - @CheckForNull + @Override public GHPullRequestReviewState getState() { return state; } - @Override - public URL getHtmlUrl() { - return null; - } - - protected String getApiRoute() { - return owner.getApiRoute()+"/reviews/"+id; - } - - /** - * Updates the comment. - */ - @Preview - @Deprecated - public void submit(String body, GHPullRequestReviewEvent event) throws IOException { - new Requester(owner.root).method("POST") - .with("body", body) - .with("event", event.action()) - .withPreview("application/vnd.github.black-cat-preview+json") - .to(getApiRoute()+"/events",this); - this.body = body; - } - - /** - * Deletes this review. - */ - @Preview - @Deprecated - public void delete() throws IOException { - new Requester(owner.root).method("DELETE") - .withPreview(BLACK_CAT) - .to(getApiRoute()); + GHPullRequestReview wrapUp(GHPullRequest owner) { + this.owner = owner; + return this; } /** * Dismisses this review. */ - @Preview - @Deprecated public void dismiss(String message) throws IOException { new Requester(owner.root).method("PUT") .with("message", message) - .withPreview(BLACK_CAT) - .to(getApiRoute()+"/dismissals"); + .to(getApiRoute() + "/dismissals"); state = GHPullRequestReviewState.DISMISSED; } - - /** - * Obtains all the review comments associated with this pull request review. - */ - @Preview - @Deprecated - public PagedIterable listReviewComments() throws IOException { - return new PagedIterable() { - public PagedIterator _iterator(int pageSize) { - return new PagedIterator( - owner.root.retrieve() - .withPreview(BLACK_CAT) - .asIterator(getApiRoute() + "/comments", - GHPullRequestReviewComment[].class, pageSize)) { - protected void wrapUp(GHPullRequestReviewComment[] page) { - for (GHPullRequestReviewComment c : page) - c.wrapUp(owner); - } - }; - } - }; - } - } diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewAbstract.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewAbstract.java new file mode 100644 index 0000000000..4842a62085 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewAbstract.java @@ -0,0 +1,101 @@ +/* + * The MIT License + * + * Copyright (c) 2011, Eric Maupin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.kohsuke.github; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +import java.io.IOException; +import java.net.URL; + +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_FIELD"}, justification = "JSON API") +public abstract class GHPullRequestReviewAbstract extends GHObject { + protected GHPullRequest owner; + + protected String body; + private GHUser user; + private String commit_id; + + public abstract GHPullRequestReviewState getState(); + + /** + * Gets the pull request to which this review is associated. + */ + public GHPullRequest getParent() { + return owner; + } + + /** + * The comment itself. + */ + public String getBody() { + return body; + } + + /** + * Gets the user who posted this review. + */ + public GHUser getUser() throws IOException { + return owner.root.getUser(user.getLogin()); + } + + public String getCommitId() { + return commit_id; + } + + @Override + public URL getHtmlUrl() { + return null; + } + + String getApiRoute() { + return owner.getApiRoute() + "/reviews/" + id; + } + + /** + * Deletes this review. + */ + public void delete() throws IOException { + new Requester(owner.root).method("DELETE") + .to(getApiRoute()); + } + + /** + * Obtains all the review comments associated with this pull request review. + */ + public PagedIterable listReviewComments() { + return new PagedIterable() { + public PagedIterator _iterator(int pageSize) { + return new PagedIterator( + owner.root.retrieve() + .asIterator(getApiRoute() + "/comments", + GHPullRequestReviewComment[].class, pageSize)) { + protected void wrapUp(GHPullRequestReviewComment[] page) { + for (GHPullRequestReviewComment c : page) + c.wrapUp(owner); + } + }; + } + }; + } +} diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewDraft.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewDraft.java new file mode 100644 index 0000000000..689d061bc0 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewDraft.java @@ -0,0 +1,53 @@ +/* + * The MIT License + * + * Copyright (c) 2011, Eric Maupin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.kohsuke.github; + +import java.io.IOException; + +/** + * Draft of a Pull Request review. + * + * @see GHPullRequest#newDraftReview(String, String, GHPullRequestReviewComment...) + */ +public class GHPullRequestReviewDraft extends GHPullRequestReviewAbstract { + + GHPullRequestReviewDraft wrapUp(GHPullRequest owner) { + this.owner = owner; + return this; + } + + @Override + public GHPullRequestReviewState getState() { + return GHPullRequestReviewState.PENDING; + } + + public void submit(String body, GHPullRequestReviewEvent event) throws IOException { + new Requester(owner.root).method("POST") + .with("body", body) + .with("event", event.action()) + .to(getApiRoute() + "/events", this); + this.body = body; + } + +} diff --git a/src/test/java/org/kohsuke/github/PullRequestTest.java b/src/test/java/org/kohsuke/github/PullRequestTest.java index bf45e35c46..97826baea0 100644 --- a/src/test/java/org/kohsuke/github/PullRequestTest.java +++ b/src/test/java/org/kohsuke/github/PullRequestTest.java @@ -33,7 +33,7 @@ public void createPullRequestComment() throws Exception { public void testPullRequestReviews() throws Exception { String name = rnd.next(); GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test"); - GHPullRequestReview draftReview = p.createReview("Some draft review", null, + GHPullRequestReviewDraft draftReview = p.newDraftReview(null, "Some draft review", GHPullRequestReviewComment.draft("Some niggle", "changelog.html", 1) ); assertThat(draftReview.getState(), is(GHPullRequestReviewState.PENDING)); @@ -45,15 +45,15 @@ public void testPullRequestReviews() throws Exception { assertThat(review.getState(), is(GHPullRequestReviewState.PENDING)); assertThat(review.getBody(), is("Some draft review")); assertThat(review.getCommitId(), notNullValue()); - review.submit("Some review comment", GHPullRequestReviewEvent.COMMENT); + draftReview.submit("Some review comment", GHPullRequestReviewEvent.COMMENT); List comments = review.listReviewComments().asList(); assertEquals(1, comments.size()); GHPullRequestReviewComment comment = comments.get(0); assertEquals("Some niggle", comment.getBody()); - review = p.createReview("Some new review", null, + draftReview = p.newDraftReview(null, "Some new review", GHPullRequestReviewComment.draft("Some niggle", "changelog.html", 1) ); - review.delete(); + draftReview.delete(); } @Test From df861f54033c23a976c28639a5e5fdf5d42b4c6e Mon Sep 17 00:00:00 2001 From: Timothy McNally Date: Tue, 9 Jan 2018 17:32:54 -0800 Subject: [PATCH 14/25] Adding methods to GHCreateRepositoryBuilder to allow setting the allowed merge methods for pull requests. --- .../github/GHCreateRepositoryBuilder.java | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHCreateRepositoryBuilder.java b/src/main/java/org/kohsuke/github/GHCreateRepositoryBuilder.java index 492aaf5c81..a11fc4493f 100644 --- a/src/main/java/org/kohsuke/github/GHCreateRepositoryBuilder.java +++ b/src/main/java/org/kohsuke/github/GHCreateRepositoryBuilder.java @@ -21,8 +21,8 @@ public class GHCreateRepositoryBuilder { } public GHCreateRepositoryBuilder description(String description) { - this.builder.with("description",description); - return this; + this.builder.with("description",description); + return this; } public GHCreateRepositoryBuilder homepage(URL homepage) { @@ -74,6 +74,30 @@ public GHCreateRepositoryBuilder autoInit(boolean b) { return this; } + /** + * Allow or disallow squash-merging pull requests. + */ + public GHCreateRepositoryBuilder allowSquashMerge(boolean b) { + this.builder.with("allow_squash_merge",b); + return this; + } + + /** + * Allow or disallow merging pull requests with a merge commit. + */ + public GHCreateRepositoryBuilder allowMergeCommit(boolean b) { + this.builder.with("allow_merge_commit",b); + return this; + } + + /** + * Allow or disallow rebase-merging pull requests. + */ + public GHCreateRepositoryBuilder allowRebaseMerge(boolean b) { + this.builder.with("allow_rebase_merge",b); + return this; + } + /** * Creates a default .gitignore * From d0b4652dcde741edabbf063b8ea6218cf822c46c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20H=C3=A4user?= Date: Mon, 20 Nov 2017 21:36:00 +0100 Subject: [PATCH 15/25] Replace "new Error" with GHException (rolled back some of the hunks from the original PR) --- src/main/java/org/kohsuke/github/GHGist.java | 10 +++------- src/main/java/org/kohsuke/github/Requester.java | 17 +++++++++-------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHGist.java b/src/main/java/org/kohsuke/github/GHGist.java index a9bf3fef42..c4c91737d6 100644 --- a/src/main/java/org/kohsuke/github/GHGist.java +++ b/src/main/java/org/kohsuke/github/GHGist.java @@ -103,7 +103,7 @@ public Map getFiles() { * Used when caller obtains {@link GHGist} without knowing its owner. * A partially constructed owner object is interned. */ - /*package*/ GHGist wrapUp(GitHub root) throws IOException { + /*package*/ GHGist wrapUp(GitHub root) { this.owner = root.getUser(owner); this.root = root; wrapUp(); @@ -144,12 +144,8 @@ public PagedIterator _iterator(int pageSize) { return new PagedIterator(root.retrieve().asIterator(getApiTailUrl("forks"), GHGist[].class, pageSize)) { @Override protected void wrapUp(GHGist[] page) { - try { - for (GHGist c : page) - c.wrapUp(root); - } catch (IOException e) { - throw new Error(e); - } + for (GHGist c : page) + c.wrapUp(root); } }; } diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index 00f11f2426..24063099e6 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -54,16 +54,17 @@ import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; -import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; -import static java.util.Arrays.*; -import static java.util.logging.Level.*; -import static org.apache.commons.lang.StringUtils.*; -import static org.kohsuke.github.GitHub.*; +import static java.util.Arrays.asList; +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.FINEST; +import static java.util.logging.Level.INFO; +import static org.apache.commons.lang.StringUtils.defaultString; +import static org.kohsuke.github.GitHub.MAPPER; /** * A builder pattern for making HTTP call and parsing its output. @@ -451,8 +452,8 @@ private boolean isMethodWithBody() { try { return new PagingIterator(type, tailApiUrl, root.getApiURL(s.toString())); - } catch (IOException e) { - throw new Error(e); + } catch (MalformedURLException e) { + throw new GHException("Unable to build github Api URL",e); } } @@ -513,7 +514,7 @@ private void fetch() { } } } catch (IOException e) { - throw new Error(e); + throw new GHException(e); } } From a17ce04552ddd3f6bd8210c740184e6c7ad13ae4 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 12 Jan 2018 21:00:25 -0800 Subject: [PATCH 16/25] Adjustment to compensate --- src/main/java/org/kohsuke/github/Requester.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index 24063099e6..f26466bacf 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -452,7 +452,7 @@ private boolean isMethodWithBody() { try { return new PagingIterator(type, tailApiUrl, root.getApiURL(s.toString())); - } catch (MalformedURLException e) { + } catch (IOException e) { throw new GHException("Unable to build github Api URL",e); } } @@ -514,7 +514,7 @@ private void fetch() { } } } catch (IOException e) { - throw new GHException(e); + throw new GHException("Failed to retrieve "+url); } } From 43075faaf82f3afc1105f92d056aad6f46032265 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 12 Jan 2018 21:06:47 -0800 Subject: [PATCH 17/25] By convention we use "listXyz" method names --- src/main/java/org/kohsuke/github/GitHub.java | 7 +++---- src/test/java/org/kohsuke/github/GitHubTest.java | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 1013508c01..f7e0d58096 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -48,7 +48,6 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; -import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; @@ -439,8 +438,8 @@ public GHOrganization getOrganization(String name) throws IOException { /** * Gets a list of all organizations. */ - public PagedIterable getOrganizations() { - return getOrganizations(null); + public PagedIterable listOrganizations() { + return listOrganizations(null); } /** @@ -448,7 +447,7 @@ public PagedIterable getOrganizations() { * * @see List All Orgs - Parameters */ - public PagedIterable getOrganizations(final String since) { + public PagedIterable listOrganizations(final String since) { return new PagedIterable() { @Override public PagedIterator _iterator(int pageSize) { diff --git a/src/test/java/org/kohsuke/github/GitHubTest.java b/src/test/java/org/kohsuke/github/GitHubTest.java index c6e1e4113a..f4b77b8271 100644 --- a/src/test/java/org/kohsuke/github/GitHubTest.java +++ b/src/test/java/org/kohsuke/github/GitHubTest.java @@ -164,7 +164,7 @@ public void getOrgs() throws IOException { GitHub hub = GitHub.connect(); int iterations = 10; Set orgIds = new HashSet(); - for (GHOrganization org : Iterables.limit(hub.getOrganizations().withPageSize(2), iterations)) { + for (GHOrganization org : Iterables.limit(hub.listOrganizations().withPageSize(2), iterations)) { orgIds.add(org.getId()); System.out.println(org.getName()); } From 65996050d5f25c44d1db8792da6c6e605955ab57 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 12 Jan 2018 21:12:40 -0800 Subject: [PATCH 18/25] Massaged changes to follow the convention --- src/main/java/org/kohsuke/github/GHTeam.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHTeam.java b/src/main/java/org/kohsuke/github/GHTeam.java index a2f9a87ae4..bccec4b5ed 100644 --- a/src/main/java/org/kohsuke/github/GHTeam.java +++ b/src/main/java/org/kohsuke/github/GHTeam.java @@ -19,10 +19,16 @@ public class GHTeam { protected /*final*/ GHOrganization org; /** Member's role in a team */ - public enum ROLE { - MEMBER, // A normal member of the team - MAINTAINER // Able to add/remove other team members, promote other team members to team maintainer, and edit the team's name and description. - }; + public enum Role { + /** + * A normal member of the team + */ + MEMBER, + /** + * Able to add/remove other team members, promote other team members to team maintainer, and edit the team's name and description. + */ + MAINTAINER + } /*package*/ GHTeam wrapUp(GHOrganization owner) { this.org = owner; @@ -132,7 +138,7 @@ public void add(GHUser u) throws IOException { * * @throws IOException */ - public void add(GHUser user, ROLE role) throws IOException { + public void add(GHUser user, Role role) throws IOException { org.root.retrieve().method("PUT") .with("role", role.name()) .to(api("/memberships/" + user.getLogin()), null); From 4e31636181a2d847a9c6dbb6c186e387951f86af Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 12 Jan 2018 21:25:30 -0800 Subject: [PATCH 19/25] Allow the caller to wait for the mergeable state to change. This approaches #394 differently. The problem with the original #394 is that the supposed behaviour is only useful for people waiting for `getMergeable()` to return non-null in a busy loop, yet it impacts all the other methods of this object. --- .../java/org/kohsuke/github/GHPullRequest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 9342623829..6c8c9aac03 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -182,6 +182,13 @@ public boolean canMaintainerModify() throws IOException { return maintainer_can_modify; } + /** + * Is this PR mergeable? + * + * @return + * null if the state has not been determined yet, for example when a PR is newly created. + * Use {@link #refresh()} after some interval to wait until the value is determined. + */ public Boolean getMergeable() throws IOException { populate(); return mergeable; @@ -217,6 +224,13 @@ public String getMergeCommitSha() throws IOException { */ private void populate() throws IOException { if (mergeable_state!=null) return; // already populated + refresh(); + } + + /** + * Repopulates this object. + */ + public void refresh() throws IOException { if (root.isOffline()) { return; // cannot populate, will have to live with what we have } From 5113aacb89de358ade715a09570396c1d9a7b11e Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 12 Jan 2018 21:28:37 -0800 Subject: [PATCH 20/25] Issue #403: Typo in method name --- src/main/java/org/kohsuke/github/GHRepository.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 4dfd1397bc..b40f387b7f 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -173,6 +173,14 @@ public String getGitTransportUrl() { * Gets the HTTPS URL to this repository, such as "https://github.com/kohsuke/jenkins.git" * This URL is read-only. */ + public String getHttpTransportUrl() { + return clone_url; + } + + /** + * @deprecated + * Typo of {@link #getHttpTransportUrl()} + */ public String gitHttpTransportUrl() { return clone_url; } From 0f7c1604098b8e9d8f92d58d07bd7ec7b2188335 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 12 Jan 2018 21:33:03 -0800 Subject: [PATCH 21/25] Based on issue #399, adjusting the behaviour. This ends up changing the behaviour cloes to that of #394. --- src/main/java/org/kohsuke/github/GHPullRequest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 6c8c9aac03..742ab24279 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -187,10 +187,12 @@ public boolean canMaintainerModify() throws IOException { * * @return * null if the state has not been determined yet, for example when a PR is newly created. - * Use {@link #refresh()} after some interval to wait until the value is determined. + * If this method is called on an instance whose mergeable state is not yet known, + * API call is made to retrieve the latest state. */ public Boolean getMergeable() throws IOException { - populate(); + if (mergeable==null) + refresh(); return mergeable; } From acbf286e59d92592038e9c0cf56dd91509d93446 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 13 Jan 2018 09:43:44 -0800 Subject: [PATCH 22/25] Massaged the changes - Restored binary compatibility. The draft API has changed in some significant way when it became public, and the PR took the liberty to delete removed constants and method signatures. I brought them back so that older clients can keep functioning. - Introduced a builder pattern to create PR review - replying to a review comment should be an instance method, not a static method. - GHPullRequestReview and GHPullRequestReviewDraft was not making sense to me, since GitHub API doesn't differentiate them. It creates a practical problem of not being able to submit a review comment unless you created the review comment in the same JVM session. That said, I don't understand the point of this two phase approach in the GitHub API to begin with! --- .../org/kohsuke/github/GHPullRequest.java | 89 +------------- .../kohsuke/github/GHPullRequestReview.java | 109 ++++++++++++++++-- .../github/GHPullRequestReviewAbstract.java | 101 ---------------- .../github/GHPullRequestReviewBuilder.java | 91 +++++++++++++++ .../github/GHPullRequestReviewComment.java | 11 ++ .../github/GHPullRequestReviewDraft.java | 53 --------- .../github/GHPullRequestReviewEvent.java | 30 +++-- .../github/GHPullRequestReviewState.java | 32 ++++- .../java/org/kohsuke/github/Previews.java | 1 - .../org/kohsuke/github/PullRequestTest.java | 17 +-- 10 files changed, 265 insertions(+), 269 deletions(-) delete mode 100644 src/main/java/org/kohsuke/github/GHPullRequestReviewAbstract.java create mode 100644 src/main/java/org/kohsuke/github/GHPullRequestReviewBuilder.java delete mode 100644 src/main/java/org/kohsuke/github/GHPullRequestReviewDraft.java diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 5a62936f8d..084c982133 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -23,16 +23,10 @@ */ package org.kohsuke.github; -import javax.annotation.Nullable; import java.io.IOException; import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Date; -import java.util.List; - -import static org.kohsuke.github.Previews.*; /** * A pull request. @@ -44,7 +38,6 @@ public class GHPullRequest extends GHIssue { private static final String COMMENTS_ACTION = "/comments"; - private static final String COMMIT_ID_FIELD = "commit_id"; private String patch_url, diff_url, issue_url; private GHCommitPointer base; @@ -298,71 +291,19 @@ protected void wrapUp(GHPullRequestCommitDetail[] page) { }; } - public GHPullRequestReview createReview(@Nullable String commitId, String body, GHPullRequestReviewEvent event, - GHPullRequestReviewComment... comments) throws IOException { - return createReview(commitId, body, event, Arrays.asList(comments)); - } - - public GHPullRequestReview createReview(@Nullable String commitId, String body, GHPullRequestReviewEvent event, - List comments) throws IOException { - List draftComments = toDraftReviewComments(comments); - return new Requester(root).method("POST") - .with(COMMIT_ID_FIELD, commitId) - .with("body", body) - .with("event", event.action()) - ._with("comments", draftComments) - .to(getApiRoute() + "/reviews", GHPullRequestReview.class) - .wrapUp(this); - } - - public GHPullRequestReviewDraft newDraftReview(@Nullable String commitId, String body, GHPullRequestReviewComment... comments) - throws IOException { - return newDraftReview(commitId, body, Arrays.asList(comments)); - } - - public GHPullRequestReviewDraft newDraftReview(@Nullable String commitId, String body, List comments) - throws IOException { - List draftComments = toDraftReviewComments(comments); - return new Requester(root).method("POST") - .with(COMMIT_ID_FIELD, commitId) - .with("body", body) - ._with("comments", draftComments) - .to(getApiRoute() + "/reviews", GHPullRequestReviewDraft.class) - .wrapUp(this); - } - - private static List toDraftReviewComments(List comments) { - List draftComments = new ArrayList(comments.size()); - for (GHPullRequestReviewComment c : comments) { - Integer position = c.getPosition(); - if (position == null) { - throw new IllegalArgumentException("GHPullRequestReviewComment must have a position"); - } - draftComments.add(new DraftReviewComment(c.getBody(), c.getPath(), position)); - } - return draftComments; + public GHPullRequestReviewBuilder createReview() { + return new GHPullRequestReviewBuilder(this); } public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position) throws IOException { return new Requester(root).method("POST") .with("body", body) - .with(COMMIT_ID_FIELD, sha) + .with("commit_id", sha) .with("path", path) .with("position", position) .to(getApiRoute() + COMMENTS_ACTION, GHPullRequestReviewComment.class).wrapUp(this); } - /** - * Create a reply to the current comment. - */ - public GHPullRequestReviewComment createReviewCommentReply(GHPullRequestReviewComment comment, String body) throws IOException { - return new Requester(owner.root).method("POST") - .with("body", body) - .with("in_reply_to", comment.getId()) - .to(getApiRoute() + COMMENTS_ACTION, GHPullRequestReviewComment.class) - .wrapUp(this); - } - /** * Merge this pull request. * @@ -415,28 +356,4 @@ private void fetchIssue() throws IOException { fetchedIssueDetails = true; } } - - private static class DraftReviewComment { - private String body; - private String path; - private int position; - - public DraftReviewComment(String body, String path, int position) { - this.body = body; - this.path = path; - this.position = position; - } - - public String getBody() { - return body; - } - - public String getPath() { - return path; - } - - public int getPosition() { - return position; - } - } } diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReview.java b/src/main/java/org/kohsuke/github/GHPullRequestReview.java index 3bb155b881..45b6c044d9 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReview.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReview.java @@ -23,26 +23,98 @@ */ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +import javax.annotation.CheckForNull; import java.io.IOException; -import java.util.List; +import java.net.URL; /** - * Review to the pull request + * Review to a pull request. * * @see GHPullRequest#listReviews() - * @see GHPullRequest#createReview(String, String, GHPullRequestReviewEvent, List) + * @see GHPullRequestReviewBuilder */ -public class GHPullRequestReview extends GHPullRequestReviewAbstract { +@SuppressFBWarnings(value = {"UWF_UNWRITTEN_FIELD"}, justification = "JSON API") +public class GHPullRequestReview extends GHObject { + GHPullRequest owner; + + private String body; + private GHUser user; + private String commit_id; private GHPullRequestReviewState state; - @Override + /*package*/ GHPullRequestReview wrapUp(GHPullRequest owner) { + this.owner = owner; + return this; + } + + /** + * Gets the pull request to which this review is associated. + */ + public GHPullRequest getParent() { + return owner; + } + + /** + * The comment itself. + */ + public String getBody() { + return body; + } + + /** + * Gets the user who posted this review. + */ + public GHUser getUser() throws IOException { + return owner.root.getUser(user.getLogin()); + } + + public String getCommitId() { + return commit_id; + } + + @CheckForNull public GHPullRequestReviewState getState() { return state; } - GHPullRequestReview wrapUp(GHPullRequest owner) { - this.owner = owner; - return this; + @Override + public URL getHtmlUrl() { + return null; + } + + protected String getApiRoute() { + return owner.getApiRoute()+"/reviews/"+id; + } + + /** + * @deprecated + * Former preview method that changed when it got public. Left here for backward compatibility. + * Use {@link #submit(String, GHPullRequestReviewEvent)} + */ + public void submit(String body, GHPullRequestReviewState state) throws IOException { + submit(body,state.toEvent()); + } + + /** + * Updates the comment. + */ + public void submit(String body, GHPullRequestReviewEvent event) throws IOException { + new Requester(owner.root).method("POST") + .with("body", body) + .with("event", event.action()) + .to(getApiRoute()+"/events",this); + this.body = body; + this.state = event.toState(); + } + + /** + * Deletes this review. + */ + public void delete() throws IOException { + new Requester(owner.root).method("DELETE") + .to(getApiRoute()); } /** @@ -51,7 +123,26 @@ GHPullRequestReview wrapUp(GHPullRequest owner) { public void dismiss(String message) throws IOException { new Requester(owner.root).method("PUT") .with("message", message) - .to(getApiRoute() + "/dismissals"); + .to(getApiRoute()+"/dismissals"); state = GHPullRequestReviewState.DISMISSED; } + + /** + * Obtains all the review comments associated with this pull request review. + */ + public PagedIterable listReviewComments() throws IOException { + return new PagedIterable() { + public PagedIterator _iterator(int pageSize) { + return new PagedIterator( + owner.root.retrieve() + .asIterator(getApiRoute() + "/comments", + GHPullRequestReviewComment[].class, pageSize)) { + protected void wrapUp(GHPullRequestReviewComment[] page) { + for (GHPullRequestReviewComment c : page) + c.wrapUp(owner); + } + }; + } + }; + } } diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewAbstract.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewAbstract.java deleted file mode 100644 index 4842a62085..0000000000 --- a/src/main/java/org/kohsuke/github/GHPullRequestReviewAbstract.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2011, Eric Maupin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.kohsuke.github; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import java.io.IOException; -import java.net.URL; - -@SuppressFBWarnings(value = {"UWF_UNWRITTEN_FIELD"}, justification = "JSON API") -public abstract class GHPullRequestReviewAbstract extends GHObject { - protected GHPullRequest owner; - - protected String body; - private GHUser user; - private String commit_id; - - public abstract GHPullRequestReviewState getState(); - - /** - * Gets the pull request to which this review is associated. - */ - public GHPullRequest getParent() { - return owner; - } - - /** - * The comment itself. - */ - public String getBody() { - return body; - } - - /** - * Gets the user who posted this review. - */ - public GHUser getUser() throws IOException { - return owner.root.getUser(user.getLogin()); - } - - public String getCommitId() { - return commit_id; - } - - @Override - public URL getHtmlUrl() { - return null; - } - - String getApiRoute() { - return owner.getApiRoute() + "/reviews/" + id; - } - - /** - * Deletes this review. - */ - public void delete() throws IOException { - new Requester(owner.root).method("DELETE") - .to(getApiRoute()); - } - - /** - * Obtains all the review comments associated with this pull request review. - */ - public PagedIterable listReviewComments() { - return new PagedIterable() { - public PagedIterator _iterator(int pageSize) { - return new PagedIterator( - owner.root.retrieve() - .asIterator(getApiRoute() + "/comments", - GHPullRequestReviewComment[].class, pageSize)) { - protected void wrapUp(GHPullRequestReviewComment[] page) { - for (GHPullRequestReviewComment c : page) - c.wrapUp(owner); - } - }; - } - }; - } -} diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewBuilder.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewBuilder.java new file mode 100644 index 0000000000..625f6bd923 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewBuilder.java @@ -0,0 +1,91 @@ +package org.kohsuke.github; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Builds up a creation of new {@link GHPullRequestReview}. + * + * @author Kohsuke Kawaguchi + * @see GHPullRequest#createReview() + */ +public class GHPullRequestReviewBuilder { + private final GHPullRequest pr; + private final Requester builder; + private final List comments = new ArrayList(); + + /*package*/ GHPullRequestReviewBuilder(GHPullRequest pr) { + this.pr = pr; + this.builder = new Requester(pr.root); + } + + // public GHPullRequestReview createReview(@Nullable String commitId, String body, GHPullRequestReviewEvent event, + // List comments) throws IOException + + /** + * The SHA of the commit that needs a review. Not using the latest commit SHA may render your review comment outdated if a subsequent commit modifies the line you specify as the position. Defaults to the most recent commit in the pull request when you do not specify a value. + */ + public GHPullRequestReviewBuilder commitId(String commitId) { + builder.with("commit_id",commitId); + return this; + } + + /** + * Required when using REQUEST_CHANGES or COMMENT for the event parameter. The body text of the pull request review. + */ + public GHPullRequestReviewBuilder body(String body) { + builder.with("body",body); + return this; + } + + /** + * The review action you want to perform. The review actions include: APPROVE, REQUEST_CHANGES, or COMMENT. + * By leaving this blank, you set the review action state to PENDING, + * which means you will need to {@linkplain GHPullRequestReview#submit() submit the pull request review} when you are ready. + */ + public GHPullRequestReviewBuilder event(GHPullRequestReviewEvent event) { + builder.with("event",event.action()); + return this; + } + + /** + * @param body The relative path to the file that necessitates a review comment. + * @param path The position in the diff where you want to add a review comment. Note this value is not the same as the line number in the file. For help finding the position value, read the note below. + * @param position Text of the review comment. + */ + public GHPullRequestReviewBuilder comment(String body, String path, int position) { + comments.add(new DraftReviewComment(body,path,position)); + return this; + } + + public GHPullRequestReview create() throws IOException { + return builder.method("POST")._with("comments",comments) + .to(pr.getApiRoute() + "/reviews", GHPullRequestReview.class) + .wrapUp(pr); + } + + private static class DraftReviewComment { + private String body; + private String path; + private int position; + + DraftReviewComment(String body, String path, int position) { + this.body = body; + this.path = path; + this.position = position; + } + + public String getBody() { + return body; + } + + public String getPath() { + return path; + } + + public int getPosition() { + return position; + } + } +} diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java index 5ab8861f8d..811e15a4fc 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java @@ -124,6 +124,17 @@ public void delete() throws IOException { new Requester(owner.root).method("DELETE").to(getApiRoute()); } + /** + * Create a new comment that replies to this comment. + */ + public GHPullRequestReviewComment reply(String body) throws IOException { + return new Requester(owner.root).method("POST") + .with("body", body) + .with("in_reply_to", getId()) + .to(getApiRoute() + "/comments", GHPullRequestReviewComment.class) + .wrapUp(owner); + } + @Preview @Deprecated public GHReaction createReaction(ReactionContent content) throws IOException { return new Requester(owner.root) diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewDraft.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewDraft.java deleted file mode 100644 index 689d061bc0..0000000000 --- a/src/main/java/org/kohsuke/github/GHPullRequestReviewDraft.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2011, Eric Maupin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package org.kohsuke.github; - -import java.io.IOException; - -/** - * Draft of a Pull Request review. - * - * @see GHPullRequest#newDraftReview(String, String, GHPullRequestReviewComment...) - */ -public class GHPullRequestReviewDraft extends GHPullRequestReviewAbstract { - - GHPullRequestReviewDraft wrapUp(GHPullRequest owner) { - this.owner = owner; - return this; - } - - @Override - public GHPullRequestReviewState getState() { - return GHPullRequestReviewState.PENDING; - } - - public void submit(String body, GHPullRequestReviewEvent event) throws IOException { - new Requester(owner.root).method("POST") - .with("body", body) - .with("event", event.action()) - .to(getApiRoute() + "/events", this); - this.body = body; - } - -} diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewEvent.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewEvent.java index 4a5d66094f..e6537e0f09 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReviewEvent.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewEvent.java @@ -23,19 +23,29 @@ */ package org.kohsuke.github; +/** + * Action to perform on {@link GHPullRequestReview}. + */ public enum GHPullRequestReviewEvent { - PENDING(null), - APPROVE("APPROVE"), - REQUEST_CHANGES("REQUEST_CHANGES"), - COMMENT("COMMENT"); - - private final String _action; + PENDING, + APPROVE, + REQUEST_CHANGES, + COMMENT; - GHPullRequestReviewEvent(String action) { - _action = action; + /*package*/ String action() { + return this==PENDING ? null : name(); } - public String action() { - return _action; + /** + * When a {@link GHPullRequestReview} is submitted with this event, it should transition to this state. + */ + /*package*/ GHPullRequestReviewState toState() { + switch (this) { + case PENDING: return GHPullRequestReviewState.PENDING; + case APPROVE: return GHPullRequestReviewState.APPROVED; + case REQUEST_CHANGES: return GHPullRequestReviewState.CHANGES_REQUESTED; + case COMMENT: return GHPullRequestReviewState.COMMENTED; + } + throw new IllegalStateException(); } } diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java index eff7fbf60b..a64a105994 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java @@ -1,9 +1,39 @@ package org.kohsuke.github; +/** + * Current state of {@link GHPullRequestReview} + */ public enum GHPullRequestReviewState { PENDING, APPROVED, CHANGES_REQUESTED, + /** + * @deprecated + * This was the thing when this API was in preview, but it changed when it became public. + * Use {@link #CHANGES_REQUESTED}. Left here for compatibility. + */ + REQUEST_CHANGES, COMMENTED, - DISMISSED + DISMISSED; + + /** + * @deprecated + * This was an internal method accidentally exposed. + * Left here for compatibility. + */ + public String action() { + GHPullRequestReviewEvent e = toEvent(); + return e==null ? null : e.action(); + } + + /*package*/ GHPullRequestReviewEvent toEvent() { + switch (this) { + case PENDING: return GHPullRequestReviewEvent.PENDING; + case APPROVED: return GHPullRequestReviewEvent.APPROVE; + case CHANGES_REQUESTED: return GHPullRequestReviewEvent.REQUEST_CHANGES; + case REQUEST_CHANGES: return GHPullRequestReviewEvent.REQUEST_CHANGES; + case COMMENTED: return GHPullRequestReviewEvent.COMMENT; + } + return null; + } } diff --git a/src/main/java/org/kohsuke/github/Previews.java b/src/main/java/org/kohsuke/github/Previews.java index 2bc6dccbc8..3f98c3d4b9 100644 --- a/src/main/java/org/kohsuke/github/Previews.java +++ b/src/main/java/org/kohsuke/github/Previews.java @@ -8,5 +8,4 @@ static final String DRAX = "application/vnd.github.drax-preview+json"; static final String SQUIRREL_GIRL = "application/vnd.github.squirrel-girl-preview"; static final String CLOAK = "application/vnd.github.cloak-preview"; - static final String BLACK_CAT = "application/vnd.github.black-cat-preview+json"; } diff --git a/src/test/java/org/kohsuke/github/PullRequestTest.java b/src/test/java/org/kohsuke/github/PullRequestTest.java index 97826baea0..c2a6a2705e 100644 --- a/src/test/java/org/kohsuke/github/PullRequestTest.java +++ b/src/test/java/org/kohsuke/github/PullRequestTest.java @@ -7,8 +7,7 @@ import java.util.Collection; import java.util.List; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.*; /** * @author Kohsuke Kawaguchi @@ -33,9 +32,10 @@ public void createPullRequestComment() throws Exception { public void testPullRequestReviews() throws Exception { String name = rnd.next(); GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test"); - GHPullRequestReviewDraft draftReview = p.newDraftReview(null, "Some draft review", - GHPullRequestReviewComment.draft("Some niggle", "changelog.html", 1) - ); + GHPullRequestReview draftReview = p.createReview() + .body("Some draft review") + .comment("Some niggle", "changelog.html", 1) + .create(); assertThat(draftReview.getState(), is(GHPullRequestReviewState.PENDING)); assertThat(draftReview.getBody(), is("Some draft review")); assertThat(draftReview.getCommitId(), notNullValue()); @@ -50,9 +50,10 @@ public void testPullRequestReviews() throws Exception { assertEquals(1, comments.size()); GHPullRequestReviewComment comment = comments.get(0); assertEquals("Some niggle", comment.getBody()); - draftReview = p.newDraftReview(null, "Some new review", - GHPullRequestReviewComment.draft("Some niggle", "changelog.html", 1) - ); + draftReview = p.createReview() + .body("Some new review") + .comment("Some niggle", "changelog.html", 1) + .create(); draftReview.delete(); } From f41da19db557aaef65b24bec1333d52aeb87061a Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 13 Jan 2018 09:54:14 -0800 Subject: [PATCH 23/25] Further restoration of the compatibility --- .../org/kohsuke/github/GHPullRequest.java | 25 +++++++++++++++++++ .../github/GHPullRequestReviewComment.java | 17 +++++++------ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 4e9f1e7e93..b5f02b964c 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -23,10 +23,13 @@ */ package org.kohsuke.github; +import javax.annotation.CheckForNull; import java.io.IOException; import java.net.URL; +import java.util.Arrays; import java.util.Collection; import java.util.Date; +import java.util.List; /** * A pull request. @@ -307,6 +310,28 @@ protected void wrapUp(GHPullRequestCommitDetail[] page) { }; } + /** + * @deprecated + * Use {@link #createReview()} + */ + public GHPullRequestReview createReview(String body, @CheckForNull GHPullRequestReviewState event, + GHPullRequestReviewComment... comments) throws IOException { + return createReview(body, event, Arrays.asList(comments)); + } + + /** + * @deprecated + * Use {@link #createReview()} + */ + public GHPullRequestReview createReview(String body, @CheckForNull GHPullRequestReviewState event, + List comments) throws IOException { + GHPullRequestReviewBuilder b = createReview().body(body); + for (GHPullRequestReviewComment c : comments) { + b.comment(c.getBody(), c.getPath(), c.getPosition()); + } + return b.create(); + } + public GHPullRequestReviewBuilder createReview() { return new GHPullRequestReviewBuilder(this); } diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java index 811e15a4fc..5cda4abb0a 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java @@ -47,6 +47,10 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable { private long in_reply_to_id = -1L; + /** + * @deprecated + * You should be using {@link GHPullRequestReviewBuilder#comment(String, String, int)} + */ public static GHPullRequestReviewComment draft(String body, String path, int position) { GHPullRequestReviewComment result = new GHPullRequestReviewComment(); result.body = body; @@ -86,18 +90,17 @@ public String getPath() { } @CheckForNull - public Integer getPosition() { - return position == -1 ? null : position; + public int getPosition() { + return position; } - @CheckForNull - public Integer getOriginalPosition() { - return original_position == -1 ? null : original_position; + public int getOriginalPosition() { + return original_position; } @CheckForNull - public Long getInReplyToId() { - return in_reply_to_id == -1 ? null : in_reply_to_id; + public long getInReplyToId() { + return in_reply_to_id; } @Override From e10b747d6a241dc404d42a818dafffa1dbf2c195 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 13 Jan 2018 10:30:48 -0800 Subject: [PATCH 24/25] Re-retried the object. It looks like the format has changed a bit since this payload was retrieved originally? --- .../java/org/kohsuke/github/GHEventPayloadTest.java | 4 ++-- .../GHEventPayloadTest/pull_request_review.json | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/test/java/org/kohsuke/github/GHEventPayloadTest.java b/src/test/java/org/kohsuke/github/GHEventPayloadTest.java index d2ff30012f..71f9fd3e68 100644 --- a/src/test/java/org/kohsuke/github/GHEventPayloadTest.java +++ b/src/test/java/org/kohsuke/github/GHEventPayloadTest.java @@ -193,8 +193,8 @@ public void pull_request_review() throws Exception { GitHub.offline().parseEventPayload(payload.asReader(), GHEventPayload.PullRequestReview.class); assertThat(event.getAction(), is("submitted")); - assertThat(event.getReview().getId(), is(2626884)); - assertThat(event.getReview().getBody(), is("Looks great!")); + assertThat(event.getReview().getId(), is(2626884L)); + assertThat(event.getReview().getBody(), is("Looks great!\n")); assertThat(event.getReview().getState(), is(GHPullRequestReviewState.APPROVED)); assertThat(event.getPullRequest().getNumber(), is(8)); diff --git a/src/test/resources/org/kohsuke/github/GHEventPayloadTest/pull_request_review.json b/src/test/resources/org/kohsuke/github/GHEventPayloadTest/pull_request_review.json index 82c8396086..dd6698c3ac 100644 --- a/src/test/resources/org/kohsuke/github/GHEventPayloadTest/pull_request_review.json +++ b/src/test/resources/org/kohsuke/github/GHEventPayloadTest/pull_request_review.json @@ -5,7 +5,7 @@ "user": { "login": "baxterthehacker", "id": 6752317, - "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3", + "avatar_url": "https://avatars3.githubusercontent.com/u/6752317?v=4", "gravatar_id": "", "url": "https://api.github.com/users/baxterthehacker", "html_url": "https://github.com/baxterthehacker", @@ -21,11 +21,11 @@ "type": "User", "site_admin": false }, - "body": "Looks great!", - "submitted_at": "2016-10-03T23:39:09Z", - "state": "approved", + "body": "Looks great!\n", + "state": "APPROVED", "html_url": "https://github.com/baxterthehacker/public-repo/pull/8#pullrequestreview-2626884", "pull_request_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/8", + "author_association": "OWNER", "_links": { "html": { "href": "https://github.com/baxterthehacker/public-repo/pull/8#pullrequestreview-2626884" @@ -33,7 +33,9 @@ "pull_request": { "href": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/8" } - } + }, + "submitted_at": "2016-10-03T23:39:09Z", + "commit_id": "b7a1f9c27caa4e03c14a88feb56e2d4f7500aa63" }, "pull_request": { "url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/8", From 188245fa7fbf09048df6c57d1763353ca24f94ad Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 13 Jan 2018 10:36:45 -0800 Subject: [PATCH 25/25] [maven-release-plugin] prepare release github-api-1.91 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a941d38b75..1d7427dbb2 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.91-SNAPSHOT + 1.91 GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java @@ -16,7 +16,7 @@ scm:git:git@github.com/kohsuke/${project.artifactId}.git scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git http://${project.artifactId}.kohsuke.org/ - HEAD + github-api-1.91