diff --git a/pom.xml b/pom.xml
index 992c9ef281..3c04540ce0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
github-api
- 1.68
+ 1.69
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.68
+ github-api-1.69
@@ -44,6 +44,25 @@
+
+ org.codehaus.mojo
+ findbugs-maven-plugin
+ 3.0.1
+
+ true
+ true
+ false
+
+
+
+ run-findbugs
+ verify
+
+ check
+
+
+
+
@@ -109,6 +128,12 @@
1.9.5
test
+
+ com.google.code.findbugs
+ annotations
+ 3.0.0
+ provided
+
diff --git a/src/main/java/org/kohsuke/github/GHBranch.java b/src/main/java/org/kohsuke/github/GHBranch.java
index 1c68bfa758..9c3d331adc 100644
--- a/src/main/java/org/kohsuke/github/GHBranch.java
+++ b/src/main/java/org/kohsuke/github/GHBranch.java
@@ -40,7 +40,8 @@ public String getSHA1() {
@Override
public String toString() {
- return "Branch:" + name + " in " + owner.getUrl();
+ final String url = owner != null ? owner.getUrl().toString() : "unknown";
+ return "Branch:" + name + " in " + url;
}
/*package*/ GHBranch wrap(GHRepository repo) {
diff --git a/src/main/java/org/kohsuke/github/GHCommit.java b/src/main/java/org/kohsuke/github/GHCommit.java
index fbb7c24fdd..ce56cddd6b 100644
--- a/src/main/java/org/kohsuke/github/GHCommit.java
+++ b/src/main/java/org/kohsuke/github/GHCommit.java
@@ -70,7 +70,8 @@ public static class Stats {
public static class File {
String status;
int changes,additions,deletions;
- String raw_url, blob_url, filename, sha, patch;
+ String raw_url, blob_url, sha, patch;
+ String filename, previous_filename;
/**
* Number of lines added + removed.
@@ -101,12 +102,19 @@ public String getStatus() {
}
/**
- * Just the base name and the extension without any directory name.
+ * Full path in the repository.
*/
public String getFileName() {
return filename;
}
+ /**
+ * Previous path, in case file has moved.
+ */
+ public String getPreviousFilename() {
+ return previous_filename;
+ }
+
/**
* The actual change.
*/
diff --git a/src/main/java/org/kohsuke/github/GHEvent.java b/src/main/java/org/kohsuke/github/GHEvent.java
index 13ef432f8f..9e172146ae 100644
--- a/src/main/java/org/kohsuke/github/GHEvent.java
+++ b/src/main/java/org/kohsuke/github/GHEvent.java
@@ -23,12 +23,15 @@ public enum GHEvent {
ISSUE_COMMENT,
ISSUES,
MEMBER,
+ PAGE_BUILD,
PUBLIC,
PULL_REQUEST,
PULL_REQUEST_REVIEW_COMMENT,
PUSH,
RELEASE,
+ REPOSITORY, // only valid for org hooks
STATUS,
TEAM_ADD,
- WATCH
+ WATCH,
+ PING
}
diff --git a/src/main/java/org/kohsuke/github/GHEventPayload.java b/src/main/java/org/kohsuke/github/GHEventPayload.java
index cd248c80ec..e60fa40193 100644
--- a/src/main/java/org/kohsuke/github/GHEventPayload.java
+++ b/src/main/java/org/kohsuke/github/GHEventPayload.java
@@ -104,8 +104,12 @@ public void setRepository(GHRepository repository) {
@Override
void wrapUp(GitHub root) {
super.wrapUp(root);
- repository.wrap(root);
- issue.wrap(repository);
+ if (repository != null) {
+ repository.wrap(root);
+ issue.wrap(repository);
+ } else {
+ issue.wrap(root);
+ }
comment.wrapUp(issue);
}
}
diff --git a/src/main/java/org/kohsuke/github/GHHook.java b/src/main/java/org/kohsuke/github/GHHook.java
index ffe4837509..ce8c8a4dfd 100644
--- a/src/main/java/org/kohsuke/github/GHHook.java
+++ b/src/main/java/org/kohsuke/github/GHHook.java
@@ -11,22 +11,12 @@
/**
* @author Kohsuke Kawaguchi
*/
-public class GHHook extends GHObject {
- /**
- * Repository that the hook belongs to.
- */
- /*package*/ transient GHRepository repository;
-
+public abstract class GHHook extends GHObject {
String name;
List events;
boolean active;
Map config;
- /*package*/ GHHook wrap(GHRepository owner) {
- this.repository = owner;
- return this;
- }
-
public String getName() {
return name;
}
@@ -50,7 +40,7 @@ public Map getConfig() {
* Deletes this hook.
*/
public void delete() throws IOException {
- new Requester(repository.root).method("DELETE").to(String.format("/repos/%s/%s/hooks/%d", repository.getOwnerName(), repository.getName(), id));
+ new Requester(getRoot()).method("DELETE").to(getApiRoute());
}
/**
@@ -60,4 +50,8 @@ public void delete() throws IOException {
public URL getHtmlUrl() {
return null;
}
+
+ abstract GitHub getRoot();
+
+ abstract String getApiRoute();
}
diff --git a/src/main/java/org/kohsuke/github/GHHooks.java b/src/main/java/org/kohsuke/github/GHHooks.java
new file mode 100644
index 0000000000..1a6154aa6d
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/GHHooks.java
@@ -0,0 +1,130 @@
+package org.kohsuke.github;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Utility class for creating and retrieving webhooks; removes duplication between GHOrganization and GHRepository
+ * functionality
+ */
+class GHHooks {
+ static abstract class Context {
+ private final GitHub root;
+
+ private Context(GitHub root) {
+ this.root = root;
+ }
+
+ public List getHooks() throws IOException {
+ List list = new ArrayList(Arrays.asList(
+ root.retrieve().to(collection(), collectionClass())));
+ for (GHHook h : list)
+ wrap(h);
+ return list;
+ }
+
+ public GHHook getHook(int id) throws IOException {
+ GHHook hook = root.retrieve().to(collection() + "/" + id, clazz());
+ return wrap(hook);
+ }
+
+ public GHHook createHook(String name, Map config, Collection events, boolean active) throws IOException {
+ List ea = null;
+ if (events!=null) {
+ ea = new ArrayList();
+ for (GHEvent e : events)
+ ea.add(e.name().toLowerCase(Locale.ENGLISH));
+ }
+
+ GHHook hook = new Requester(root)
+ .with("name", name)
+ .with("active", active)
+ ._with("config", config)
+ ._with("events", ea)
+ .to(collection(), clazz());
+
+ return wrap(hook);
+ }
+
+ abstract String collection();
+
+ abstract Class extends GHHook[]> collectionClass();
+
+ abstract Class extends GHHook> clazz();
+
+ abstract GHHook wrap(GHHook hook);
+ }
+
+ private static class RepoContext extends Context {
+ private final GHRepository repository;
+ private final GHUser owner;
+
+ private RepoContext(GHRepository repository, GHUser owner) {
+ super(repository.root);
+ this.repository = repository;
+ this.owner = owner;
+ }
+
+ @Override
+ String collection() {
+ return String.format("/repos/%s/%s/hooks", owner.getLogin(), repository.getName());
+ }
+
+ @Override
+ Class extends GHHook[]> collectionClass() {
+ return GHRepoHook[].class;
+ }
+
+ @Override
+ Class extends GHHook> clazz() {
+ return GHRepoHook.class;
+ }
+
+ @Override
+ GHHook wrap(GHHook hook) {
+ return ((GHRepoHook)hook).wrap(repository);
+ }
+ }
+
+ private static class OrgContext extends Context {
+ private final GHOrganization organization;
+
+ private OrgContext(GHOrganization organization) {
+ super(organization.root);
+ this.organization = organization;
+ }
+
+ @Override
+ String collection() {
+ return String.format("/orgs/%s/hooks", organization.getLogin());
+ }
+
+ @Override
+ Class extends GHHook[]> collectionClass() {
+ return GHOrgHook[].class;
+ }
+
+ @Override
+ Class extends GHHook> clazz() {
+ return GHOrgHook.class;
+ }
+
+ @Override
+ GHHook wrap(GHHook hook) {
+ return ((GHOrgHook)hook).wrap(organization);
+ }
+ }
+
+ static Context repoContext(GHRepository repository, GHUser owner) {
+ return new RepoContext(repository, owner);
+ }
+
+ static Context orgContext(GHOrganization organization) {
+ return new OrgContext(organization);
+ }
+}
diff --git a/src/main/java/org/kohsuke/github/GHIssue.java b/src/main/java/org/kohsuke/github/GHIssue.java
index 8c071a93f8..e7864087dd 100644
--- a/src/main/java/org/kohsuke/github/GHIssue.java
+++ b/src/main/java/org/kohsuke/github/GHIssue.java
@@ -24,6 +24,8 @@
package org.kohsuke.github;
+import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
+
import java.io.IOException;
import java.net.URL;
import java.util.Collection;
@@ -140,9 +142,14 @@ public URL getApiURL(){
/**
* Updates the issue by adding a comment.
+ *
+ * @return
+ * Newly posted comment.
*/
- public void comment(String message) throws IOException {
- new Requester(root).with("body",message).to(getIssuesApiRoute() + "/comments");
+ @WithBridgeMethods(void.class)
+ public GHIssueComment comment(String message) throws IOException {
+ GHIssueComment r = new Requester(root).with("body",message).to(getIssuesApiRoute() + "/comments", GHIssueComment.class);
+ return r.wrapUp(this);
}
private void edit(String key, Object value) throws IOException {
@@ -176,7 +183,7 @@ public void setBody(String body) throws IOException {
}
public void assignTo(GHUser user) throws IOException {
- editIssue("assignee",user.getLogin());
+ editIssue("assignee", user.getLogin());
}
public void setLabels(String... labels) throws IOException {
diff --git a/src/main/java/org/kohsuke/github/GHIssueComment.java b/src/main/java/org/kohsuke/github/GHIssueComment.java
index 732c508a2d..3179fa93a6 100644
--- a/src/main/java/org/kohsuke/github/GHIssueComment.java
+++ b/src/main/java/org/kohsuke/github/GHIssueComment.java
@@ -25,7 +25,6 @@
import java.io.IOException;
import java.net.URL;
-import java.util.Date;
/**
* Comment to the issue
@@ -79,4 +78,23 @@ public GHUser getUser() throws IOException {
public URL getHtmlUrl() {
return null;
}
+
+ /**
+ * Updates the body of the issue comment.
+ */
+ public void update(String body) throws IOException {
+ new Requester(owner.root).with("body", body).method("PATCH").to(getApiRoute(), GHIssueComment.class);
+ this.body = body;
+ }
+
+ /**
+ * Deletes this issue comment.
+ */
+ public void delete() throws IOException {
+ new Requester(owner.root).method("DELETE").to(getApiRoute());
+ }
+
+ private String getApiRoute() {
+ return "/repos/"+owner.getRepository().getOwnerName()+"/"+owner.getRepository().getName()+"/issues/comments/" + id;
+ }
}
diff --git a/src/main/java/org/kohsuke/github/GHMyself.java b/src/main/java/org/kohsuke/github/GHMyself.java
index 7b588e88fa..2041336367 100644
--- a/src/main/java/org/kohsuke/github/GHMyself.java
+++ b/src/main/java/org/kohsuke/github/GHMyself.java
@@ -5,7 +5,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -17,6 +16,33 @@
* @author Kohsuke Kawaguchi
*/
public class GHMyself extends GHUser {
+
+ /**
+ * Type of repositories returned during listing.
+ */
+ public enum RepositoryListFilter {
+ /**
+ * All public and private repositories that current user has access or collaborates to
+ */
+ ALL,
+ /**
+ * Public and private repositories owned by current user
+ */
+ OWNER,
+ /**
+ * Public repositories that current user has access or collaborates to
+ */
+ PUBLIC,
+ /**
+ * Private repositories that current user has access or collaborates to
+ */
+ PRIVATE,
+ /**
+ * Public and private repositories that current user is a member
+ */
+ MEMBER;
+ }
+
/**
* @deprecated
* Use {@link #getEmails2()}
@@ -109,16 +135,31 @@ public PagedIterable listRepositories() {
}
/**
- * Lists up all the repositories this user owns (public and private) using the specified page size.
+ * List repositories that are accessible to the authenticated user (public and private) using the specified page size.
+ *
+ * This includes repositories owned by the authenticated user, repositories that belong to other users
+ * where the authenticated user is a collaborator, and other organizations' repositories that the authenticated
+ * user has access to through an organization membership.
*
* @param pageSize size for each page of items returned by GitHub. Maximum page size is 100.
*
* Unlike {@link #getRepositories()}, this does not wait until all the repositories are returned.
*/
public PagedIterable listRepositories(final int pageSize) {
+ return listRepositories(pageSize, RepositoryListFilter.ALL);
+ }
+
+ /**
+ * List repositories of a certain type that are accessible by current authenticated user using the specified page size.
+ *
+ * @param pageSize size for each page of items returned by GitHub. Maximum page size is 100.
+ * @param repoType type of repository returned in the listing
+ */
+ public PagedIterable listRepositories(final int pageSize, final RepositoryListFilter repoType) {
return new PagedIterable() {
public PagedIterator iterator() {
- return new PagedIterator(root.retrieve().asIterator("/user/repos?per_page=" + pageSize, GHRepository[].class)) {
+ return new PagedIterator(root.retrieve().asIterator("/user/repos?per_page=" + pageSize +
+ "&type=" + repoType.name().toLowerCase(), GHRepository[].class)) {
@Override
protected void wrapUp(GHRepository[] page) {
for (GHRepository c : page)
diff --git a/src/main/java/org/kohsuke/github/GHOrgHook.java b/src/main/java/org/kohsuke/github/GHOrgHook.java
new file mode 100644
index 0000000000..58404019bf
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/GHOrgHook.java
@@ -0,0 +1,27 @@
+/*
+ * © Copyright 2015 - SourceClear Inc
+ */
+
+package org.kohsuke.github;
+
+class GHOrgHook extends GHHook {
+ /**
+ * Organization that the hook belongs to.
+ */
+ /*package*/ transient GHOrganization organization;
+
+ /*package*/ GHOrgHook wrap(GHOrganization owner) {
+ this.organization = owner;
+ return this;
+ }
+
+ @Override
+ GitHub getRoot() {
+ return organization.root;
+ }
+
+ @Override
+ String getApiRoute() {
+ return String.format("/orgs/%s/hooks/%d", organization.getLogin(), id);
+ }
+}
diff --git a/src/main/java/org/kohsuke/github/GHOrganization.java b/src/main/java/org/kohsuke/github/GHOrganization.java
index 0680ca39ca..4409dafaaa 100644
--- a/src/main/java/org/kohsuke/github/GHOrganization.java
+++ b/src/main/java/org/kohsuke/github/GHOrganization.java
@@ -1,10 +1,13 @@
package org.kohsuke.github;
import java.io.IOException;
+import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
@@ -26,7 +29,7 @@ public GHRepository createRepository(String name, String description, String hom
GHTeam t = getTeams().get(team);
if (t==null)
throw new IllegalArgumentException("No such team: "+team);
- return createRepository(name,description,homepage,t,isPublic);
+ return createRepository(name, description, homepage, t, isPublic);
}
public GHRepository createRepository(String name, String description, String homepage, GHTeam team, boolean isPublic) throws IOException {
@@ -252,4 +255,39 @@ protected void wrapUp(GHRepository[] page) {
}
};
}
+
+ /**
+ * Retrieves the currently configured hooks.
+ */
+ public List getHooks() throws IOException {
+ return GHHooks.orgContext(this).getHooks();
+ }
+
+ public GHHook getHook(int id) throws IOException {
+ return GHHooks.orgContext(this).getHook(id);
+ }
+
+ /**
+ *
+ * See https://api.github.com/hooks for possible names and their configuration scheme.
+ * TODO: produce type-safe binding
+ *
+ * @param name
+ * Type of the hook to be created. See https://api.github.com/hooks for possible names.
+ * @param config
+ * The configuration hash.
+ * @param events
+ * Can be null. Types of events to hook into.
+ */
+ public GHHook createHook(String name, Map config, Collection events, boolean active) throws IOException {
+ return GHHooks.orgContext(this).createHook(name, config, events, active);
+ }
+
+ public GHHook createWebHook(URL url, Collection events) throws IOException {
+ return createHook("web", Collections.singletonMap("url", url.toExternalForm()),events,true);
+ }
+
+ public GHHook createWebHook(URL url) throws IOException {
+ return createWebHook(url, null);
+ }
}
diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java
index 09863f78cf..8cb497e16a 100644
--- a/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java
+++ b/src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java
@@ -86,7 +86,7 @@ public URL getHtmlUrl() {
}
protected String getApiRoute() {
- return "/repos/"+owner.getRepository().getFullName()+"/comments/"+id;
+ return "/repos/"+owner.getRepository().getFullName()+"/pulls/comments/"+id;
}
/**
@@ -94,6 +94,7 @@ protected String getApiRoute() {
*/
public void update(String body) throws IOException {
new Requester(owner.root).method("PATCH").with("body", body).to(getApiRoute(),this);
+ this.body = body;
}
/**
diff --git a/src/main/java/org/kohsuke/github/GHRepoHook.java b/src/main/java/org/kohsuke/github/GHRepoHook.java
new file mode 100644
index 0000000000..948438eb96
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/GHRepoHook.java
@@ -0,0 +1,23 @@
+package org.kohsuke.github;
+
+class GHRepoHook extends GHHook {
+ /**
+ * Repository that the hook belongs to.
+ */
+ /*package*/ transient GHRepository repository;
+
+ /*package*/ GHRepoHook wrap(GHRepository owner) {
+ this.repository = owner;
+ return this;
+ }
+
+ @Override
+ GitHub getRoot() {
+ return repository.root;
+ }
+
+ @Override
+ String getApiRoute() {
+ return String.format("/repos/%s/%s/hooks/%d", repository.getOwnerName(), repository.getName(), id);
+ }
+}
diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java
index e4459e84d6..5acf0a648b 100644
--- a/src/main/java/org/kohsuke/github/GHRepository.java
+++ b/src/main/java/org/kohsuke/github/GHRepository.java
@@ -40,7 +40,7 @@
/**
* A repository on GitHub.
- *
+ *
* @author Kohsuke Kawaguchi
*/
@SuppressWarnings({"UnusedDeclaration"})
@@ -57,14 +57,14 @@ public class GHRepository extends GHObject {
private int watchers,forks,open_issues,size,network_count,subscribers_count;
private String pushed_at;
private Map milestones = new HashMap();
-
+
private String default_branch,language;
private Map commits = new HashMap();
private GHRepoPermission permissions;
private GHRepository source, parent;
-
+
public GHDeploymentBuilder createDeployment(String ref) {
return new GHDeploymentBuilder(this,ref);
}
@@ -164,7 +164,7 @@ public String getSshUrl() {
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
-
+
/**
* Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins
*/
@@ -321,6 +321,10 @@ public boolean isFork() {
return fork;
}
+ /**
+ * Returns the number of all forks of this repository.
+ * This not only counts direct forks, but also forks of forks, and so on.
+ */
public int getForks() {
return forks;
}
@@ -364,6 +368,14 @@ public Date getPushedAt() {
* @return
* This field is null until the user explicitly configures the master branch.
*/
+ public String getDefaultBranch() {
+ return default_branch;
+ }
+
+ /**
+ * @deprecated
+ * Renamed to {@link #getDefaultBranch()}
+ */
public String getMasterBranch() {
return default_branch;
}
@@ -494,6 +506,10 @@ public void setHomepage(String value) throws IOException {
edit("homepage",value);
}
+ public void setDefaultBranch(String value) throws IOException {
+ edit("default_branch", value);
+ }
+
/**
* Deletes this repository.
*/
@@ -505,6 +521,43 @@ public void delete() throws IOException {
}
}
+ /**
+ * Sort orders for listing forks
+ */
+ public static enum ForkSort { NEWEST, OLDEST, STARGAZERS }
+
+ /**
+ * Lists all the direct forks of this repository, sorted by
+ * github api default, currently {@link ForkSort#NEWEST ForkSort.NEWEST}.
+ */
+ public PagedIterable listForks() {
+ return listForks(null);
+ }
+
+ /**
+ * Lists all the direct forks of this repository, sorted by the given sort order.
+ * @param sort the sort order. If null, defaults to github api default,
+ * currently {@link ForkSort#NEWEST ForkSort.NEWEST}.
+ */
+ public PagedIterable listForks(final ForkSort sort) {
+ return new PagedIterable() {
+ public PagedIterator iterator() {
+ String sortParam = "";
+ if (sort != null) {
+ sortParam = "?sort=" + sort.toString().toLowerCase(Locale.ENGLISH);
+ }
+ return new PagedIterator(root.retrieve().asIterator(getApiTailUrl("forks" + sortParam), GHRepository[].class)) {
+ @Override
+ protected void wrapUp(GHRepository[] page) {
+ for (GHRepository c : page) {
+ c.wrap(root);
+ }
+ }
+ };
+ }
+ };
+ }
+
/**
* Forks this repository as your repository.
*
@@ -597,15 +650,11 @@ public GHPullRequest createPullRequest(String title, String head, String base, S
* Retrieves the currently configured hooks.
*/
public List getHooks() throws IOException {
- List list = new ArrayList(Arrays.asList(
- root.retrieve().to(getApiTailUrl("hooks"), GHHook[].class)));
- for (GHHook h : list)
- h.wrap(this);
- return list;
+ return GHHooks.repoContext(this, owner).getHooks();
}
public GHHook getHook(int id) throws IOException {
- return root.retrieve().to(getApiTailUrl("hooks/" + id), GHHook.class).wrap(this);
+ return GHHooks.repoContext(this, owner).getHook(id);
}
/**
@@ -649,7 +698,7 @@ public GHRef[] getRefs(String refType) throws IOException {
}
/**
* Retrive a ref of the given type for the current GitHub repository.
- *
+ *
* @param refName
* eg: heads/branch
* @return refs matching the request type
@@ -662,7 +711,7 @@ public GHRef getRef(String refName) throws IOException {
}
/**
* Retrive a tree of the given type for the current GitHub repository.
- *
+ *
* @param sha - sha number or branch name ex: "master"
* @return refs matching the request type
* @throws IOException
@@ -673,11 +722,11 @@ public GHTree getTree(String sha) throws IOException {
String url = String.format("/repos/%s/%s/git/trees/%s", owner.login, name, sha);
return root.retrieve().to(url, GHTree.class).wrap(root);
}
-
+
/**
* Retrieves the tree for the current GitHub repository, recursively as described in here:
* https://developer.github.com/v3/git/trees/#get-a-tree-recursively
- *
+ *
* @param sha - sha number or branch name ex: "master"
* @param recursive use 1
* @throws IOException
@@ -774,7 +823,7 @@ public GHCommitStatus getLastCommitStatus(String sha1) throws IOException {
* @param description
* Optional short description.
* @param context
- * Optinal commit status context.
+ * Optinal commit status context.
*/
public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description, String context) throws IOException {
return new Requester(root)
@@ -784,7 +833,7 @@ public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, Strin
.with("context", context)
.to(String.format("/repos/%s/%s/statuses/%s",owner.login,this.name,sha1),GHCommitStatus.class).wrapUp(root);
}
-
+
/**
* @see #createCommitStatus(String, GHCommitState,String,String,String)
*/
@@ -858,10 +907,10 @@ protected void wrapUp(GHUser[] page) {
}
/**
- *
+ *
* See https://api.github.com/hooks for possible names and their configuration scheme.
* TODO: produce type-safe binding
- *
+ *
* @param name
* Type of the hook to be created. See https://api.github.com/hooks for possible names.
* @param config
@@ -870,21 +919,9 @@ protected void wrapUp(GHUser[] page) {
* Can be null. Types of events to hook into.
*/
public GHHook createHook(String name, Map config, Collection events, boolean active) throws IOException {
- List ea = null;
- if (events!=null) {
- ea = new ArrayList();
- for (GHEvent e : events)
- ea.add(e.name().toLowerCase(Locale.ENGLISH));
- }
-
- return new Requester(root)
- .with("name", name)
- .with("active", active)
- ._with("config", config)
- ._with("events",ea)
- .to(String.format("/repos/%s/%s/hooks",owner.login,this.name),GHHook.class).wrap(this);
+ return GHHooks.repoContext(this, owner).createHook(name, config, events, active);
}
-
+
public GHHook createWebHook(URL url, Collection events) throws IOException {
return createHook("web",Collections.singletonMap("url",url.toExternalForm()),events,true);
}
@@ -909,8 +946,8 @@ private void verifyMine() throws IOException {
/**
* Returns a set that represents the post-commit hook URLs.
* The returned set is live, and changes made to them are reflected to GitHub.
- *
- * @deprecated
+ *
+ * @deprecated
* Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)}
*/
public Set getPostCommitHooks() {
@@ -1098,19 +1135,19 @@ public GHMilestone createMilestone(String title, String description) throws IOEx
return new Requester(root)
.with("title", title).with("description", description).method("POST").to(getApiTailUrl("milestones"), GHMilestone.class).wrap(this);
}
-
+
public GHDeployKey addDeployKey(String title,String key) throws IOException {
return new Requester(root)
.with("title", title).with("key", key).method("POST").to(getApiTailUrl("keys"), GHDeployKey.class).wrap(this);
-
+
}
-
+
public List getDeployKeys() throws IOException{
List list = new ArrayList(Arrays.asList(
root.retrieve().to(getApiTailUrl("keys"), GHDeployKey[].class)));
for (GHDeployKey h : list)
h.wrap(this);
- return list;
+ return list;
}
/**
@@ -1119,7 +1156,7 @@ public List getDeployKeys() throws IOException{
* @return
* {@link GHRepository} that points to the root repository where this repository is forked
* (indirectly or directly) from. Otherwise null.
- * @see #getParent()
+ * @see #getParent()
*/
public GHRepository getSource() throws IOException {
if (source == null) return null;
@@ -1136,7 +1173,7 @@ public GHRepository getSource() throws IOException {
* @return
* {@link GHRepository} that points to the repository where this repository is forked
* directly from. Otherwise null.
- * @see #getSource()
+ * @see #getSource()
*/
public GHRepository getParent() throws IOException {
if (parent == null) return null;
@@ -1144,7 +1181,7 @@ public GHRepository getParent() throws IOException {
parent = root.getRepository(parent.getFullName());
return parent;
}
-
+
/**
* Subscribes to this repository to get notifications.
*/
@@ -1162,7 +1199,7 @@ public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOEx
*/
public GHSubscription getSubscription() throws IOException {
try {
- return new Requester(root).to(getApiTailUrl("subscription"), GHSubscription.class).wrapUp(this);
+ return root.retrieve().to(getApiTailUrl("subscription"), GHSubscription.class).wrapUp(this);
} catch (FileNotFoundException e) {
return null;
}
diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java
index d196481bc2..d3853380e8 100644
--- a/src/main/java/org/kohsuke/github/GitHub.java
+++ b/src/main/java/org/kohsuke/github/GitHub.java
@@ -45,6 +45,7 @@
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.binary.Base64;
@@ -248,6 +249,7 @@ public GHRateLimit getRateLimit() throws IOException {
// see issue #78
GHRateLimit r = new GHRateLimit();
r.limit = r.remaining = 1000000;
+ r.reset = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1));
return r;
}
}
diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java
index 960940e7cf..281426dd3e 100644
--- a/src/main/java/org/kohsuke/github/Requester.java
+++ b/src/main/java/org/kohsuke/github/Requester.java
@@ -53,6 +53,7 @@
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
+import static java.util.Arrays.asList;
import static org.kohsuke.github.GitHub.*;
/**
@@ -61,6 +62,8 @@
* @author Kohsuke Kawaguchi
*/
class Requester {
+ private static final List METHODS_WITHOUT_BODY = asList("GET", "DELETE");
+
private final GitHub root;
private final List args = new ArrayList();
private final Map headers = new LinkedHashMap();
@@ -208,7 +211,7 @@ public T to(String tailApiUrl, Class type, String method) throws IOExcept
private T _to(String tailApiUrl, Class type, T instance) throws IOException {
while (true) {// loop while API rate limit is hit
- if (method.equals("GET") && !args.isEmpty()) {
+ if (METHODS_WITHOUT_BODY.contains(method) && !args.isEmpty()) {
StringBuilder qs=new StringBuilder();
for (Entry arg : args) {
qs.append(qs.length()==0 ? '?' : '&');
@@ -287,7 +290,7 @@ public String getResponseHeader(String header) {
* Set up the request parameters or POST payload.
*/
private void buildRequest() throws IOException {
- if (!method.equals("GET")) {
+ if (isMethodWithBody()) {
uc.setDoOutput(true);
uc.setRequestProperty("Content-type", contentType);
@@ -311,6 +314,10 @@ private void buildRequest() throws IOException {
}
}
+ private boolean isMethodWithBody() {
+ return !METHODS_WITHOUT_BODY.contains(method);
+ }
+
/**
* Loads pagenated resources.
*
diff --git a/src/test/java/org/kohsuke/github/AppTest.java b/src/test/java/org/kohsuke/github/AppTest.java
index 5cdb17e987..d2b68e112c 100755
--- a/src/test/java/org/kohsuke/github/AppTest.java
+++ b/src/test/java/org/kohsuke/github/AppTest.java
@@ -351,7 +351,7 @@ public void testQueryCommits() throws Exception {
sha1.add(c.getSHA1());
}
assertEquals("1cccddb22e305397151b2b7b87b4b47d74ca337b",sha1.get(0));
- assertEquals(29,sha1.size());
+ assertEquals(29, sha1.size());
}
@Test
@@ -618,7 +618,7 @@ public void directoryListing() throws IOException {
@Test
public void testAddDeployKey() throws IOException {
- GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(),0);
+ GHRepository myRepository = getTestRepository();
final GHDeployKey newDeployKey = myRepository.addDeployKey("test", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUt0RAycC5cS42JKh6SecfFZBR1RrF+2hYMctz4mk74/arBE+wFb7fnSHGzdGKX2h5CFOWODifRCJVhB7hlVxodxe+QkQQYAEL/x1WVCJnGgTGQGOrhOMj95V3UE5pQKhsKD608C+u5tSofcWXLToP1/wZ7U4/AHjqYi08OLsWToHCax55TZkvdt2jo0hbIoYU+XI9Q8Uv4ONDN1oabiOdgeKi8+crvHAuvNleiBhWVBzFh8KdfzaH5uNdw7ihhFjEd1vzqACsjCINCjdMfzl6jD9ExuWuE92nZJnucls2cEoNC6k2aPmrZDg9hA32FXVpyseY+bDUWFU6LO2LG6PB kohsuke@atlas");
try {
assertNotNull(newDeployKey.getId());
@@ -636,7 +636,7 @@ public boolean apply(GHDeployKey deployKey) {
@Test
public void testCommitStatusContext() throws IOException {
- GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(), 0);
+ GHRepository myRepository = getTestRepository();
GHRef masterRef = myRepository.getRef("heads/master");
GHCommitStatus commitStatus = myRepository.createCommitStatus(masterRef.getObject().getSha(), GHCommitState.SUCCESS, "http://www.example.com", "test", "test/context");
assertEquals("test/context", commitStatus.getContext());
diff --git a/src/test/java/org/kohsuke/github/GitHubTest.java b/src/test/java/org/kohsuke/github/GitHubTest.java
index 578bbc13f3..54ce6e35d7 100644
--- a/src/test/java/org/kohsuke/github/GitHubTest.java
+++ b/src/test/java/org/kohsuke/github/GitHubTest.java
@@ -1,34 +1,40 @@
package org.kohsuke.github;
+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.Properties;
-import junit.framework.TestCase;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
/**
* Unit test for {@link GitHub}.
*/
-public class GitHubTest extends TestCase {
-
+public class GitHubTest {
+ @Test
public void testGitHubServerWithHttp() throws Exception {
GitHub hub = GitHub.connectToEnterprise("http://enterprise.kohsuke.org/api/v3", "bogus","bogus");
assertEquals("http://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
}
-
+ @Test
public void testGitHubServerWithHttps() throws Exception {
GitHub hub = GitHub.connectToEnterprise("https://enterprise.kohsuke.org/api/v3", "bogus","bogus");
assertEquals("https://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
}
-
+ @Test
public void testGitHubServerWithoutServer() throws Exception {
GitHub hub = GitHub.connectUsingPassword("kohsuke", "bogus");
assertEquals("https://api.github.com/test", hub.getApiURL("/test").toString());
}
-
+ @Test
public void testGitHubBuilderFromEnvironment() throws IOException {
Mapprops = new HashMap();
@@ -86,7 +92,7 @@ private void setupEnvironment(Map newenv) {
e1.printStackTrace();
}
}
-
+ @Test
public void testGitHubBuilderFromCustomEnvironment() throws IOException {
Map props = new HashMap();
@@ -105,4 +111,12 @@ public void testGitHubBuilderFromCustomEnvironment() throws IOException {
assertEquals("bogusEndpoint", builder.endpoint);
}
+ @Test
+ public void testGitHubEnterpriseDoesNotHaveRateLimit() throws IOException {
+ GitHub github = spy(new GitHubBuilder().build());
+ when(github.retrieve()).thenThrow(FileNotFoundException.class);
+
+ GHRateLimit rateLimit = github.getRateLimit();
+ assertThat(rateLimit.getResetDate(), notNullValue());
+ }
}
diff --git a/src/test/java/org/kohsuke/github/PullRequestTest.java b/src/test/java/org/kohsuke/github/PullRequestTest.java
index c513860eae..9fc55f7519 100644
--- a/src/test/java/org/kohsuke/github/PullRequestTest.java
+++ b/src/test/java/org/kohsuke/github/PullRequestTest.java
@@ -5,6 +5,7 @@
import java.io.IOException;
import java.util.Collection;
+import java.util.List;
/**
* @author Kohsuke Kawaguchi
@@ -18,7 +19,38 @@ public void createPullRequest() throws Exception {
assertEquals(name, p.getTitle());
}
- @Test // Requires push access to the test repo to pass
+ @Test
+ public void createPullRequestComment() throws Exception {
+ String name = rnd.next();
+ GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
+ p.comment("Some comment");
+ }
+
+ @Test
+ public void testPullRequestReviewComments() throws Exception {
+ String name = rnd.next();
+ GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
+ System.out.println(p.getUrl());
+ assertTrue(p.listReviewComments().asList().isEmpty());
+ p.createReviewComment("Sample review comment", p.getHead().getSha(), "cli/pom.xml", 5);
+ List comments = p.listReviewComments().asList();
+ assertEquals(1, comments.size());
+ GHPullRequestReviewComment comment = comments.get(0);
+ assertEquals("Sample review comment", comment.getBody());
+
+ comment.update("Updated review comment");
+ comments = p.listReviewComments().asList();
+ assertEquals(1, comments.size());
+ comment = comments.get(0);
+ assertEquals("Updated review comment", comment.getBody());
+
+ comment.delete();
+ comments = p.listReviewComments().asList();
+ assertTrue(comments.isEmpty());
+ }
+
+ @Test
+ // Requires push access to the test repo to pass
public void setLabels() throws Exception {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
String label = rnd.next();
@@ -29,7 +61,8 @@ public void setLabels() throws Exception {
assertEquals(label, labels.iterator().next().getName());
}
- @Test // Requires push access to the test repo to pass
+ @Test
+ // Requires push access to the test repo to pass
public void setAssignee() throws Exception {
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
GHMyself user = gitHub.getMyself();
@@ -49,7 +82,7 @@ public void testGetUser() throws IOException {
PagedIterable ghPullRequests = getRepository().listPullRequests(GHIssueState.OPEN);
for (GHPullRequest pr : ghPullRequests) {
assertNotNull(pr.getUser().root);
- assertFalse(pr.getMergeable());
+ pr.getMergeable();
assertNotNull(pr.getUser().root);
}
}