diff --git a/pom.xml b/pom.xml
index bc4e873120..1d7427dbb2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
github-api
- 1.90
+ 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/
- github-api-1.90
+ github-api-1.91
@@ -131,6 +131,7 @@
com.infradna.tool
bridge-method-annotation
1.17
+ true
org.kohsuke.stapler
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
*
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/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/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);
}
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);
diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java
index 9342623829..b5f02b964c 100644
--- a/src/main/java/org/kohsuke/github/GHPullRequest.java
+++ b/src/main/java/org/kohsuke/github/GHPullRequest.java
@@ -26,23 +26,22 @@
import javax.annotation.CheckForNull;
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.
- *
+ *
* @author Kohsuke Kawaguchi
* @see GHRepository#getPullRequest(int)
*/
@SuppressWarnings({"UnusedDeclaration"})
public class GHPullRequest extends GHIssue {
+ private static final String COMMENTS_ACTION = "/comments";
+
private String patch_url, diff_url, issue_url;
private GHCommitPointer base;
private String merged_at;
@@ -91,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
@@ -114,7 +113,7 @@ public GHCommitPointer getBase() {
public GHCommitPointer getHead() {
return head;
}
-
+
@Deprecated
public Date getIssueUpdatedAt() throws IOException {
return super.getUpdatedAt();
@@ -182,8 +181,17 @@ 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.
+ * 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;
}
@@ -217,6 +225,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
}
@@ -246,7 +261,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
@@ -266,7 +280,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)
@@ -296,32 +310,30 @@ protected void wrapUp(GHPullRequestCommitDetail[] page) {
};
}
- @Preview
- @Deprecated
+ /**
+ * @deprecated
+ * Use {@link #createReview()}
+ */
public GHPullRequestReview createReview(String body, @CheckForNull GHPullRequestReviewState event,
- GHPullRequestReviewComment... comments)
- throws IOException {
+ GHPullRequestReviewComment... comments) throws IOException {
return createReview(body, event, Arrays.asList(comments));
}
- @Preview
- @Deprecated
+ /**
+ * @deprecated
+ * Use {@link #createReview()}
+ */
public GHPullRequestReview createReview(String body, @CheckForNull GHPullRequestReviewState event,
- List comments)
- throws IOException {
-// if (event == null) {
-// event = GHPullRequestReviewState.PENDING;
-// }
- List draftComments = new ArrayList(comments.size());
+ List comments) throws IOException {
+ GHPullRequestReviewBuilder b = createReview().body(body);
for (GHPullRequestReviewComment c : comments) {
- draftComments.add(new DraftReviewComment(c.getBody(), c.getPath(), c.getPosition()));
+ b.comment(c.getBody(), c.getPath(), c.getPosition());
}
- 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 b.create();
+ }
+
+ public GHPullRequestReviewBuilder createReview() {
+ return new GHPullRequestReviewBuilder(this);
}
public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position) throws IOException {
@@ -330,7 +342,7 @@ public GHPullRequestReviewComment createReviewComment(String body, String sha, S
.with("commit_id", sha)
.with("path", path)
.with("position", position)
- .to(getApiRoute() + "/comments", GHPullRequestReviewComment.class).wrapUp(this);
+ .to(getApiRoute() + COMMENTS_ACTION, GHPullRequestReviewComment.class).wrapUp(this);
}
/**
@@ -371,10 +383,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 }
@@ -385,28 +397,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 d7afe59aad..45b6c044d9 100644
--- a/src/main/java/org/kohsuke/github/GHPullRequestReview.java
+++ b/src/main/java/org/kohsuke/github/GHPullRequestReview.java
@@ -23,17 +23,19 @@
*/
package org.kohsuke.github;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+import javax.annotation.CheckForNull;
import java.io.IOException;
import java.net.URL;
-import static org.kohsuke.github.Previews.*;
-
/**
- * Review to the pull request
+ * Review to a pull request.
*
* @see GHPullRequest#listReviews()
- * @see GHPullRequest#createReview(String, GHPullRequestReviewState, GHPullRequestReviewComment...)
+ * @see GHPullRequestReviewBuilder
*/
+@SuppressFBWarnings(value = {"UWF_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHPullRequestReview extends GHObject {
GHPullRequest owner;
@@ -72,6 +74,7 @@ public String getCommitId() {
return commit_id;
}
+ @CheckForNull
public GHPullRequestReviewState getState() {
return state;
}
@@ -85,41 +88,41 @@ 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.
*/
- @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;
+ this.state = event.toState();
}
/**
* Deletes this review.
*/
- @Preview
- @Deprecated
public void delete() throws IOException {
new Requester(owner.root).method("DELETE")
- .withPreview(BLACK_CAT)
.to(getApiRoute());
}
/**
* 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");
state = GHPullRequestReviewState.DISMISSED;
}
@@ -127,14 +130,11 @@ public void dismiss(String message) throws IOException {
/**
* 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) {
@@ -145,5 +145,4 @@ protected void wrapUp(GHPullRequestReviewComment[] page) {
}
};
}
-
}
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 33097bc29d..5cda4abb0a 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,9 +42,15 @@ 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;
+ 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;
@@ -82,12 +89,18 @@ public String getPath() {
return path;
}
+ @CheckForNull
public int getPosition() {
return position;
}
public int getOriginalPosition() {
- return originalPosition;
+ return original_position;
+ }
+
+ @CheckForNull
+ public long getInReplyToId() {
+ return in_reply_to_id;
}
@Override
@@ -114,6 +127,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)
@@ -126,7 +150,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)
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..e6537e0f09
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewEvent.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+/**
+ * Action to perform on {@link GHPullRequestReview}.
+ */
+public enum GHPullRequestReviewEvent {
+ PENDING,
+ APPROVE,
+ REQUEST_CHANGES,
+ COMMENT;
+
+ /*package*/ String action() {
+ return this==PENDING ? null : name();
+ }
+
+ /**
+ * 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 fca3fabfb3..a64a105994 100644
--- a/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java
+++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewState.java
@@ -1,19 +1,39 @@
package org.kohsuke.github;
+/**
+ * Current state of {@link GHPullRequestReview}
+ */
public enum GHPullRequestReviewState {
- PENDING(null),
- APPROVED("APPROVE"),
- REQUEST_CHANGES("REQUEST_CHANGES"),
- COMMENTED("COMMENT"),
- DISMISSED(null);
+ 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;
- private final String _action;
-
- GHPullRequestReviewState(String action) {
- _action = action;
+ /**
+ * @deprecated
+ * This was an internal method accidentally exposed.
+ * Left here for compatibility.
+ */
+ public String action() {
+ GHPullRequestReviewEvent e = toEvent();
+ return e==null ? null : e.action();
}
- public String action() {
- return _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/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;
}
diff --git a/src/main/java/org/kohsuke/github/GHTeam.java b/src/main/java/org/kohsuke/github/GHTeam.java
index ae950aed70..bccec4b5ed 100644
--- a/src/main/java/org/kohsuke/github/GHTeam.java
+++ b/src/main/java/org/kohsuke/github/GHTeam.java
@@ -18,6 +18,18 @@ public class GHTeam {
protected /*final*/ GHOrganization org;
+ /** Member's role in a team */
+ 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;
return this;
@@ -116,6 +128,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 +157,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 +173,7 @@ public void delete() throws IOException {
}
private String api(String tail) {
- return "/teams/"+id+tail;
+ return "/teams/" + id + tail;
}
public GHOrganization getOrganization() {
diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java
index 67fc1f8fe4..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;
@@ -424,6 +423,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 +435,35 @@ public GHOrganization getOrganization(String name) throws IOException {
return o;
}
+ /**
+ * Gets a list of all organizations.
+ */
+ public PagedIterable listOrganizations() {
+ return listOrganizations(null);
+ }
+
+ /**
+ * Gets a list of all organizations starting after the organization identifier specified by 'since'.
+ *
+ * @see List All Orgs - Parameters
+ */
+ public PagedIterable listOrganizations(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/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/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java
index 00f11f2426..899597b33e 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.
@@ -134,6 +135,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);
@@ -452,7 +457,7 @@ private boolean isMethodWithBody() {
try {
return new PagingIterator(type, tailApiUrl, root.getApiURL(s.toString()));
} catch (IOException e) {
- throw new Error(e);
+ throw new GHException("Unable to build github Api URL",e);
}
}
@@ -513,7 +518,7 @@ private void fetch() {
}
}
} catch (IOException e) {
- throw new Error(e);
+ throw new GHException("Failed to retrieve "+url);
}
}
diff --git a/src/test/java/org/kohsuke/github/GHEventPayloadTest.java b/src/test/java/org/kohsuke/github/GHEventPayloadTest.java
index 07758d1a03..71f9fd3e68 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(2626884L));
+ assertThat(event.getReview().getBody(), is("Looks great!\n"));
+ 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 {
diff --git a/src/test/java/org/kohsuke/github/GitHubTest.java b/src/test/java/org/kohsuke/github/GitHubTest.java
index a418db5fde..f4b77b8271 100644
--- a/src/test/java/org/kohsuke/github/GitHubTest.java
+++ b/src/test/java/org/kohsuke/github/GitHubTest.java
@@ -5,11 +5,14 @@
import java.lang.reflect.Field;
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;
+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 +158,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.listOrganizations().withPageSize(2), iterations)) {
+ orgIds.add(org.getId());
+ System.out.println(org.getName());
+ }
+ assertThat(orgIds.size(), equalTo(iterations));
+ }
}
diff --git a/src/test/java/org/kohsuke/github/PullRequestTest.java b/src/test/java/org/kohsuke/github/PullRequestTest.java
index 5ea2628303..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");
- GHPullRequestReview draftReview = p.createReview("Some draft review", null,
- 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());
@@ -45,15 +45,16 @@ 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);
+ 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,
- GHPullRequestReviewComment.draft("Some niggle", "changelog.html", 1)
- );
- review.delete();
+ draftReview = p.createReview()
+ .body("Some new review")
+ .comment("Some niggle", "changelog.html", 1)
+ .create();
+ draftReview.delete();
}
@Test
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",