From 9f3f644b83ec002cf4e7b58c1a7b79f803757d7c Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Mon, 16 May 2016 13:33:53 -0700 Subject: [PATCH 01/34] Add some level of synchronization to the root of the API This adds some synchronization to the maps at the root of the API to avoid duplicated calls to the actual GH REST API. Specifically this is targeted around the two maps, orgs and users. This fix makes the GHPRB jenkins plugin behave much better when there are lots of projects that could build for a specific repo (even if only a few are actually triggered) There are also a few fixes around GHUser and GHPullRequest * GHPullRequest was checking a field that may be null (merged_by) when determining whether to fetch details. An unmerged PR would make a bunch of Github API calls for each property accessed. * Where GHUser was returned in various objects, we weren't going through the caching mechanism at the root, so calls to APIs on GHUSer often resulted in new REST calls. Instead, return from the cache wherever possible. --- .../org/kohsuke/github/GHCommitPointer.java | 3 +- .../org/kohsuke/github/GHCommitStatus.java | 3 +- .../java/org/kohsuke/github/GHDeployment.java | 5 +- src/main/java/org/kohsuke/github/GHGist.java | 4 +- src/main/java/org/kohsuke/github/GHIssue.java | 11 ++- .../java/org/kohsuke/github/GHMilestone.java | 4 +- .../org/kohsuke/github/GHPullRequest.java | 2 +- src/main/java/org/kohsuke/github/GitHub.java | 94 +++++++++++++------ 8 files changed, 83 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHCommitPointer.java b/src/main/java/org/kohsuke/github/GHCommitPointer.java index b9716366b5..6b3f414f43 100644 --- a/src/main/java/org/kohsuke/github/GHCommitPointer.java +++ b/src/main/java/org/kohsuke/github/GHCommitPointer.java @@ -39,7 +39,8 @@ public class GHCommitPointer { * This points to the user who owns * the {@link #getRepository()}. */ - public GHUser getUser() { + public GHUser getUser() throws IOException { + if (user != null) return user.root.getUser(user.getLogin()); return user; } diff --git a/src/main/java/org/kohsuke/github/GHCommitStatus.java b/src/main/java/org/kohsuke/github/GHCommitStatus.java index 7b876fc5a0..241f8b98b4 100644 --- a/src/main/java/org/kohsuke/github/GHCommitStatus.java +++ b/src/main/java/org/kohsuke/github/GHCommitStatus.java @@ -45,7 +45,8 @@ public String getDescription() { return description; } - public GHUser getCreator() { + public GHUser getCreator() throws IOException { + if (creator != null) return creator.root.getUser(creator.getLogin()); return creator; } diff --git a/src/main/java/org/kohsuke/github/GHDeployment.java b/src/main/java/org/kohsuke/github/GHDeployment.java index 51a7843d0b..ff8b4d6afc 100644 --- a/src/main/java/org/kohsuke/github/GHDeployment.java +++ b/src/main/java/org/kohsuke/github/GHDeployment.java @@ -1,6 +1,6 @@ package org.kohsuke.github; - +import java.io.IOException; import java.net.URL; public class GHDeployment extends GHObject { @@ -41,7 +41,8 @@ public String getPayload() { public String getEnvironment() { return environment; } - public GHUser getCreator() { + public GHUser getCreator() throws IOException { + if(creator != null) return root.getUser(creator.getLogin()); return creator; } public String getRef() { diff --git a/src/main/java/org/kohsuke/github/GHGist.java b/src/main/java/org/kohsuke/github/GHGist.java index eb105b40c6..e0954175d0 100644 --- a/src/main/java/org/kohsuke/github/GHGist.java +++ b/src/main/java/org/kohsuke/github/GHGist.java @@ -38,8 +38,8 @@ public class GHGist extends GHObject { /** * User that owns this Gist. */ - public GHUser getOwner() { - return owner; + public GHUser getOwner() throws IOException { + return root.getUser(owner.getLogin()); } public String getForksUrl() { diff --git a/src/main/java/org/kohsuke/github/GHIssue.java b/src/main/java/org/kohsuke/github/GHIssue.java index a5afad6d2e..76a4e0e390 100644 --- a/src/main/java/org/kohsuke/github/GHIssue.java +++ b/src/main/java/org/kohsuke/github/GHIssue.java @@ -225,15 +225,16 @@ protected String getIssuesApiRoute() { return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number; } - public GHUser getAssignee() { + public GHUser getAssignee() throws IOException { + if (assignee != null) return owner.root.getUser(assignee.getLogin()); return assignee; } /** * User who submitted the issue. */ - public GHUser getUser() { - return user; + public GHUser getUser() throws IOException { + return owner.root.getUser(user.getLogin()); } /** @@ -244,9 +245,9 @@ public GHUser getUser() { * even for an issue that's already closed. See * https://github.com/kohsuke/github-api/issues/60. */ - public GHUser getClosedBy() { + public GHUser getClosedBy() throws IOException { if(!"closed".equals(state)) return null; - if(closed_by != null) return closed_by; + if(closed_by != null) return owner.root.getUser(closed_by.getLogin());; //TODO closed_by = owner.getIssue(number).getClosed_by(); return closed_by; diff --git a/src/main/java/org/kohsuke/github/GHMilestone.java b/src/main/java/org/kohsuke/github/GHMilestone.java index 48f8364bbf..950dea2574 100644 --- a/src/main/java/org/kohsuke/github/GHMilestone.java +++ b/src/main/java/org/kohsuke/github/GHMilestone.java @@ -27,8 +27,8 @@ public GHRepository getOwner() { return owner; } - public GHUser getCreator() { - return creator; + public GHUser getCreator() throws IOException { + return root.getUser(creator.getLogin()); } public Date getDueOn() { diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index dd3d93b758..4f549975f8 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -200,7 +200,7 @@ public String getMergeCommitSha() throws IOException { * Depending on the original API call where this object is created, it may not contain everything. */ private void populate() throws IOException { - if (merged_by!=null) return; // already populated + if (mergeable_state != null) return; // already populated by id root.retrieve().to(url, this).wrapUp(owner); } diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 22792a8798..12e24157c0 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -77,9 +77,10 @@ public class GitHub { */ /*package*/ final String encodedAuthorization; - private final Map users = new Hashtable(); - private final Map orgs = new Hashtable(); - + private final Map users; + private final Map orgs; + // Cache of myself object. + private GHMyself myself; private final String apiUrl; /*package*/ final RateLimitHandler rateLimitHandler; @@ -139,6 +140,8 @@ public class GitHub { } } + users = new Hashtable(); + orgs = new Hashtable(); this.rateLimitHandler = rateLimitHandler; if (login==null && encodedAuthorization!=null) @@ -226,7 +229,7 @@ public HttpConnector getConnector() { /** * Sets the custom connector used to make requests to GitHub. */ - public void setConnector(HttpConnector connector) { + public synchronized void setConnector(HttpConnector connector) { this.connector = connector; } @@ -276,56 +279,89 @@ public GHRateLimit getRateLimit() throws IOException { public GHMyself getMyself() throws IOException { requireCredential(); - GHMyself u = retrieve().to("/user", GHMyself.class); - - u.root = this; - users.put(u.getLogin(), u); + // This entire block is under synchronization to avoid the relatively common case + // where a bunch of threads try to enter this code simultaneously. While we could + // scope the synchronization separately around the map retrieval and update (or use a concurrent hash) + // map, the point is to avoid making unnecessary GH API calls, which are expensive from + // an API rate standpoint + synchronized (this) { + if (this.myself != null) return myself; + + GHMyself u = retrieve().to("/user", GHMyself.class); - return u; + u.root = this; + this.myself = u; + return u; + } } /** * Obtains the object that represents the named user. */ public GHUser getUser(String login) throws IOException { - GHUser u = users.get(login); - if (u == null) { - u = retrieve().to("/users/" + login, GHUser.class); - u.root = this; - users.put(u.getLogin(), u); + // This entire block is under synchronization to avoid the relatively common case + // where a bunch of threads try to enter this code simultaneously. While we could + // scope the synchronization separately around the map retrieval and update (or use a concurrent hash + // map), the point is to avoid making unnecessary GH API calls, which are expensive from + // an API rate standpoint + synchronized (users) { + GHUser u = users.get(login); + if (u == null) { + u = retrieve().to("/users/" + login, GHUser.class); + u.root = this; + users.put(u.getLogin(), u); + } + return u; } - return u; } - + /** * clears all cached data in order for external changes (modifications and del */ public void refreshCache() { - users.clear(); - orgs.clear(); + synchronized (users) { + users.clear(); + } + synchronized (orgs) { + orgs.clear(); + } } /** * Interns the given {@link GHUser}. */ protected GHUser getUser(GHUser orig) throws IOException { - GHUser u = users.get(orig.getLogin()); - if (u==null) { - orig.root = this; - users.put(orig.getLogin(),orig); - return orig; + // This entire block is under synchronization to avoid the relatively common case + // where a bunch of threads try to enter this code simultaneously. While we could + // scope the synchronization separately around the map retrieval and update (or use a concurrent hash + // map), the point is to avoid making unnecessary GH API calls, which are expensive from + // an API rate standpoint + synchronized (users) { + GHUser u = users.get(orig.getLogin()); + if (u==null) { + orig.root = this; + users.put(orig.getLogin(),orig); + return orig; + } + return u; } - return u; } public GHOrganization getOrganization(String name) throws IOException { - GHOrganization o = orgs.get(name); - if (o==null) { - o = retrieve().to("/orgs/" + name, GHOrganization.class).wrapUp(this); - orgs.put(name,o); + // This entire block is under synchronization to avoid the relatively common case + // where a bunch of threads try to enter this code simultaneously. While we could + // scope the synchronization separately around the map retrieval and update (or use a concurrent hash + // map), the point is to avoid making unnecessary GH API calls, which are expensive from + // an API rate standpoint + synchronized (orgs) { + GHOrganization o = orgs.get(name); + if (o==null) { + o = retrieve().to("/orgs/" + name, GHOrganization.class).wrapUp(this); + orgs.put(name,o); + } + return o; } - return o; } /** From 5b156006fb396612e7a931a8292173fdb2bd23f7 Mon Sep 17 00:00:00 2001 From: Greg Gianforcaro Date: Fri, 27 Jan 2017 23:36:54 -0500 Subject: [PATCH 02/34] Add 'Preview' support for MergeMethod on GHPullRequest - Add 'polaris' preview - Add MergeMethod Enum - Add merge method to GHPullRequest which takes a MergeMethod --- .../org/kohsuke/github/GHPullRequest.java | 25 ++++++++++++++++++- .../java/org/kohsuke/github/Previews.java | 1 + .../org/kohsuke/github/PullRequestTest.java | 13 ++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 04898039bc..8b6404a212 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -23,6 +23,8 @@ */ package org.kohsuke.github; +import static org.kohsuke.github.Previews.POLARIS; + import java.io.IOException; import java.net.URL; import java.util.Collection; @@ -277,7 +279,7 @@ public GHPullRequestReviewComment createReviewComment(String body, String sha, S * Commit message. If null, the default one will be used. */ public void merge(String msg) throws IOException { - merge(msg,null); + merge(msg,(String)null); } /** @@ -294,6 +296,27 @@ public void merge(String msg, String sha) throws IOException { new Requester(root).method("PUT").with("commit_message",msg).with("sha",sha).to(getApiRoute()+"/merge"); } + /** + * Merge this pull request, using the specified merge method. + * + * The equivalent of the big green "Merge pull request" button. + * + * @param msg + * Commit message. If null, the default one will be used. + * @param method + * SHA that pull request head must match to allow merge. + */ + @Preview @Deprecated + public void merge(String msg, MergeMethod method) throws IOException { + new Requester(root).method("PUT") + .withPreview(POLARIS) + .with("commit_message",msg) + .with("merge_method",method) + .to(getApiRoute()+"/merge"); + } + + public enum MergeMethod{ MERGE, SQUASH, REBASE } + private void fetchIssue() throws IOException { if (!fetchedIssueDetails) { new Requester(root).to(getIssuesApiRoute(), this); diff --git a/src/main/java/org/kohsuke/github/Previews.java b/src/main/java/org/kohsuke/github/Previews.java index 238b062b8b..3b7eeb5939 100644 --- a/src/main/java/org/kohsuke/github/Previews.java +++ b/src/main/java/org/kohsuke/github/Previews.java @@ -8,4 +8,5 @@ static final String DRAX = "application/vnd.github.drax-preview+json"; static final String SQUIRREL_GIRL = "application/vnd.github.squirrel-girl-preview"; static final String KORRA = "application/vnd.github.korra-preview"; + static final String POLARIS = "application/vnd.github.polaris-preview"; } diff --git a/src/test/java/org/kohsuke/github/PullRequestTest.java b/src/test/java/org/kohsuke/github/PullRequestTest.java index c7ce77d289..ba8f087197 100644 --- a/src/test/java/org/kohsuke/github/PullRequestTest.java +++ b/src/test/java/org/kohsuke/github/PullRequestTest.java @@ -69,6 +69,19 @@ public void testMergeCommitSHA() throws Exception { fail(); } + @Test + public void testSquashMerge() throws Exception { + String name = rnd.next(); + GHRef masterRef = getRepository().getRef("heads/master"); + GHRef branchRef = getRepository().createRef("refs/heads/" + name, masterRef.getObject().getSha()); + getRepository().createContent(name, name, name, name); + Thread.sleep(1000); + GHPullRequest p = getRepository().createPullRequest(name, name, "master", "## test squash"); + Thread.sleep(1000); + p.merge("squash merge", GHPullRequest.MergeMethod.SQUASH); + branchRef.delete(); + } + @Test // Requires push access to the test repo to pass public void setLabels() throws Exception { From fafe6b0ff7ba04c887171a41862f0bb9150780c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20K=C3=BCrten?= Date: Thu, 9 Feb 2017 18:13:54 +0100 Subject: [PATCH 03/34] Remove unused imports Especially also remove the unsued import of javax.xml.bind.DatatypeConverter from GHContent which is non-public API as of Java 8 --- src/main/java/org/kohsuke/github/GHAuthorization.java | 1 - src/main/java/org/kohsuke/github/GHCommitComment.java | 2 -- src/main/java/org/kohsuke/github/GHContent.java | 2 -- .../java/org/kohsuke/github/GHDeploymentStatusBuilder.java | 1 - src/main/java/org/kohsuke/github/GHHooks.java | 1 - src/main/java/org/kohsuke/github/GHIssueSearchBuilder.java | 2 -- src/main/java/org/kohsuke/github/GHMyself.java | 1 - src/main/java/org/kohsuke/github/GHObject.java | 3 --- .../java/org/kohsuke/github/GHRepositorySearchBuilder.java | 2 -- src/main/java/org/kohsuke/github/GHUserSearchBuilder.java | 2 -- src/main/java/org/kohsuke/github/GitHub.java | 2 -- src/main/java/org/kohsuke/github/HttpConnector.java | 1 - src/main/java/org/kohsuke/github/PagedIterable.java | 1 - src/main/java/org/kohsuke/github/PagedSearchIterable.java | 1 - src/main/java/org/kohsuke/github/Requester.java | 1 - src/test/java/Foo.java | 3 --- src/test/java/org/kohsuke/github/AppTest.java | 3 --- src/test/java/org/kohsuke/github/CommitTest.java | 1 - src/test/java/org/kohsuke/github/GitHubTest.java | 1 - 19 files changed, 31 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHAuthorization.java b/src/main/java/org/kohsuke/github/GHAuthorization.java index 2a9fa39092..e196047776 100644 --- a/src/main/java/org/kohsuke/github/GHAuthorization.java +++ b/src/main/java/org/kohsuke/github/GHAuthorization.java @@ -3,7 +3,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.net.URL; import java.util.Collection; -import java.util.Date; import java.util.List; /** diff --git a/src/main/java/org/kohsuke/github/GHCommitComment.java b/src/main/java/org/kohsuke/github/GHCommitComment.java index 3543b5fdb3..646badf5c3 100644 --- a/src/main/java/org/kohsuke/github/GHCommitComment.java +++ b/src/main/java/org/kohsuke/github/GHCommitComment.java @@ -3,8 +3,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.net.URL; -import java.util.Date; - import static org.kohsuke.github.Previews.SQUIRREL_GIRL; /** diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index 8b6f6fea54..d7a7bd446f 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -7,8 +7,6 @@ import java.io.IOException; import java.io.InputStream; -import javax.xml.bind.DatatypeConverter; - /** * A Content of a repository. * diff --git a/src/main/java/org/kohsuke/github/GHDeploymentStatusBuilder.java b/src/main/java/org/kohsuke/github/GHDeploymentStatusBuilder.java index 18cf5464ac..f028b6f889 100644 --- a/src/main/java/org/kohsuke/github/GHDeploymentStatusBuilder.java +++ b/src/main/java/org/kohsuke/github/GHDeploymentStatusBuilder.java @@ -1,7 +1,6 @@ package org.kohsuke.github; import java.io.IOException; -import java.util.Locale; public class GHDeploymentStatusBuilder { private final Requester builder; diff --git a/src/main/java/org/kohsuke/github/GHHooks.java b/src/main/java/org/kohsuke/github/GHHooks.java index 6f64587b17..6ecbb04b6e 100644 --- a/src/main/java/org/kohsuke/github/GHHooks.java +++ b/src/main/java/org/kohsuke/github/GHHooks.java @@ -5,7 +5,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.Locale; import java.util.Map; /** diff --git a/src/main/java/org/kohsuke/github/GHIssueSearchBuilder.java b/src/main/java/org/kohsuke/github/GHIssueSearchBuilder.java index f9634a59f1..6cefc01678 100644 --- a/src/main/java/org/kohsuke/github/GHIssueSearchBuilder.java +++ b/src/main/java/org/kohsuke/github/GHIssueSearchBuilder.java @@ -1,7 +1,5 @@ package org.kohsuke.github; -import java.util.Locale; - /** * Search issues. * diff --git a/src/main/java/org/kohsuke/github/GHMyself.java b/src/main/java/org/kohsuke/github/GHMyself.java index cc05f03bc5..5ab9b4a270 100644 --- a/src/main/java/org/kohsuke/github/GHMyself.java +++ b/src/main/java/org/kohsuke/github/GHMyself.java @@ -6,7 +6,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeMap; diff --git a/src/main/java/org/kohsuke/github/GHObject.java b/src/main/java/org/kohsuke/github/GHObject.java index a81d913a5c..d368af0aec 100644 --- a/src/main/java/org/kohsuke/github/GHObject.java +++ b/src/main/java/org/kohsuke/github/GHObject.java @@ -3,10 +3,7 @@ import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.apache.commons.lang.builder.ReflectionToStringBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; -import org.apache.commons.lang.reflect.FieldUtils; - import java.io.IOException; import java.lang.reflect.Field; import java.net.URL; diff --git a/src/main/java/org/kohsuke/github/GHRepositorySearchBuilder.java b/src/main/java/org/kohsuke/github/GHRepositorySearchBuilder.java index 03b12f5133..642f7f3d95 100644 --- a/src/main/java/org/kohsuke/github/GHRepositorySearchBuilder.java +++ b/src/main/java/org/kohsuke/github/GHRepositorySearchBuilder.java @@ -1,7 +1,5 @@ package org.kohsuke.github; -import java.util.Locale; - /** * Search repositories. * diff --git a/src/main/java/org/kohsuke/github/GHUserSearchBuilder.java b/src/main/java/org/kohsuke/github/GHUserSearchBuilder.java index ca40f4d050..3edcd15065 100644 --- a/src/main/java/org/kohsuke/github/GHUserSearchBuilder.java +++ b/src/main/java/org/kohsuke/github/GHUserSearchBuilder.java @@ -1,7 +1,5 @@ package org.kohsuke.github; -import java.util.Locale; - /** * Search users. * diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index ccc18b450e..3844d8181e 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -47,8 +47,6 @@ import java.util.Map; import java.util.Set; import java.util.TimeZone; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; diff --git a/src/main/java/org/kohsuke/github/HttpConnector.java b/src/main/java/org/kohsuke/github/HttpConnector.java index 72f7ce5b05..2d87c148c9 100644 --- a/src/main/java/org/kohsuke/github/HttpConnector.java +++ b/src/main/java/org/kohsuke/github/HttpConnector.java @@ -5,7 +5,6 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; -import java.util.concurrent.TimeUnit; /** * Pluggability for customizing HTTP request behaviors or using altogether different library. diff --git a/src/main/java/org/kohsuke/github/PagedIterable.java b/src/main/java/org/kohsuke/github/PagedIterable.java index 41c5bfdb0c..1c6eccea36 100644 --- a/src/main/java/org/kohsuke/github/PagedIterable.java +++ b/src/main/java/org/kohsuke/github/PagedIterable.java @@ -1,6 +1,5 @@ package org.kohsuke.github; -import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; diff --git a/src/main/java/org/kohsuke/github/PagedSearchIterable.java b/src/main/java/org/kohsuke/github/PagedSearchIterable.java index 1efe49a1ef..f23bd6b58c 100644 --- a/src/main/java/org/kohsuke/github/PagedSearchIterable.java +++ b/src/main/java/org/kohsuke/github/PagedSearchIterable.java @@ -2,7 +2,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.io.IOException; import java.util.Iterator; /** diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index db70fbd64b..d4bca32d6f 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -48,7 +48,6 @@ 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; diff --git a/src/test/java/Foo.java b/src/test/java/Foo.java index 35e5eb5955..540f9fd3ca 100644 --- a/src/test/java/Foo.java +++ b/src/test/java/Foo.java @@ -1,10 +1,7 @@ -import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHRepository.Contributor; import org.kohsuke.github.GHUser; import org.kohsuke.github.GitHub; -import java.util.Collection; - /** * @author Kohsuke Kawaguchi */ diff --git a/src/test/java/org/kohsuke/github/AppTest.java b/src/test/java/org/kohsuke/github/AppTest.java index a20b2eccf3..3d40c78616 100755 --- a/src/test/java/org/kohsuke/github/AppTest.java +++ b/src/test/java/org/kohsuke/github/AppTest.java @@ -5,8 +5,6 @@ import com.google.common.collect.Lists; import org.apache.commons.io.IOUtils; -import org.hamcrest.CoreMatchers; -import org.junit.Assume; import org.junit.Test; import org.kohsuke.github.GHCommit.File; import org.kohsuke.github.GHOrganization.Permission; @@ -16,7 +14,6 @@ import java.net.URL; import java.util.*; import java.util.Map.Entry; -import java.util.concurrent.ExecutionException; import java.util.regex.Pattern; import static org.hamcrest.CoreMatchers.*; diff --git a/src/test/java/org/kohsuke/github/CommitTest.java b/src/test/java/org/kohsuke/github/CommitTest.java index c42fceef41..8e4edb1fed 100644 --- a/src/test/java/org/kohsuke/github/CommitTest.java +++ b/src/test/java/org/kohsuke/github/CommitTest.java @@ -1,7 +1,6 @@ package org.kohsuke.github; import com.google.common.collect.Iterables; -import com.google.common.collect.Iterators; import org.junit.Test; import java.io.IOException; diff --git a/src/test/java/org/kohsuke/github/GitHubTest.java b/src/test/java/org/kohsuke/github/GitHubTest.java index 010adc8b24..a418db5fde 100644 --- a/src/test/java/org/kohsuke/github/GitHubTest.java +++ b/src/test/java/org/kohsuke/github/GitHubTest.java @@ -8,7 +8,6 @@ import java.util.Map; import com.google.common.collect.Iterables; -import com.google.common.collect.Iterators; import org.junit.Test; import static org.hamcrest.CoreMatchers.notNullValue; From 55b00a87f619250ddcd0784ada74fa10625e9980 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Fri, 10 Feb 2017 03:28:06 +0300 Subject: [PATCH 04/34] Set 1.6 level. I'm not so old. Signed-off-by: Kanstantsin Shautsou --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 462816255a..0e908df6fe 100644 --- a/pom.xml +++ b/pom.xml @@ -41,13 +41,13 @@ org.codehaus.mojo.signature - java15 + java16 1.0 - ensure-java-1.5-class-library + ensure-java-1.6-class-library test check From be081eec3ff24317bb6423a11230712c2107e2b3 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Fri, 10 Feb 2017 03:33:18 +0300 Subject: [PATCH 05/34] Inject responce headers in GHObject and Exceptions. GH has specific to GET/POST headers required for analysing in case of error. Signed-off-by: Kanstantsin Shautsou --- pom.xml | 6 ++ .../java/org/kohsuke/github/GHObject.java | 13 ++- .../java/org/kohsuke/github/Requester.java | 53 ++++++++++--- .../exception/GHFileNotFoundException.java | 34 ++++++++ .../github/exception/GHIOException.java | 42 ++++++++++ .../java/org/kohsuke/github/GHHookTest.java | 79 +++++++++++++++++++ 6 files changed, 215 insertions(+), 12 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/exception/GHFileNotFoundException.java create mode 100644 src/main/java/org/kohsuke/github/exception/GHIOException.java create mode 100644 src/test/java/org/kohsuke/github/GHHookTest.java diff --git a/pom.xml b/pom.xml index 0e908df6fe..9f372d703d 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,12 @@ 4.11 test + + org.hamcrest + hamcrest-all + 1.3 + test + com.fasterxml.jackson.core jackson-databind diff --git a/src/main/java/org/kohsuke/github/GHObject.java b/src/main/java/org/kohsuke/github/GHObject.java index a81d913a5c..3a1cde1908 100644 --- a/src/main/java/org/kohsuke/github/GHObject.java +++ b/src/main/java/org/kohsuke/github/GHObject.java @@ -3,14 +3,15 @@ import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.apache.commons.lang.builder.ReflectionToStringBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; -import org.apache.commons.lang.reflect.FieldUtils; +import javax.annotation.CheckForNull; import java.io.IOException; import java.lang.reflect.Field; import java.net.URL; import java.util.Date; +import java.util.List; +import java.util.Map; /** * Most (all?) domain objects in GitHub seems to have these 4 properties. @@ -18,6 +19,9 @@ @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public abstract class GHObject { + // not data but information related to data from responce + protected Map> responseHeaderFields; + protected String url; protected int id; protected String created_at; @@ -26,6 +30,11 @@ public abstract class GHObject { /*package*/ GHObject() { } + @CheckForNull + public Map> getResponseHeaderFields() { + return responseHeaderFields; + } + /** * When was this resource created? */ diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index db70fbd64b..64aefe68fe 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -25,6 +25,10 @@ import com.fasterxml.jackson.databind.JsonMappingException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.apache.commons.io.IOUtils; +import org.kohsuke.github.exception.GHFileNotFoundException; +import org.kohsuke.github.exception.GHIOException; + import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -48,17 +52,18 @@ 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 javax.annotation.CheckForNull; import javax.annotation.WillClose; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import static java.util.Arrays.asList; -import static java.util.logging.Level.*; +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.FINEST; import static org.kohsuke.github.GitHub.MAPPER; /** @@ -269,7 +274,7 @@ private T _to(String tailApiUrl, Class type, T instance) throws IOExcepti if (nextLinkMatcher.find()) { final String link = nextLinkMatcher.group(1); T nextResult = _to(link, type, instance); - + injectInResult(nextResult); final int resultLength = Array.getLength(result); final int nextResultLength = Array.getLength(nextResult); T concatResult = (T) Array.newInstance(type.getComponentType(), resultLength + nextResultLength); @@ -279,6 +284,7 @@ private T _to(String tailApiUrl, Class type, T instance) throws IOExcepti } } } + injectInResult(result); return result; } catch (IOException e) { handleApiError(e); @@ -579,6 +585,7 @@ private void setRequestMethod(HttpURLConnection uc) throws IOException { throw new IllegalStateException("Failed to set the request method to "+method); } + @CheckForNull private T parse(Class type, T instance) throws IOException { InputStreamReader r = null; int responseCode = -1; @@ -598,12 +605,17 @@ private T parse(Class type, T instance) throws IOException { String data = IOUtils.toString(r); if (type!=null) try { - return MAPPER.readValue(data,type); + final T readValue = MAPPER.readValue(data, type); + injectInResult(readValue); + return readValue; } catch (JsonMappingException e) { throw (IOException)new IOException("Failed to deserialize " +data).initCause(e); } - if (instance!=null) - return MAPPER.readerForUpdating(instance).readValue(data); + if (instance!=null) { + final T readValue = MAPPER.readerForUpdating(instance).readValue(data); + injectInResult(readValue); + return readValue; + } return null; } catch (FileNotFoundException e) { // java.net.URLConnection handles 404 exception has FileNotFoundException, don't wrap exception in HttpException @@ -616,6 +628,26 @@ private T parse(Class type, T instance) throws IOException { } } + private void injectInResult(T readValue) { + if (readValue instanceof GHObject[]) { + for (GHObject ghObject : (GHObject[]) readValue) { + injectInResult(ghObject); + } + } else if (readValue instanceof GHObject) { + injectInResult((GHObject) readValue); + } + } + + private void injectInResult(GHObject readValue) { + try { + final Field field = GHObject.class.getDeclaredField("responseHeaderFields"); + field.setAccessible(true); + field.set(readValue, uc.getHeaderFields()); + } catch (NoSuchFieldException ignore) { + } catch (IllegalAccessException ignore) { + } + } + /** * Handles the "Content-Encoding" header. */ @@ -663,15 +695,16 @@ private InputStream wrapStream(InputStream in) throws IOException { String error = IOUtils.toString(es, "UTF-8"); if (e instanceof FileNotFoundException) { // pass through 404 Not Found to allow the caller to handle it intelligently - throw (IOException) new FileNotFoundException(error).initCause(e); + throw (IOException) new GHFileNotFoundException(error).withResponseHeaderFields(uc).initCause(e); } else if (e instanceof HttpException) { HttpException http = (HttpException) e; throw (IOException) new HttpException(error, http.getResponseCode(), http.getResponseMessage(), http.getUrl(), e); } else { - throw (IOException) new IOException(error).initCause(e); + throw (IOException) new GHIOException(error).withResponceHeaderFields(uc).initCause(e); } - } else + } else { throw e; + } } finally { IOUtils.closeQuietly(es); } diff --git a/src/main/java/org/kohsuke/github/exception/GHFileNotFoundException.java b/src/main/java/org/kohsuke/github/exception/GHFileNotFoundException.java new file mode 100644 index 0000000000..27606de595 --- /dev/null +++ b/src/main/java/org/kohsuke/github/exception/GHFileNotFoundException.java @@ -0,0 +1,34 @@ +package org.kohsuke.github.exception; + +import javax.annotation.CheckForNull; +import java.io.FileNotFoundException; +import java.net.HttpURLConnection; +import java.util.List; +import java.util.Map; + +/** + * Request/responce contains useful metadata. + * Custom exception allows store info for next diagnostics. + * + * @author Kanstantsin Shautsou + */ +public class GHFileNotFoundException extends FileNotFoundException { + protected Map> responseHeaderFields; + + public GHFileNotFoundException() { + } + + public GHFileNotFoundException(String s) { + super(s); + } + + @CheckForNull + public Map> getResponseHeaderFields() { + return responseHeaderFields; + } + + public GHFileNotFoundException withResponseHeaderFields(HttpURLConnection urlConnection) { + this.responseHeaderFields = urlConnection.getHeaderFields(); + return this; + } +} diff --git a/src/main/java/org/kohsuke/github/exception/GHIOException.java b/src/main/java/org/kohsuke/github/exception/GHIOException.java new file mode 100644 index 0000000000..7bb614092e --- /dev/null +++ b/src/main/java/org/kohsuke/github/exception/GHIOException.java @@ -0,0 +1,42 @@ +package org.kohsuke.github.exception; + +import javax.annotation.CheckForNull; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.util.List; +import java.util.Map; + +/** + * Request/responce contains useful metadata. + * Custom exception allows store info for next diagnostics. + * + * @author Kanstantsin Shautsou + */ +public class GHIOException extends IOException { + protected Map> responceHeaderFields; + + public GHIOException() { + } + + public GHIOException(String message) { + super(message); + } + + public GHIOException(String message, Throwable cause) { + super(message, cause); + } + + public GHIOException(Throwable cause) { + super(cause); + } + + @CheckForNull + public Map> getResponceHeaderFields() { + return responceHeaderFields; + } + + public GHIOException withResponceHeaderFields(HttpURLConnection urlConnection) { + this.responceHeaderFields = urlConnection.getHeaderFields(); + return this; + } +} diff --git a/src/test/java/org/kohsuke/github/GHHookTest.java b/src/test/java/org/kohsuke/github/GHHookTest.java new file mode 100644 index 0000000000..2cbab48cb7 --- /dev/null +++ b/src/test/java/org/kohsuke/github/GHHookTest.java @@ -0,0 +1,79 @@ +package org.kohsuke.github; + +import org.apache.commons.lang.StringUtils; +import org.junit.Ignore; +import org.junit.Test; +import org.kohsuke.github.exception.GHFileNotFoundException; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.hasValue; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertThat; + + +/** + * @author Kanstantsin Shautsou + */ +public class GHHookTest { + + @Ignore + @Test + public void exposeResponceHeaders() throws Exception { + String user1Login = "KostyaSha-auto"; + String user1Pass = "secret"; + + String clientId = "90140219451"; + String clientSecret = "1451245425"; + + String orgRepo = "KostyaSha-org/test"; + + // some login based user that has access to application + final GitHub gitHub = GitHub.connectUsingPassword(user1Login, user1Pass); + gitHub.getMyself(); + + // we request read + final List scopes = Arrays.asList("repo", "read:org", "user:email", "read:repo_hook"); + + // application creates token with scopes + final GHAuthorization auth = gitHub.createOrGetAuth(clientId, clientSecret, scopes, "", ""); + String token = auth.getToken(); + if (StringUtils.isEmpty(token)) { + gitHub.deleteAuth(auth.getId()); + token = gitHub.createOrGetAuth(clientId, clientSecret, scopes, "", "").getToken(); + } + + /// now create connection using token + final GitHub gitHub2 = GitHub.connectUsingOAuth(token); + // some repo in organisation + final GHRepository repository = gitHub2.getRepository(orgRepo); + + // doesn't fail because we have read access + final List hooks = repository.getHooks(); + + try { + // fails because application isn't approved in organisation and you can find it only after doing real call + final GHHook hook = repository.createHook( + "my-hook", + singletonMap("url", "http://localhost"), + singletonList(GHEvent.PUSH), + true + ); + } catch (IOException ex) { + assertThat(ex, instanceOf(GHFileNotFoundException.class)); + final GHFileNotFoundException ghFileNotFoundException = (GHFileNotFoundException) ex; + final Map> responseHeaderFields = ghFileNotFoundException.getResponseHeaderFields(); + assertThat(responseHeaderFields, hasKey("X-Accepted-OAuth-Scopes")); + assertThat(responseHeaderFields.get("X-Accepted-OAuth-Scopes"), + hasItem("admin:repo_hook, public_repo, repo, write:repo_hook") + ); + } + } +} From b537f9925b8cea4f7736c8f7b80093033c36b795 Mon Sep 17 00:00:00 2001 From: Serban Iordache Date: Fri, 7 Jul 2017 16:21:11 +0200 Subject: [PATCH 06/34] issue #360: Add support for committing multiple files --- .../org/kohsuke/github/GHBlobBuilder.java | 50 ++++++++++ .../org/kohsuke/github/GHCommitBuilder.java | 92 +++++++++++++++++++ .../org/kohsuke/github/GHTreeBuilder.java | 86 +++++++++++++++++ 3 files changed, 228 insertions(+) create mode 100644 src/main/java/org/kohsuke/github/GHBlobBuilder.java create mode 100644 src/main/java/org/kohsuke/github/GHCommitBuilder.java create mode 100644 src/main/java/org/kohsuke/github/GHTreeBuilder.java diff --git a/src/main/java/org/kohsuke/github/GHBlobBuilder.java b/src/main/java/org/kohsuke/github/GHBlobBuilder.java new file mode 100644 index 0000000000..321e88191d --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHBlobBuilder.java @@ -0,0 +1,50 @@ +package org.kohsuke.github; + +import org.apache.commons.codec.binary.Base64; + +import java.io.IOException; + +/** + * Builder pattern for creating a new blob. + * Based on https://developer.github.com/v3/git/blobs/#create-a-blob + */ +public class GHBlobBuilder { + private final GHRepository repo; + private final Requester req; + + public GHBlobBuilder(GHRepository repo) { + this.repo = repo; + req = new Requester(repo.root); + } + + /** + * Configures a blob with the specified text {@code content}. + */ + public GHBlobBuilder textContent(String content) { + req.with("content", content); + req.with("encoding", "utf-8"); + return this; + } + + /** + * Configures a blob with the specified binary {@code content}. + */ + public GHBlobBuilder binaryContent(byte[] content) { + new String(content); + String base64Content = Base64.encodeBase64String(content); + req.with("content", base64Content); + req.with("encoding", "base64"); + return this; + } + + private String getApiTail() { + return String.format("/repos/%s/%s/git/blobs", repo.getOwnerName(), repo.getName()); + } + + /** + * Creates a blob based on the parameters specified thus far. + */ + public GHBlob create() throws IOException { + return req.method("POST").to(getApiTail(), GHBlob.class); + } +} diff --git a/src/main/java/org/kohsuke/github/GHCommitBuilder.java b/src/main/java/org/kohsuke/github/GHCommitBuilder.java new file mode 100644 index 0000000000..5f5b268a63 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHCommitBuilder.java @@ -0,0 +1,92 @@ +package org.kohsuke.github; + +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +/** + * Builder pattern for creating a new commit. + * Based on https://developer.github.com/v3/git/commits/#create-a-commit + */ +public class GHCommitBuilder { + private final GHRepository repo; + private final Requester req; + + private final List parents = new ArrayList(); + + private static final class UserInfo { + private final String name; + private final String email; + private final String date; + + private UserInfo(String name, String email, Date date) { + this.name = name; + this.email = email; + TimeZone tz = TimeZone.getTimeZone("UTC"); + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + df.setTimeZone(tz); + this.date = df.format((date != null) ? date : new Date()); + } + } + + public GHCommitBuilder(GHRepository repo) { + this.repo = repo; + req = new Requester(repo.root); + } + + /** + * @param message the commit message + */ + public GHCommitBuilder message(String message) { + req.with("message", message); + return this; + } + + /** + * @param tree the SHA of the tree object this commit points to + */ + public GHCommitBuilder tree(String tree) { + req.with("tree", tree); + return this; + } + + /** + * @param parent the SHA of a parent commit. + */ + public GHCommitBuilder parent(String parent) { + parents.add(parent); + return this; + } + + /** + * Configures the author of this commit. + */ + public GHCommitBuilder author(String name, String email, Date date) { + req._with("author", new UserInfo(name, email, date)); + return this; + } + + /** + * Configures the committer of this commit. + */ + public GHCommitBuilder committer(String name, String email, Date date) { + req._with("committer", new UserInfo(name, email, date)); + return this; + } + + private String getApiTail() { + return String.format("/repos/%s/%s/git/commits", repo.getOwnerName(), repo.getName()); + } + + /** + * Creates a blob based on the parameters specified thus far. + */ + public GHCommit create() throws IOException { + req._with("parents", parents); + return req.method("POST").to(getApiTail(), GHCommit.class).wrapUp(repo); + } +} diff --git a/src/main/java/org/kohsuke/github/GHTreeBuilder.java b/src/main/java/org/kohsuke/github/GHTreeBuilder.java new file mode 100644 index 0000000000..05c04ef9c1 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHTreeBuilder.java @@ -0,0 +1,86 @@ +package org.kohsuke.github; + +import java.io.IOException; +import java.util.*; + +/** + * Builder pattern for creating a new tree. + * Based on https://developer.github.com/v3/git/trees/#create-a-tree + */ +public class GHTreeBuilder { + private final GHRepository repo; + private final Requester req; + + private final List treeEntries = new ArrayList(); + + private static final class TreeEntry { + private final String path; + private final String mode; + private final String type; + private String sha; + private String content; + + private TreeEntry(String path, String mode, String type) { + this.path = path; + this.mode = mode; + this.type = type; + } + } + + public GHTreeBuilder(GHRepository repo) { + this.repo = repo; + req = new Requester(repo.root); + } + + /** + * @param baseTree the SHA of tree you want to update with new data + */ + public GHTreeBuilder baseTree(String baseTree) { + req.with("base_tree", baseTree); + return this; + } + + /** + * Adds a new entry to the tree. + * Exactly one of the parameters {@code sha} and {@code content} must be non-null. + */ + public GHTreeBuilder entry(String path, String mode, String type, String sha, String content) { + TreeEntry entry = new TreeEntry(path, mode, type); + entry.sha = sha; + entry.content = content; + treeEntries.add(entry); + return this; + } + + /** + * Specialized version of {@link #entry(String, String, String, String, String)} for adding an existing blob referred by its SHA. + */ + public GHTreeBuilder shaEntry(String path, String sha, boolean executable) { + TreeEntry entry = new TreeEntry(path, executable ? "100755" : "100644", "blob"); + entry.sha = sha; + treeEntries.add(entry); + return this; + } + + /** + * Specialized version of {@link #entry(String, String, String, String, String)} for adding a text file with the specified {@code content}. + */ + public GHTreeBuilder textEntry(String path, String content, boolean executable) { + TreeEntry entry = new TreeEntry(path, executable ? "100755" : "100644", "blob"); + entry.content = content; + treeEntries.add(entry); + return this; + } + + private String getApiTail() { + return String.format("/repos/%s/%s/git/trees", repo.getOwnerName(), repo.getName()); + } + + /** + * Creates a tree based on the parameters specified thus far. + */ + public GHTree create() throws IOException { + req._with("tree", treeEntries); + return req.method("POST").to(getApiTail(), GHTree.class).wrap(repo); + } +} From e90c86ec2fd34c9f8adc91044427298e758d6899 Mon Sep 17 00:00:00 2001 From: Greg Gianforcaro Date: Tue, 18 Jul 2017 11:36:38 -0400 Subject: [PATCH 07/34] Remove Preview status, merge_method is now out of preview --- src/main/java/org/kohsuke/github/GHPullRequest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 8b6404a212..096adcf92e 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -23,8 +23,6 @@ */ package org.kohsuke.github; -import static org.kohsuke.github.Previews.POLARIS; - import java.io.IOException; import java.net.URL; import java.util.Collection; @@ -306,10 +304,8 @@ public void merge(String msg, String sha) throws IOException { * @param method * SHA that pull request head must match to allow merge. */ - @Preview @Deprecated public void merge(String msg, MergeMethod method) throws IOException { new Requester(root).method("PUT") - .withPreview(POLARIS) .with("commit_message",msg) .with("merge_method",method) .to(getApiRoute()+"/merge"); From 6dcbace5723bb43a0ebc6f8297fe0b3975e6a150 Mon Sep 17 00:00:00 2001 From: adw1n Date: Tue, 1 Aug 2017 03:38:46 +0200 Subject: [PATCH 08/34] Added getViews method to GHRepository. getViews implements https://developer.github.com/v3/repos/traffic/#views --- .../java/org/kohsuke/github/GHRepository.java | 6 + .../org/kohsuke/github/GHRepositoryViews.java | 57 ++++++++++ .../github/RepositoryTrafficMockTest.java | 107 ++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 src/main/java/org/kohsuke/github/GHRepositoryViews.java create mode 100644 src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 74fbb4d665..82c9e30d9a 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -1481,6 +1481,12 @@ public GHNotificationStream listNotifications() { return new GHNotificationStream(root,getApiTailUrl("/notifications")); } + /** + * https://developer.github.com/v3/repos/traffic/#views + */ + public GHRepositoryViews getViews() throws IOException{ + return root.retrieve().to(getApiTailUrl("/traffic/views"), GHRepositoryViews.class); + } @Override public int hashCode() { diff --git a/src/main/java/org/kohsuke/github/GHRepositoryViews.java b/src/main/java/org/kohsuke/github/GHRepositoryViews.java new file mode 100644 index 0000000000..8990fb07f4 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHRepositoryViews.java @@ -0,0 +1,57 @@ +package org.kohsuke.github; + +import java.util.List; + +public class GHRepositoryViews{ + private Integer count; + private Integer uniques; + private List views; + + public GHRepositoryViews() { + } + + public GHRepositoryViews(Integer count, Integer uniques, List views) { + this.count = count; + this.uniques = uniques; + this.views = views; + } + + public Integer getCount() { + return count; + } + + public Integer getUniques() { + return uniques; + } + + public List getViews() { + return views; + } + + public static class DayViews { + private String timestamp; + private Integer count; + private Integer uniques; + + public String getTimestamp() { + return timestamp; + } + + public Integer getCount() { + return count; + } + + public Integer getUniques() { + return uniques; + } + + public DayViews() { + } + + public DayViews(String timestamp, Integer count, Integer uniques) { + this.timestamp = timestamp; + this.count = count; + this.uniques = uniques; + } + } +} diff --git a/src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java b/src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java new file mode 100644 index 0000000000..2c9ad3ca1e --- /dev/null +++ b/src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java @@ -0,0 +1,107 @@ +package org.kohsuke.github; + +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Arrays; +import java.util.Iterator; + +public class RepositoryTrafficMockTest { + final private String login = "kohsuke", repositoryName = "github-api"; + private void checkResponse(GHRepositoryViews expected, GHRepositoryViews actual){ + Assert.assertEquals(expected.getCount(), actual.getCount()); + Assert.assertEquals(expected.getUniques(), actual.getUniques()); + Assert.assertEquals(expected.getViews().size(), actual.getViews().size()); + Iterator expectedIt = expected.getViews().iterator(); + Iterator actualIt = actual.getViews().iterator(); + while(expectedIt.hasNext() && actualIt.hasNext()) { + GHRepositoryViews.DayViews expectedDayViews = expectedIt.next(); + GHRepositoryViews.DayViews actualDayViews = actualIt.next(); + Assert.assertEquals(expectedDayViews.getCount(), actualDayViews.getCount()); + Assert.assertEquals(expectedDayViews.getUniques(), actualDayViews.getUniques()); + Assert.assertEquals(expectedDayViews.getTimestamp(), actualDayViews.getTimestamp()); + } + } + + @Test + public void getViews() throws IOException{ + // example taken from the docs https://developer.github.com/v3/repos/traffic/#views + GHRepositoryViews expectedResult = new GHRepositoryViews( + 14850, + 3782, + Arrays.asList( + new GHRepositoryViews.DayViews("2016-10-10T00:00:00Z", 440,143), + new GHRepositoryViews.DayViews("2016-10-11T00:00:00Z", 1308,414), + new GHRepositoryViews.DayViews("2016-10-12T00:00:00Z", 1486,452), + new GHRepositoryViews.DayViews("2016-10-13T00:00:00Z", 1170,401), + new GHRepositoryViews.DayViews("2016-10-14T00:00:00Z", 868,266), + new GHRepositoryViews.DayViews("2016-10-15T00:00:00Z", 495,157), + new GHRepositoryViews.DayViews("2016-10-16T00:00:00Z", 524,175), + new GHRepositoryViews.DayViews("2016-10-17T00:00:00Z", 1263,412), + new GHRepositoryViews.DayViews("2016-10-18T00:00:00Z", 1402,417), + new GHRepositoryViews.DayViews("2016-10-19T00:00:00Z", 1394,424), + new GHRepositoryViews.DayViews("2016-10-20T00:00:00Z", 1492,448), + new GHRepositoryViews.DayViews("2016-10-21T00:00:00Z", 1153,332), + new GHRepositoryViews.DayViews("2016-10-22T00:00:00Z", 566,168), + new GHRepositoryViews.DayViews("2016-10-23T00:00:00Z", 675,184), + new GHRepositoryViews.DayViews("2016-10-24T00:00:00Z", 614,237) + ) + ); + String mockedGHRepositoryViewsResponse = GitHub.MAPPER.writeValueAsString(expectedResult); + + GitHub gitHub = GitHub.connect(login, null); + GitHub gitHubSpy = Mockito.spy(gitHub); + GHRepository repo = gitHubSpy.getUser(login).getRepository(repositoryName); + + + // accessing traffic info requires push access to the repo + // since we don't have that, let the mocking begin... + + HttpConnector connectorSpy = Mockito.spy(gitHubSpy.getConnector()); + Mockito.doReturn(connectorSpy).when(gitHubSpy).getConnector(); + + + // also known as the "uc" in the Requester class + HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class); + + + // needed for Requester.setRequestMethod + Mockito.doReturn("GET").when(mockHttpURLConnection).getRequestMethod(); + + + // this covers calls on "uc" in Requester.setupConnection and Requester.buildRequest + URL trafficURL = new URL("https://api.github.com/repos/"+login+"/"+repositoryName+"/traffic/views"); + Mockito.doReturn(mockHttpURLConnection).when(connectorSpy).connect(Mockito.eq(trafficURL)); + + + // make Requester.parse work + Mockito.doReturn(200).when(mockHttpURLConnection).getResponseCode(); + Mockito.doReturn("OK").when(mockHttpURLConnection).getResponseMessage(); + InputStream stubInputStream = IOUtils.toInputStream(mockedGHRepositoryViewsResponse, "UTF-8"); + Mockito.doReturn(stubInputStream).when(mockHttpURLConnection).getInputStream(); + + + GHRepositoryViews views = repo.getViews(); + + + checkResponse(expectedResult, views); + } + + @Test + public void getViewsAccessFailureDueToInsufficientPermissions() throws IOException { + GitHub gitHub = GitHub.connect(login, null); + GHRepository repo = gitHub.getUser(login).getRepository(repositoryName); + try { + repo.getViews(); + Assert.fail("Exception should be thrown, since we don't have permission to access repo's traffic info."); + } + catch (HttpException ex){ + } + } +} From 8accf07d4620d0d2ef0b2c0f1f8ce86303d8e929 Mon Sep 17 00:00:00 2001 From: adw1n Date: Tue, 1 Aug 2017 04:02:10 +0200 Subject: [PATCH 09/34] Changed timestamp (GHRepositoryViews.DayViews.timestamp) field type from String to Date. --- .../java/org/kohsuke/github/GHRepositoryViews.java | 11 +++++++++-- .../org/kohsuke/github/RepositoryTrafficMockTest.java | 9 ++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepositoryViews.java b/src/main/java/org/kohsuke/github/GHRepositoryViews.java index 8990fb07f4..1e7a627b0e 100644 --- a/src/main/java/org/kohsuke/github/GHRepositoryViews.java +++ b/src/main/java/org/kohsuke/github/GHRepositoryViews.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import java.util.Date; import java.util.List; public class GHRepositoryViews{ @@ -29,11 +30,11 @@ public List getViews() { } public static class DayViews { - private String timestamp; + private Date timestamp; private Integer count; private Integer uniques; - public String getTimestamp() { + public Date getTimestamp() { return timestamp; } @@ -49,6 +50,12 @@ public DayViews() { } public DayViews(String timestamp, Integer count, Integer uniques) { + this.timestamp = GitHub.parseDate(timestamp); + this.count = count; + this.uniques = uniques; + } + + public DayViews(Date timestamp, Integer count, Integer uniques) { this.timestamp = timestamp; this.count = count; this.uniques = uniques; diff --git a/src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java b/src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java index 2c9ad3ca1e..ecd944d35f 100644 --- a/src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java +++ b/src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.Test; @@ -9,8 +10,10 @@ import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Iterator; +import java.util.TimeZone; public class RepositoryTrafficMockTest { final private String login = "kohsuke", repositoryName = "github-api"; @@ -53,7 +56,11 @@ public void getViews() throws IOException{ new GHRepositoryViews.DayViews("2016-10-24T00:00:00Z", 614,237) ) ); - String mockedGHRepositoryViewsResponse = GitHub.MAPPER.writeValueAsString(expectedResult); + SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + ObjectMapper mapper = new ObjectMapper().setDateFormat(dateFormat); + String mockedGHRepositoryViewsResponse = mapper.writeValueAsString(expectedResult); + GitHub gitHub = GitHub.connect(login, null); GitHub gitHubSpy = Mockito.spy(gitHub); From a1819bf23265fdb2f3dd0768d61ee3a9feb58d7f Mon Sep 17 00:00:00 2001 From: adw1n Date: Tue, 1 Aug 2017 06:20:24 +0200 Subject: [PATCH 10/34] Added getClones method to GHRepository (https://developer.github.com/v3/repos/traffic/#clones). --- .../java/org/kohsuke/github/GHRepository.java | 7 + .../kohsuke/github/GHRepositoryClones.java | 33 ++++ .../github/GHRepositoryTrafficInfo.java | 57 ++++++ .../org/kohsuke/github/GHRepositoryViews.java | 41 +--- .../github/RepositoryTrafficMockTest.java | 114 ------------ .../kohsuke/github/RepositoryTrafficTest.java | 175 ++++++++++++++++++ 6 files changed, 277 insertions(+), 150 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/GHRepositoryClones.java create mode 100644 src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java delete mode 100644 src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java create mode 100644 src/test/java/org/kohsuke/github/RepositoryTrafficTest.java diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 82c9e30d9a..bf2a669ff1 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -1488,6 +1488,13 @@ public GHRepositoryViews getViews() throws IOException{ return root.retrieve().to(getApiTailUrl("/traffic/views"), GHRepositoryViews.class); } + /** + * https://developer.github.com/v3/repos/traffic/#clones + */ + public GHRepositoryClones getClones() throws IOException{ + return root.retrieve().to(getApiTailUrl("/traffic/clones"), GHRepositoryClones.class); + } + @Override public int hashCode() { return ("Repository:"+getOwnerName()+":"+name).hashCode(); diff --git a/src/main/java/org/kohsuke/github/GHRepositoryClones.java b/src/main/java/org/kohsuke/github/GHRepositoryClones.java new file mode 100644 index 0000000000..e88a902a7e --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHRepositoryClones.java @@ -0,0 +1,33 @@ +package org.kohsuke.github; + +import java.util.Date; +import java.util.List; + +public class GHRepositoryClones extends GHRepositoryTrafficInfo { + private List clones; + + public GHRepositoryClones() { + } + + public GHRepositoryClones(Integer count, Integer uniques, List clones) { + super(count, uniques); + this.clones = clones; + } + + public List getClones() { + return clones; + } + + public static class DayClones extends GHRepositoryTrafficInfo.DayInfo { + public DayClones() { + } + + public DayClones(String timestamp, Integer count, Integer uniques) { + super(timestamp, count, uniques); + } + + public DayClones(Date timestamp, Integer count, Integer uniques) { + super(timestamp, count, uniques); + } + } +} diff --git a/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java b/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java new file mode 100644 index 0000000000..143ed23a02 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java @@ -0,0 +1,57 @@ +package org.kohsuke.github; + +import java.util.Date; + +public abstract class GHRepositoryTrafficInfo { + private Integer count; + private Integer uniques; + + public GHRepositoryTrafficInfo() { + } + + public GHRepositoryTrafficInfo(Integer count, Integer uniques) { + this.count = count; + this.uniques = uniques; + } + + public Integer getCount() { + return count; + } + + public Integer getUniques() { + return uniques; + } + + public static abstract class DayInfo { + private Date timestamp; + private Integer count; + private Integer uniques; + + public Date getTimestamp() { + return timestamp; + } + + public Integer getCount() { + return count; + } + + public Integer getUniques() { + return uniques; + } + + public DayInfo() { + } + + public DayInfo(String timestamp, Integer count, Integer uniques) { + this.timestamp = GitHub.parseDate(timestamp); + this.count = count; + this.uniques = uniques; + } + + public DayInfo(Date timestamp, Integer count, Integer uniques) { + this.timestamp = timestamp; + this.count = count; + this.uniques = uniques; + } + } +} diff --git a/src/main/java/org/kohsuke/github/GHRepositoryViews.java b/src/main/java/org/kohsuke/github/GHRepositoryViews.java index 1e7a627b0e..0d6d9d8493 100644 --- a/src/main/java/org/kohsuke/github/GHRepositoryViews.java +++ b/src/main/java/org/kohsuke/github/GHRepositoryViews.java @@ -3,62 +3,31 @@ import java.util.Date; import java.util.List; -public class GHRepositoryViews{ - private Integer count; - private Integer uniques; +public class GHRepositoryViews extends GHRepositoryTrafficInfo { private List views; public GHRepositoryViews() { } public GHRepositoryViews(Integer count, Integer uniques, List views) { - this.count = count; - this.uniques = uniques; + super(count, uniques); this.views = views; } - public Integer getCount() { - return count; - } - - public Integer getUniques() { - return uniques; - } - public List getViews() { return views; } - public static class DayViews { - private Date timestamp; - private Integer count; - private Integer uniques; - - public Date getTimestamp() { - return timestamp; - } - - public Integer getCount() { - return count; - } - - public Integer getUniques() { - return uniques; - } - + public static class DayViews extends GHRepositoryTrafficInfo.DayInfo { public DayViews() { } public DayViews(String timestamp, Integer count, Integer uniques) { - this.timestamp = GitHub.parseDate(timestamp); - this.count = count; - this.uniques = uniques; + super(timestamp, count, uniques); } public DayViews(Date timestamp, Integer count, Integer uniques) { - this.timestamp = timestamp; - this.count = count; - this.uniques = uniques; + super(timestamp, count, uniques); } } } diff --git a/src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java b/src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java deleted file mode 100644 index ecd944d35f..0000000000 --- a/src/test/java/org/kohsuke/github/RepositoryTrafficMockTest.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.kohsuke.github; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.io.IOUtils; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Iterator; -import java.util.TimeZone; - -public class RepositoryTrafficMockTest { - final private String login = "kohsuke", repositoryName = "github-api"; - private void checkResponse(GHRepositoryViews expected, GHRepositoryViews actual){ - Assert.assertEquals(expected.getCount(), actual.getCount()); - Assert.assertEquals(expected.getUniques(), actual.getUniques()); - Assert.assertEquals(expected.getViews().size(), actual.getViews().size()); - Iterator expectedIt = expected.getViews().iterator(); - Iterator actualIt = actual.getViews().iterator(); - while(expectedIt.hasNext() && actualIt.hasNext()) { - GHRepositoryViews.DayViews expectedDayViews = expectedIt.next(); - GHRepositoryViews.DayViews actualDayViews = actualIt.next(); - Assert.assertEquals(expectedDayViews.getCount(), actualDayViews.getCount()); - Assert.assertEquals(expectedDayViews.getUniques(), actualDayViews.getUniques()); - Assert.assertEquals(expectedDayViews.getTimestamp(), actualDayViews.getTimestamp()); - } - } - - @Test - public void getViews() throws IOException{ - // example taken from the docs https://developer.github.com/v3/repos/traffic/#views - GHRepositoryViews expectedResult = new GHRepositoryViews( - 14850, - 3782, - Arrays.asList( - new GHRepositoryViews.DayViews("2016-10-10T00:00:00Z", 440,143), - new GHRepositoryViews.DayViews("2016-10-11T00:00:00Z", 1308,414), - new GHRepositoryViews.DayViews("2016-10-12T00:00:00Z", 1486,452), - new GHRepositoryViews.DayViews("2016-10-13T00:00:00Z", 1170,401), - new GHRepositoryViews.DayViews("2016-10-14T00:00:00Z", 868,266), - new GHRepositoryViews.DayViews("2016-10-15T00:00:00Z", 495,157), - new GHRepositoryViews.DayViews("2016-10-16T00:00:00Z", 524,175), - new GHRepositoryViews.DayViews("2016-10-17T00:00:00Z", 1263,412), - new GHRepositoryViews.DayViews("2016-10-18T00:00:00Z", 1402,417), - new GHRepositoryViews.DayViews("2016-10-19T00:00:00Z", 1394,424), - new GHRepositoryViews.DayViews("2016-10-20T00:00:00Z", 1492,448), - new GHRepositoryViews.DayViews("2016-10-21T00:00:00Z", 1153,332), - new GHRepositoryViews.DayViews("2016-10-22T00:00:00Z", 566,168), - new GHRepositoryViews.DayViews("2016-10-23T00:00:00Z", 675,184), - new GHRepositoryViews.DayViews("2016-10-24T00:00:00Z", 614,237) - ) - ); - SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); - ObjectMapper mapper = new ObjectMapper().setDateFormat(dateFormat); - String mockedGHRepositoryViewsResponse = mapper.writeValueAsString(expectedResult); - - - GitHub gitHub = GitHub.connect(login, null); - GitHub gitHubSpy = Mockito.spy(gitHub); - GHRepository repo = gitHubSpy.getUser(login).getRepository(repositoryName); - - - // accessing traffic info requires push access to the repo - // since we don't have that, let the mocking begin... - - HttpConnector connectorSpy = Mockito.spy(gitHubSpy.getConnector()); - Mockito.doReturn(connectorSpy).when(gitHubSpy).getConnector(); - - - // also known as the "uc" in the Requester class - HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class); - - - // needed for Requester.setRequestMethod - Mockito.doReturn("GET").when(mockHttpURLConnection).getRequestMethod(); - - - // this covers calls on "uc" in Requester.setupConnection and Requester.buildRequest - URL trafficURL = new URL("https://api.github.com/repos/"+login+"/"+repositoryName+"/traffic/views"); - Mockito.doReturn(mockHttpURLConnection).when(connectorSpy).connect(Mockito.eq(trafficURL)); - - - // make Requester.parse work - Mockito.doReturn(200).when(mockHttpURLConnection).getResponseCode(); - Mockito.doReturn("OK").when(mockHttpURLConnection).getResponseMessage(); - InputStream stubInputStream = IOUtils.toInputStream(mockedGHRepositoryViewsResponse, "UTF-8"); - Mockito.doReturn(stubInputStream).when(mockHttpURLConnection).getInputStream(); - - - GHRepositoryViews views = repo.getViews(); - - - checkResponse(expectedResult, views); - } - - @Test - public void getViewsAccessFailureDueToInsufficientPermissions() throws IOException { - GitHub gitHub = GitHub.connect(login, null); - GHRepository repo = gitHub.getUser(login).getRepository(repositoryName); - try { - repo.getViews(); - Assert.fail("Exception should be thrown, since we don't have permission to access repo's traffic info."); - } - catch (HttpException ex){ - } - } -} diff --git a/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java b/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java new file mode 100644 index 0000000000..27e3915bd2 --- /dev/null +++ b/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java @@ -0,0 +1,175 @@ +package org.kohsuke.github; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.TimeZone; + +public class RepositoryTrafficTest { + final private String login = "kohsuke", repositoryName = "github-api"; + + @SuppressWarnings("unchecked") + private void checkResponse(T expected, T actual){ + Assert.assertEquals(expected.getCount(), actual.getCount()); + Assert.assertEquals(expected.getUniques(), actual.getUniques()); + + List expectedList = null; + List actualList = null; + Iterator expectedIt; + Iterator actualIt; + + if(expected instanceof GHRepositoryViews){ + expectedList = (List)((List)((GHRepositoryViews) expected).getViews()); + actualList = (List)((List)((GHRepositoryViews) actual).getViews()); + } + else if(expected instanceof GHRepositoryClones){ + expectedList = (List)((List)((GHRepositoryClones) expected).getClones()); + actualList = (List)((List)((GHRepositoryClones) actual).getClones()); + } + + Assert.assertEquals(expectedList.size(), actualList.size()); + expectedIt = expectedList.iterator(); + actualIt = actualList.iterator(); + + while(expectedIt.hasNext() && actualIt.hasNext()) { + T.DayInfo expectedDayInfo = expectedIt.next(); + T.DayInfo actualDayInfo = actualIt.next(); + Assert.assertEquals(expectedDayInfo.getCount(), actualDayInfo.getCount()); + Assert.assertEquals(expectedDayInfo.getUniques(), actualDayInfo.getUniques()); + Assert.assertEquals(expectedDayInfo.getTimestamp(), actualDayInfo.getTimestamp()); + } + } + + private void testTraffic(T expectedResult) throws IOException{ + SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + ObjectMapper mapper = new ObjectMapper().setDateFormat(dateFormat); + String mockedResponse = mapper.writeValueAsString(expectedResult); + + + GitHub gitHub = GitHub.connect(login, null); + GitHub gitHubSpy = Mockito.spy(gitHub); + GHRepository repo = gitHubSpy.getUser(login).getRepository(repositoryName); + + + // accessing traffic info requires push access to the repo + // since we don't have that, let the mocking begin... + + HttpConnector connectorSpy = Mockito.spy(gitHubSpy.getConnector()); + Mockito.doReturn(connectorSpy).when(gitHubSpy).getConnector(); + + + // also known as the "uc" in the Requester class + HttpURLConnection mockHttpURLConnection = Mockito.mock(HttpURLConnection.class); + + + // needed for Requester.setRequestMethod + Mockito.doReturn("GET").when(mockHttpURLConnection).getRequestMethod(); + + + // this covers calls on "uc" in Requester.setupConnection and Requester.buildRequest + URL trafficURL = new URL( + "https://api.github.com/repos/"+login+"/"+repositoryName+"/traffic/" + + ((expectedResult instanceof GHRepositoryViews) ? "views" : "clones") + ); + Mockito.doReturn(mockHttpURLConnection).when(connectorSpy).connect(Mockito.eq(trafficURL)); + + + // make Requester.parse work + Mockito.doReturn(200).when(mockHttpURLConnection).getResponseCode(); + Mockito.doReturn("OK").when(mockHttpURLConnection).getResponseMessage(); + InputStream stubInputStream = IOUtils.toInputStream(mockedResponse, "UTF-8"); + Mockito.doReturn(stubInputStream).when(mockHttpURLConnection).getInputStream(); + + if(expectedResult instanceof GHRepositoryViews){ + GHRepositoryViews views = repo.getViews(); + checkResponse(expectedResult, views); + } + else if(expectedResult instanceof GHRepositoryClones) { + GHRepositoryClones clones = repo.getClones(); + checkResponse(expectedResult, clones); + } + } + + @Test + public void testGetViews() throws IOException{ + GHRepositoryViews expectedResult = new GHRepositoryViews( + 21523359, + 65534, + Arrays.asList( + new GHRepositoryViews.DayViews("2016-10-10T00:00:00Z", 3, 2), + new GHRepositoryViews.DayViews("2016-10-11T00:00:00Z", 9, 4), + new GHRepositoryViews.DayViews("2016-10-12T00:00:00Z", 27, 8), + new GHRepositoryViews.DayViews("2016-10-13T00:00:00Z", 81, 16), + new GHRepositoryViews.DayViews("2016-10-14T00:00:00Z", 243, 32), + new GHRepositoryViews.DayViews("2016-10-15T00:00:00Z", 729, 64), + new GHRepositoryViews.DayViews("2016-10-16T00:00:00Z", 2187, 128), + new GHRepositoryViews.DayViews("2016-10-17T00:00:00Z", 6561, 256), + new GHRepositoryViews.DayViews("2016-10-18T00:00:00Z", 19683, 512), + new GHRepositoryViews.DayViews("2016-10-19T00:00:00Z", 59049, 1024), + new GHRepositoryViews.DayViews("2016-10-20T00:00:00Z", 177147, 2048), + new GHRepositoryViews.DayViews("2016-10-21T00:00:00Z", 531441, 4096), + new GHRepositoryViews.DayViews("2016-10-22T00:00:00Z", 1594323, 8192), + new GHRepositoryViews.DayViews("2016-10-23T00:00:00Z", 4782969, 16384), + new GHRepositoryViews.DayViews("2016-10-24T00:00:00Z", 14348907, 32768) + ) + ); + testTraffic(expectedResult); + } + + @Test + public void testGetClones() throws IOException{ + GHRepositoryClones expectedResult = new GHRepositoryClones( + 1500, + 455, + Arrays.asList( + new GHRepositoryClones.DayClones("2016-10-10T00:00:00Z", 10,3), + new GHRepositoryClones.DayClones("2016-10-11T00:00:00Z", 20,6), + new GHRepositoryClones.DayClones("2016-10-12T00:00:00Z", 30,5), + new GHRepositoryClones.DayClones("2016-10-13T00:00:00Z", 40,7), + new GHRepositoryClones.DayClones("2016-10-14T00:00:00Z", 50,11), + new GHRepositoryClones.DayClones("2016-10-15T00:00:00Z", 60,12), + new GHRepositoryClones.DayClones("2016-10-16T00:00:00Z", 70,19), + new GHRepositoryClones.DayClones("2016-10-17T00:00:00Z", 170,111), + new GHRepositoryClones.DayClones("2016-10-18T00:00:00Z", 180,70), + new GHRepositoryClones.DayClones("2016-10-19T00:00:00Z", 190,10), + new GHRepositoryClones.DayClones("2016-10-20T00:00:00Z", 200,18), + new GHRepositoryClones.DayClones("2016-10-21T00:00:00Z", 210,8), + new GHRepositoryClones.DayClones("2016-10-22T00:00:00Z", 220,168), + new GHRepositoryClones.DayClones("2016-10-23T00:00:00Z", 5,2), + new GHRepositoryClones.DayClones("2016-10-24T00:00:00Z", 45,5) + ) + ); + testTraffic(expectedResult); + } + + @Test + public void testGetTrafficStatsAccessFailureDueToInsufficientPermissions() throws IOException { + String errorMsg = "Exception should be thrown, since we don't have permission to access repo traffic info."; + GitHub gitHub = GitHub.connect(login, null); + GHRepository repo = gitHub.getUser(login).getRepository(repositoryName); + try { + repo.getViews(); + Assert.fail(errorMsg); + } + catch (HttpException ex){ + } + try { + repo.getClones(); + Assert.fail(errorMsg); + } + catch (HttpException ex){ + } + } +} From f2a2ad90b7a8ed334444c7523f829b9892d440c1 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Tue, 29 Aug 2017 11:30:25 -0700 Subject: [PATCH 11/34] Switch to a concurrent hash map --- .../org/kohsuke/github/GHCommitStatus.java | 1 + src/main/java/org/kohsuke/github/GitHub.java | 69 ++++++------------- 2 files changed, 23 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHCommitStatus.java b/src/main/java/org/kohsuke/github/GHCommitStatus.java index 241f8b98b4..f71be99622 100644 --- a/src/main/java/org/kohsuke/github/GHCommitStatus.java +++ b/src/main/java/org/kohsuke/github/GHCommitStatus.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import java.io.IOException; import java.net.URL; /** diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index f787a2db45..bde74b1262 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -47,6 +47,7 @@ import java.util.Map; import java.util.Set; import java.util.TimeZone; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -147,8 +148,8 @@ public class GitHub { } } - users = new Hashtable(); - orgs = new Hashtable(); + users = new ConcurrentHashMap(); + orgs = new ConcurrentHashMap(); this.rateLimitHandler = rateLimitHandler; this.abuseLimitHandler = abuseLimitHandler; @@ -360,12 +361,6 @@ public GHRateLimit rateLimit() throws IOException { @WithBridgeMethods(GHUser.class) public GHMyself getMyself() throws IOException { requireCredential(); - - // This entire block is under synchronization to avoid the relatively common case - // where a bunch of threads try to enter this code simultaneously. While we could - // scope the synchronization separately around the map retrieval and update (or use a concurrent hash) - // map, the point is to avoid making unnecessary GH API calls, which are expensive from - // an API rate standpoint synchronized (this) { if (this.myself != null) return myself; @@ -381,20 +376,13 @@ public GHMyself getMyself() throws IOException { * Obtains the object that represents the named user. */ public GHUser getUser(String login) throws IOException { - // This entire block is under synchronization to avoid the relatively common case - // where a bunch of threads try to enter this code simultaneously. While we could - // scope the synchronization separately around the map retrieval and update (or use a concurrent hash - // map), the point is to avoid making unnecessary GH API calls, which are expensive from - // an API rate standpoint - synchronized (users) { - GHUser u = users.get(login); - if (u == null) { - u = retrieve().to("/users/" + login, GHUser.class); - u.root = this; - users.put(u.getLogin(), u); - } - return u; + GHUser u = users.get(login); + if (u == null) { + u = retrieve().to("/users/" + login, GHUser.class); + u.root = this; + users.put(u.getLogin(), u); } + return u; } @@ -402,43 +390,30 @@ public GHUser getUser(String login) throws IOException { * clears all cached data in order for external changes (modifications and del */ public void refreshCache() { - synchronized (users) { - users.clear(); - } - synchronized (orgs) { - orgs.clear(); - } + users.clear(); + orgs.clear(); } /** * Interns the given {@link GHUser}. */ protected GHUser getUser(GHUser orig) { - synchronized (users) { - GHUser u = users.get(orig.getLogin()); - if (u==null) { - orig.root = this; - users.put(orig.getLogin(),orig); - return orig; - } - return u; + GHUser u = users.get(orig.getLogin()); + if (u==null) { + orig.root = this; + users.put(orig.getLogin(),orig); + return orig; } + return u; } public GHOrganization getOrganization(String name) throws IOException { - // This entire block is under synchronization to avoid the relatively common case - // where a bunch of threads try to enter this code simultaneously. While we could - // scope the synchronization separately around the map retrieval and update (or use a concurrent hash - // map), the point is to avoid making unnecessary GH API calls, which are expensive from - // an API rate standpoint - synchronized (orgs) { - GHOrganization o = orgs.get(name); - if (o==null) { - o = retrieve().to("/orgs/" + name, GHOrganization.class).wrapUp(this); - orgs.put(name,o); - } - return o; + GHOrganization o = orgs.get(name); + if (o==null) { + o = retrieve().to("/orgs/" + name, GHOrganization.class).wrapUp(this); + orgs.put(name,o); } + return o; } /** From 57c36f437a7187769ecc2a9847a2f36b963ba401 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 08:19:29 -0700 Subject: [PATCH 12/34] [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 733dd51a97..9b11b977f3 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.88 + 1.89-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.88 + HEAD From 9af8112148fec83e706aca83afd8a9d5c734f0e5 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 11:37:18 -0700 Subject: [PATCH 13/34] Tightening up access control and use primitive type --- .../kohsuke/github/GHRepositoryClones.java | 19 ++++++++---- .../github/GHRepositoryTrafficInfo.java | 29 ++++++++++--------- .../org/kohsuke/github/GHRepositoryViews.java | 19 ++++++++---- .../kohsuke/github/RepositoryTrafficTest.java | 22 +++++--------- 4 files changed, 51 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepositoryClones.java b/src/main/java/org/kohsuke/github/GHRepositoryClones.java index e88a902a7e..1bd126038a 100644 --- a/src/main/java/org/kohsuke/github/GHRepositoryClones.java +++ b/src/main/java/org/kohsuke/github/GHRepositoryClones.java @@ -3,13 +3,18 @@ import java.util.Date; import java.util.List; +/** + * Repository clone statistics. + * + * @see GHRepository#getClones() + */ public class GHRepositoryClones extends GHRepositoryTrafficInfo { private List clones; - public GHRepositoryClones() { + /*package*/ GHRepositoryClones() { } - public GHRepositoryClones(Integer count, Integer uniques, List clones) { + /*package*/ GHRepositoryClones(Integer count, Integer uniques, List clones) { super(count, uniques); this.clones = clones; } @@ -18,15 +23,19 @@ public List getClones() { return clones; } + public List getDailyInfo() { + return getClones(); + } + public static class DayClones extends GHRepositoryTrafficInfo.DayInfo { - public DayClones() { + /*package*/ DayClones() { } - public DayClones(String timestamp, Integer count, Integer uniques) { + /*package*/ DayClones(String timestamp, int count, int uniques) { super(timestamp, count, uniques); } - public DayClones(Date timestamp, Integer count, Integer uniques) { + /*package*/ DayClones(Date timestamp, int count, int uniques) { super(timestamp, count, uniques); } } diff --git a/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java b/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java index 143ed23a02..24bd177bd2 100644 --- a/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java +++ b/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java @@ -1,54 +1,57 @@ package org.kohsuke.github; import java.util.Date; +import java.util.List; public abstract class GHRepositoryTrafficInfo { - private Integer count; - private Integer uniques; + private int count; + private int uniques; - public GHRepositoryTrafficInfo() { + /*package*/ GHRepositoryTrafficInfo() { } - public GHRepositoryTrafficInfo(Integer count, Integer uniques) { + /*package*/ GHRepositoryTrafficInfo(int count, int uniques) { this.count = count; this.uniques = uniques; } - public Integer getCount() { + public int getCount() { return count; } - public Integer getUniques() { + public int getUniques() { return uniques; } + public abstract List getDailyInfo(); + public static abstract class DayInfo { private Date timestamp; - private Integer count; - private Integer uniques; + private int count; + private int uniques; public Date getTimestamp() { return timestamp; } - public Integer getCount() { + public int getCount() { return count; } - public Integer getUniques() { + public int getUniques() { return uniques; } - public DayInfo() { + /*package*/ DayInfo() { } - public DayInfo(String timestamp, Integer count, Integer uniques) { + /*package*/ DayInfo(String timestamp, Integer count, Integer uniques) { this.timestamp = GitHub.parseDate(timestamp); this.count = count; this.uniques = uniques; } - public DayInfo(Date timestamp, Integer count, Integer uniques) { + /*package*/ DayInfo(Date timestamp, Integer count, Integer uniques) { this.timestamp = timestamp; this.count = count; this.uniques = uniques; diff --git a/src/main/java/org/kohsuke/github/GHRepositoryViews.java b/src/main/java/org/kohsuke/github/GHRepositoryViews.java index 0d6d9d8493..2f7ea80f78 100644 --- a/src/main/java/org/kohsuke/github/GHRepositoryViews.java +++ b/src/main/java/org/kohsuke/github/GHRepositoryViews.java @@ -3,13 +3,18 @@ import java.util.Date; import java.util.List; +/** + * Repository view statistics. + * + * @see GHRepository#getViews() + */ public class GHRepositoryViews extends GHRepositoryTrafficInfo { private List views; - public GHRepositoryViews() { + /*package*/ GHRepositoryViews() { } - public GHRepositoryViews(Integer count, Integer uniques, List views) { + /*package*/ GHRepositoryViews(int count, int uniques, List views) { super(count, uniques); this.views = views; } @@ -18,15 +23,19 @@ public List getViews() { return views; } + public List getDailyInfo() { + return getViews(); + } + public static class DayViews extends GHRepositoryTrafficInfo.DayInfo { - public DayViews() { + /*package*/ DayViews() { } - public DayViews(String timestamp, Integer count, Integer uniques) { + /*package*/ DayViews(String timestamp, int count, int uniques) { super(timestamp, count, uniques); } - public DayViews(Date timestamp, Integer count, Integer uniques) { + /*package*/ DayViews(Date timestamp, int count, int uniques) { super(timestamp, count, uniques); } } diff --git a/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java b/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java index 27e3915bd2..66cccd7ed3 100644 --- a/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java +++ b/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java @@ -4,6 +4,7 @@ import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.Test; +import org.kohsuke.github.GHRepositoryTrafficInfo.DayInfo; import org.mockito.Mockito; import java.io.IOException; @@ -24,27 +25,18 @@ private void checkResponse(T expected, T act Assert.assertEquals(expected.getCount(), actual.getCount()); Assert.assertEquals(expected.getUniques(), actual.getUniques()); - List expectedList = null; - List actualList = null; - Iterator expectedIt; - Iterator actualIt; - - if(expected instanceof GHRepositoryViews){ - expectedList = (List)((List)((GHRepositoryViews) expected).getViews()); - actualList = (List)((List)((GHRepositoryViews) actual).getViews()); - } - else if(expected instanceof GHRepositoryClones){ - expectedList = (List)((List)((GHRepositoryClones) expected).getClones()); - actualList = (List)((List)((GHRepositoryClones) actual).getClones()); - } + List expectedList = expected.getDailyInfo(); + List actualList = actual.getDailyInfo(); + Iterator expectedIt; + Iterator actualIt; Assert.assertEquals(expectedList.size(), actualList.size()); expectedIt = expectedList.iterator(); actualIt = actualList.iterator(); while(expectedIt.hasNext() && actualIt.hasNext()) { - T.DayInfo expectedDayInfo = expectedIt.next(); - T.DayInfo actualDayInfo = actualIt.next(); + DayInfo expectedDayInfo = expectedIt.next(); + DayInfo actualDayInfo = actualIt.next(); Assert.assertEquals(expectedDayInfo.getCount(), actualDayInfo.getCount()); Assert.assertEquals(expectedDayInfo.getUniques(), actualDayInfo.getUniques()); Assert.assertEquals(expectedDayInfo.getTimestamp(), actualDayInfo.getTimestamp()); From 2c80ef178d7e73ec717442942a151a5569fe05d8 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 11:39:12 -0700 Subject: [PATCH 14/34] Capture commonality between total and daily --- .../kohsuke/github/GHRepositoryTrafficInfo.java | 4 ++-- .../java/org/kohsuke/github/TrafficInfo.java | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/TrafficInfo.java diff --git a/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java b/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java index 24bd177bd2..7336c93285 100644 --- a/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java +++ b/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java @@ -3,7 +3,7 @@ import java.util.Date; import java.util.List; -public abstract class GHRepositoryTrafficInfo { +public abstract class GHRepositoryTrafficInfo implements TrafficInfo { private int count; private int uniques; @@ -25,7 +25,7 @@ public int getUniques() { public abstract List getDailyInfo(); - public static abstract class DayInfo { + public static abstract class DayInfo implements TrafficInfo { private Date timestamp; private int count; private int uniques; diff --git a/src/main/java/org/kohsuke/github/TrafficInfo.java b/src/main/java/org/kohsuke/github/TrafficInfo.java new file mode 100644 index 0000000000..9b232e9f1a --- /dev/null +++ b/src/main/java/org/kohsuke/github/TrafficInfo.java @@ -0,0 +1,16 @@ +package org.kohsuke.github; + +/** + * @author Kohsuke Kawaguchi + */ +public interface TrafficInfo { + /** + * Total count of hits. + */ + int getCount(); + + /** + * Unique visitors. + */ + int getUniques(); +} From fb4706721518e47aa29fde685276d1d2509bbf2a Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 11:40:28 -0700 Subject: [PATCH 15/34] Naming changes to emphasize that these are just traffic info --- .../java/org/kohsuke/github/GHRepository.java | 8 +- .../github/GHRepositoryCloneTraffic.java | 42 +++++++++ .../kohsuke/github/GHRepositoryClones.java | 42 --------- .../github/GHRepositoryViewTraffic.java | 42 +++++++++ .../org/kohsuke/github/GHRepositoryViews.java | 42 --------- .../kohsuke/github/RepositoryTrafficTest.java | 93 ++++++++++--------- 6 files changed, 135 insertions(+), 134 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/GHRepositoryCloneTraffic.java delete mode 100644 src/main/java/org/kohsuke/github/GHRepositoryClones.java create mode 100644 src/main/java/org/kohsuke/github/GHRepositoryViewTraffic.java delete mode 100644 src/main/java/org/kohsuke/github/GHRepositoryViews.java diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index bf2a669ff1..2c71592321 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -1484,15 +1484,15 @@ public GHNotificationStream listNotifications() { /** * https://developer.github.com/v3/repos/traffic/#views */ - public GHRepositoryViews getViews() throws IOException{ - return root.retrieve().to(getApiTailUrl("/traffic/views"), GHRepositoryViews.class); + public GHRepositoryViewTraffic getViewTraffic() throws IOException{ + return root.retrieve().to(getApiTailUrl("/traffic/views"), GHRepositoryViewTraffic.class); } /** * https://developer.github.com/v3/repos/traffic/#clones */ - public GHRepositoryClones getClones() throws IOException{ - return root.retrieve().to(getApiTailUrl("/traffic/clones"), GHRepositoryClones.class); + public GHRepositoryCloneTraffic getCloneTraffic() throws IOException{ + return root.retrieve().to(getApiTailUrl("/traffic/clones"), GHRepositoryCloneTraffic.class); } @Override diff --git a/src/main/java/org/kohsuke/github/GHRepositoryCloneTraffic.java b/src/main/java/org/kohsuke/github/GHRepositoryCloneTraffic.java new file mode 100644 index 0000000000..497392deb2 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHRepositoryCloneTraffic.java @@ -0,0 +1,42 @@ +package org.kohsuke.github; + +import java.util.Date; +import java.util.List; + +/** + * Repository clone statistics. + * + * @see GHRepository#getCloneTraffic() + */ +public class GHRepositoryCloneTraffic extends GHRepositoryTrafficInfo { + private List clones; + + /*package*/ GHRepositoryCloneTraffic() { + } + + /*package*/ GHRepositoryCloneTraffic(Integer count, Integer uniques, List clones) { + super(count, uniques); + this.clones = clones; + } + + public List getClones() { + return clones; + } + + public List getDailyInfo() { + return getClones(); + } + + public static class DayInfo extends GHRepositoryTrafficInfo.DayInfo { + /*package*/ DayInfo() { + } + + /*package*/ DayInfo(String timestamp, int count, int uniques) { + super(timestamp, count, uniques); + } + + /*package*/ DayInfo(Date timestamp, int count, int uniques) { + super(timestamp, count, uniques); + } + } +} diff --git a/src/main/java/org/kohsuke/github/GHRepositoryClones.java b/src/main/java/org/kohsuke/github/GHRepositoryClones.java deleted file mode 100644 index 1bd126038a..0000000000 --- a/src/main/java/org/kohsuke/github/GHRepositoryClones.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.kohsuke.github; - -import java.util.Date; -import java.util.List; - -/** - * Repository clone statistics. - * - * @see GHRepository#getClones() - */ -public class GHRepositoryClones extends GHRepositoryTrafficInfo { - private List clones; - - /*package*/ GHRepositoryClones() { - } - - /*package*/ GHRepositoryClones(Integer count, Integer uniques, List clones) { - super(count, uniques); - this.clones = clones; - } - - public List getClones() { - return clones; - } - - public List getDailyInfo() { - return getClones(); - } - - public static class DayClones extends GHRepositoryTrafficInfo.DayInfo { - /*package*/ DayClones() { - } - - /*package*/ DayClones(String timestamp, int count, int uniques) { - super(timestamp, count, uniques); - } - - /*package*/ DayClones(Date timestamp, int count, int uniques) { - super(timestamp, count, uniques); - } - } -} diff --git a/src/main/java/org/kohsuke/github/GHRepositoryViewTraffic.java b/src/main/java/org/kohsuke/github/GHRepositoryViewTraffic.java new file mode 100644 index 0000000000..42c716cc6e --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHRepositoryViewTraffic.java @@ -0,0 +1,42 @@ +package org.kohsuke.github; + +import java.util.Date; +import java.util.List; + +/** + * Repository view statistics. + * + * @see GHRepository#getViewTraffic() + */ +public class GHRepositoryViewTraffic extends GHRepositoryTrafficInfo { + private List views; + + /*package*/ GHRepositoryViewTraffic() { + } + + /*package*/ GHRepositoryViewTraffic(int count, int uniques, List views) { + super(count, uniques); + this.views = views; + } + + public List getViews() { + return views; + } + + public List getDailyInfo() { + return getViews(); + } + + public static class Daily extends GHRepositoryTrafficInfo.DayInfo { + /*package*/ Daily() { + } + + /*package*/ Daily(String timestamp, int count, int uniques) { + super(timestamp, count, uniques); + } + + /*package*/ Daily(Date timestamp, int count, int uniques) { + super(timestamp, count, uniques); + } + } +} diff --git a/src/main/java/org/kohsuke/github/GHRepositoryViews.java b/src/main/java/org/kohsuke/github/GHRepositoryViews.java deleted file mode 100644 index 2f7ea80f78..0000000000 --- a/src/main/java/org/kohsuke/github/GHRepositoryViews.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.kohsuke.github; - -import java.util.Date; -import java.util.List; - -/** - * Repository view statistics. - * - * @see GHRepository#getViews() - */ -public class GHRepositoryViews extends GHRepositoryTrafficInfo { - private List views; - - /*package*/ GHRepositoryViews() { - } - - /*package*/ GHRepositoryViews(int count, int uniques, List views) { - super(count, uniques); - this.views = views; - } - - public List getViews() { - return views; - } - - public List getDailyInfo() { - return getViews(); - } - - public static class DayViews extends GHRepositoryTrafficInfo.DayInfo { - /*package*/ DayViews() { - } - - /*package*/ DayViews(String timestamp, int count, int uniques) { - super(timestamp, count, uniques); - } - - /*package*/ DayViews(Date timestamp, int count, int uniques) { - super(timestamp, count, uniques); - } - } -} diff --git a/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java b/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java index 66cccd7ed3..64864acfa2 100644 --- a/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java +++ b/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java @@ -4,7 +4,8 @@ import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.Test; -import org.kohsuke.github.GHRepositoryTrafficInfo.DayInfo; +import org.kohsuke.github.GHRepositoryCloneTraffic.DayInfo; +import org.kohsuke.github.GHRepositoryViewTraffic.Daily; import org.mockito.Mockito; import java.io.IOException; @@ -25,18 +26,18 @@ private void checkResponse(T expected, T act Assert.assertEquals(expected.getCount(), actual.getCount()); Assert.assertEquals(expected.getUniques(), actual.getUniques()); - List expectedList = expected.getDailyInfo(); - List actualList = actual.getDailyInfo(); - Iterator expectedIt; - Iterator actualIt; + List expectedList = expected.getDailyInfo(); + List actualList = actual.getDailyInfo(); + Iterator expectedIt; + Iterator actualIt; Assert.assertEquals(expectedList.size(), actualList.size()); expectedIt = expectedList.iterator(); actualIt = actualList.iterator(); while(expectedIt.hasNext() && actualIt.hasNext()) { - DayInfo expectedDayInfo = expectedIt.next(); - DayInfo actualDayInfo = actualIt.next(); + GHRepositoryTrafficInfo.DayInfo expectedDayInfo = expectedIt.next(); + GHRepositoryTrafficInfo.DayInfo actualDayInfo = actualIt.next(); Assert.assertEquals(expectedDayInfo.getCount(), actualDayInfo.getCount()); Assert.assertEquals(expectedDayInfo.getUniques(), actualDayInfo.getUniques()); Assert.assertEquals(expectedDayInfo.getTimestamp(), actualDayInfo.getTimestamp()); @@ -73,7 +74,7 @@ private void testTraffic(T expectedResult) t // this covers calls on "uc" in Requester.setupConnection and Requester.buildRequest URL trafficURL = new URL( "https://api.github.com/repos/"+login+"/"+repositoryName+"/traffic/" + - ((expectedResult instanceof GHRepositoryViews) ? "views" : "clones") + ((expectedResult instanceof GHRepositoryViewTraffic) ? "views" : "clones") ); Mockito.doReturn(mockHttpURLConnection).when(connectorSpy).connect(Mockito.eq(trafficURL)); @@ -84,37 +85,37 @@ private void testTraffic(T expectedResult) t InputStream stubInputStream = IOUtils.toInputStream(mockedResponse, "UTF-8"); Mockito.doReturn(stubInputStream).when(mockHttpURLConnection).getInputStream(); - if(expectedResult instanceof GHRepositoryViews){ - GHRepositoryViews views = repo.getViews(); + if(expectedResult instanceof GHRepositoryViewTraffic){ + GHRepositoryViewTraffic views = repo.getViewTraffic(); checkResponse(expectedResult, views); } - else if(expectedResult instanceof GHRepositoryClones) { - GHRepositoryClones clones = repo.getClones(); + else if(expectedResult instanceof GHRepositoryCloneTraffic) { + GHRepositoryCloneTraffic clones = repo.getCloneTraffic(); checkResponse(expectedResult, clones); } } @Test public void testGetViews() throws IOException{ - GHRepositoryViews expectedResult = new GHRepositoryViews( + GHRepositoryViewTraffic expectedResult = new GHRepositoryViewTraffic( 21523359, 65534, Arrays.asList( - new GHRepositoryViews.DayViews("2016-10-10T00:00:00Z", 3, 2), - new GHRepositoryViews.DayViews("2016-10-11T00:00:00Z", 9, 4), - new GHRepositoryViews.DayViews("2016-10-12T00:00:00Z", 27, 8), - new GHRepositoryViews.DayViews("2016-10-13T00:00:00Z", 81, 16), - new GHRepositoryViews.DayViews("2016-10-14T00:00:00Z", 243, 32), - new GHRepositoryViews.DayViews("2016-10-15T00:00:00Z", 729, 64), - new GHRepositoryViews.DayViews("2016-10-16T00:00:00Z", 2187, 128), - new GHRepositoryViews.DayViews("2016-10-17T00:00:00Z", 6561, 256), - new GHRepositoryViews.DayViews("2016-10-18T00:00:00Z", 19683, 512), - new GHRepositoryViews.DayViews("2016-10-19T00:00:00Z", 59049, 1024), - new GHRepositoryViews.DayViews("2016-10-20T00:00:00Z", 177147, 2048), - new GHRepositoryViews.DayViews("2016-10-21T00:00:00Z", 531441, 4096), - new GHRepositoryViews.DayViews("2016-10-22T00:00:00Z", 1594323, 8192), - new GHRepositoryViews.DayViews("2016-10-23T00:00:00Z", 4782969, 16384), - new GHRepositoryViews.DayViews("2016-10-24T00:00:00Z", 14348907, 32768) + new Daily("2016-10-10T00:00:00Z", 3, 2), + new Daily("2016-10-11T00:00:00Z", 9, 4), + new Daily("2016-10-12T00:00:00Z", 27, 8), + new Daily("2016-10-13T00:00:00Z", 81, 16), + new Daily("2016-10-14T00:00:00Z", 243, 32), + new Daily("2016-10-15T00:00:00Z", 729, 64), + new Daily("2016-10-16T00:00:00Z", 2187, 128), + new Daily("2016-10-17T00:00:00Z", 6561, 256), + new Daily("2016-10-18T00:00:00Z", 19683, 512), + new Daily("2016-10-19T00:00:00Z", 59049, 1024), + new Daily("2016-10-20T00:00:00Z", 177147, 2048), + new Daily("2016-10-21T00:00:00Z", 531441, 4096), + new Daily("2016-10-22T00:00:00Z", 1594323, 8192), + new Daily("2016-10-23T00:00:00Z", 4782969, 16384), + new Daily("2016-10-24T00:00:00Z", 14348907, 32768) ) ); testTraffic(expectedResult); @@ -122,25 +123,25 @@ public void testGetViews() throws IOException{ @Test public void testGetClones() throws IOException{ - GHRepositoryClones expectedResult = new GHRepositoryClones( + GHRepositoryCloneTraffic expectedResult = new GHRepositoryCloneTraffic( 1500, 455, Arrays.asList( - new GHRepositoryClones.DayClones("2016-10-10T00:00:00Z", 10,3), - new GHRepositoryClones.DayClones("2016-10-11T00:00:00Z", 20,6), - new GHRepositoryClones.DayClones("2016-10-12T00:00:00Z", 30,5), - new GHRepositoryClones.DayClones("2016-10-13T00:00:00Z", 40,7), - new GHRepositoryClones.DayClones("2016-10-14T00:00:00Z", 50,11), - new GHRepositoryClones.DayClones("2016-10-15T00:00:00Z", 60,12), - new GHRepositoryClones.DayClones("2016-10-16T00:00:00Z", 70,19), - new GHRepositoryClones.DayClones("2016-10-17T00:00:00Z", 170,111), - new GHRepositoryClones.DayClones("2016-10-18T00:00:00Z", 180,70), - new GHRepositoryClones.DayClones("2016-10-19T00:00:00Z", 190,10), - new GHRepositoryClones.DayClones("2016-10-20T00:00:00Z", 200,18), - new GHRepositoryClones.DayClones("2016-10-21T00:00:00Z", 210,8), - new GHRepositoryClones.DayClones("2016-10-22T00:00:00Z", 220,168), - new GHRepositoryClones.DayClones("2016-10-23T00:00:00Z", 5,2), - new GHRepositoryClones.DayClones("2016-10-24T00:00:00Z", 45,5) + new DayInfo("2016-10-10T00:00:00Z", 10,3), + new DayInfo("2016-10-11T00:00:00Z", 20,6), + new DayInfo("2016-10-12T00:00:00Z", 30,5), + new DayInfo("2016-10-13T00:00:00Z", 40,7), + new DayInfo("2016-10-14T00:00:00Z", 50,11), + new DayInfo("2016-10-15T00:00:00Z", 60,12), + new DayInfo("2016-10-16T00:00:00Z", 70,19), + new DayInfo("2016-10-17T00:00:00Z", 170,111), + new DayInfo("2016-10-18T00:00:00Z", 180,70), + new DayInfo("2016-10-19T00:00:00Z", 190,10), + new DayInfo("2016-10-20T00:00:00Z", 200,18), + new DayInfo("2016-10-21T00:00:00Z", 210,8), + new DayInfo("2016-10-22T00:00:00Z", 220,168), + new DayInfo("2016-10-23T00:00:00Z", 5,2), + new DayInfo("2016-10-24T00:00:00Z", 45,5) ) ); testTraffic(expectedResult); @@ -152,13 +153,13 @@ public void testGetTrafficStatsAccessFailureDueToInsufficientPermissions() throw GitHub gitHub = GitHub.connect(login, null); GHRepository repo = gitHub.getUser(login).getRepository(repositoryName); try { - repo.getViews(); + repo.getViewTraffic(); Assert.fail(errorMsg); } catch (HttpException ex){ } try { - repo.getClones(); + repo.getCloneTraffic(); Assert.fail(errorMsg); } catch (HttpException ex){ From bbc2f3962f55de88413e88243d11a49c816a09b7 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 11:44:02 -0700 Subject: [PATCH 16/34] Proper access control modifier --- src/main/java/org/kohsuke/github/GHBlobBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHBlobBuilder.java b/src/main/java/org/kohsuke/github/GHBlobBuilder.java index 321e88191d..0ab62aeafb 100644 --- a/src/main/java/org/kohsuke/github/GHBlobBuilder.java +++ b/src/main/java/org/kohsuke/github/GHBlobBuilder.java @@ -12,7 +12,7 @@ public class GHBlobBuilder { private final GHRepository repo; private final Requester req; - public GHBlobBuilder(GHRepository repo) { + GHBlobBuilder(GHRepository repo) { this.repo = repo; req = new Requester(repo.root); } From 9cf6ee78d4a0fe03676f608ce5bb449f9df3f663 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 11:44:09 -0700 Subject: [PATCH 17/34] Pointless string conversion --- src/main/java/org/kohsuke/github/GHBlobBuilder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHBlobBuilder.java b/src/main/java/org/kohsuke/github/GHBlobBuilder.java index 0ab62aeafb..a6259e5b6d 100644 --- a/src/main/java/org/kohsuke/github/GHBlobBuilder.java +++ b/src/main/java/org/kohsuke/github/GHBlobBuilder.java @@ -30,7 +30,6 @@ public GHBlobBuilder textContent(String content) { * Configures a blob with the specified binary {@code content}. */ public GHBlobBuilder binaryContent(byte[] content) { - new String(content); String base64Content = Base64.encodeBase64String(content); req.with("content", base64Content); req.with("encoding", "base64"); From f3a3b8786122d3f78df61a64db36a0d2288817df Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 11:48:25 -0700 Subject: [PATCH 18/34] Defined entry points --- .../java/org/kohsuke/github/GHCommitBuilder.java | 2 +- src/main/java/org/kohsuke/github/GHRepository.java | 12 ++++++++++++ src/main/java/org/kohsuke/github/GHTreeBuilder.java | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHCommitBuilder.java b/src/main/java/org/kohsuke/github/GHCommitBuilder.java index 5f5b268a63..76e846a7d7 100644 --- a/src/main/java/org/kohsuke/github/GHCommitBuilder.java +++ b/src/main/java/org/kohsuke/github/GHCommitBuilder.java @@ -33,7 +33,7 @@ private UserInfo(String name, String email, Date date) { } } - public GHCommitBuilder(GHRepository repo) { + GHCommitBuilder(GHRepository repo) { this.repo = repo; req = new Requester(repo.root); } diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 74fbb4d665..2e15f089f7 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -824,6 +824,10 @@ public GHTree getTree(String sha) throws IOException { return root.retrieve().to(url, GHTree.class).wrap(this); } + public GHTreeBuilder createTree() { + return new GHTreeBuilder(this); + } + /** * Retrieves the tree for the current GitHub repository, recursively as described in here: * https://developer.github.com/v3/git/trees/#get-a-tree-recursively @@ -853,6 +857,10 @@ public GHBlob getBlob(String blobSha) throws IOException { return root.retrieve().to(target, GHBlob.class); } + public GHBlobBuilder createBlob() { + return new GHBlobBuilder(this); + } + /** * Reads the content of a blob as a stream for better efficiency. * @@ -876,6 +884,10 @@ public GHCommit getCommit(String sha1) throws IOException { return c; } + public GHCommitBuilder createCommit() { + return new GHCommitBuilder(this); + } + /** * Lists all the commits. */ diff --git a/src/main/java/org/kohsuke/github/GHTreeBuilder.java b/src/main/java/org/kohsuke/github/GHTreeBuilder.java index 05c04ef9c1..46fe43b4ad 100644 --- a/src/main/java/org/kohsuke/github/GHTreeBuilder.java +++ b/src/main/java/org/kohsuke/github/GHTreeBuilder.java @@ -27,7 +27,7 @@ private TreeEntry(String path, String mode, String type) { } } - public GHTreeBuilder(GHRepository repo) { + GHTreeBuilder(GHRepository repo) { this.repo = repo; req = new Requester(repo.root); } From 8928a8a1dcedd33ef5cec103ca8c4ab5cb6074a7 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 11:51:55 -0700 Subject: [PATCH 19/34] Content type should be JSON by default when sending JSON. This solves #350 a little differently. --- src/main/java/org/kohsuke/github/Requester.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index 576d313f5d..beeef0d2e2 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -60,6 +60,7 @@ import static java.util.Arrays.asList; import java.util.logging.Level; import static java.util.logging.Level.*; +import static org.apache.commons.lang.StringUtils.defaultString; import static org.kohsuke.github.GitHub.MAPPER; /** @@ -76,7 +77,7 @@ class Requester { * Request method. */ private String method = "POST"; - private String contentType = "application/x-www-form-urlencoded"; + private String contentType = null; private InputStream body; /** @@ -392,18 +393,19 @@ public String getResponseHeader(String header) { private void buildRequest() throws IOException { if (isMethodWithBody()) { uc.setDoOutput(true); - uc.setRequestProperty("Content-type", contentType); if (body == null) { + uc.setRequestProperty("Content-type", defaultString(contentType,"application/json")); Map json = new HashMap(); for (Entry e : args) { json.put(e.key, e.value); } MAPPER.writeValue(uc.getOutputStream(), json); } else { + uc.setRequestProperty("Content-type", defaultString(contentType,"application/x-www-form-urlencoded")); try { byte[] bytes = new byte[32768]; - int read = 0; + int read; while ((read = body.read(bytes)) != -1) { uc.getOutputStream().write(bytes, 0, read); } From 17edd33703a323ebec53dfc912eb3028826105c7 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:00:23 -0700 Subject: [PATCH 20/34] Reorganized imports following #337 --- .../org/kohsuke/github/GHAuthorization.java | 1 + .../java/org/kohsuke/github/GHBranch.java | 7 +++---- .../kohsuke/github/GHBranchProtection.java | 5 ++--- .../github/GHBranchProtectionBuilder.java | 4 ++-- .../java/org/kohsuke/github/GHCommit.java | 1 + .../org/kohsuke/github/GHCommitComment.java | 4 +++- .../kohsuke/github/GHCommitSearchBuilder.java | 4 ++-- .../java/org/kohsuke/github/GHDeployKey.java | 4 ++-- .../java/org/kohsuke/github/GHEventInfo.java | 6 +++--- .../org/kohsuke/github/GHEventPayload.java | 1 + src/main/java/org/kohsuke/github/GHHook.java | 1 + .../org/kohsuke/github/GHIssueComment.java | 2 +- .../java/org/kohsuke/github/GHLicense.java | 2 +- .../java/org/kohsuke/github/GHObject.java | 1 + .../org/kohsuke/github/GHPullRequest.java | 4 ++-- .../kohsuke/github/GHPullRequestReview.java | 2 +- .../java/org/kohsuke/github/GHRateLimit.java | 1 + .../java/org/kohsuke/github/GHReaction.java | 2 +- src/main/java/org/kohsuke/github/GHRef.java | 1 + .../java/org/kohsuke/github/GHRelease.java | 2 +- .../java/org/kohsuke/github/GHThread.java | 1 + .../org/kohsuke/github/GHTreeBuilder.java | 3 ++- src/main/java/org/kohsuke/github/GitHub.java | 20 +++++++++---------- src/main/java/org/kohsuke/github/GitUser.java | 1 + .../org/kohsuke/github/HttpException.java | 3 +-- .../java/org/kohsuke/github/Requester.java | 15 +++++++------- 26 files changed, 54 insertions(+), 44 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHAuthorization.java b/src/main/java/org/kohsuke/github/GHAuthorization.java index e196047776..bf7e24c7f2 100644 --- a/src/main/java/org/kohsuke/github/GHAuthorization.java +++ b/src/main/java/org/kohsuke/github/GHAuthorization.java @@ -1,6 +1,7 @@ package org.kohsuke.github; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import java.net.URL; import java.util.Collection; import java.util.List; diff --git a/src/main/java/org/kohsuke/github/GHBranch.java b/src/main/java/org/kohsuke/github/GHBranch.java index c2e5b29441..1ce9c29ac4 100644 --- a/src/main/java/org/kohsuke/github/GHBranch.java +++ b/src/main/java/org/kohsuke/github/GHBranch.java @@ -1,14 +1,13 @@ package org.kohsuke.github; -import static org.kohsuke.github.Previews.LOKI; +import com.fasterxml.jackson.annotation.JsonProperty; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.net.URL; import java.util.Collection; -import com.fasterxml.jackson.annotation.JsonProperty; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import static org.kohsuke.github.Previews.*; /** * A branch in a repository. diff --git a/src/main/java/org/kohsuke/github/GHBranchProtection.java b/src/main/java/org/kohsuke/github/GHBranchProtection.java index 3216366115..7e43bd69cb 100644 --- a/src/main/java/org/kohsuke/github/GHBranchProtection.java +++ b/src/main/java/org/kohsuke/github/GHBranchProtection.java @@ -1,11 +1,10 @@ package org.kohsuke.github; -import java.util.Collection; - import com.fasterxml.jackson.annotation.JsonProperty; - import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.util.Collection; + @SuppressFBWarnings(value = { "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD" }, justification = "JSON API") public class GHBranchProtection { diff --git a/src/main/java/org/kohsuke/github/GHBranchProtectionBuilder.java b/src/main/java/org/kohsuke/github/GHBranchProtectionBuilder.java index 5fccf7eb8c..dc7dbd8845 100644 --- a/src/main/java/org/kohsuke/github/GHBranchProtectionBuilder.java +++ b/src/main/java/org/kohsuke/github/GHBranchProtectionBuilder.java @@ -1,6 +1,6 @@ package org.kohsuke.github; -import static org.kohsuke.github.Previews.LOKI; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.util.ArrayList; @@ -12,7 +12,7 @@ import java.util.Map; import java.util.Set; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import static org.kohsuke.github.Previews.*; /** * Builder to configure the branch protection settings. diff --git a/src/main/java/org/kohsuke/github/GHCommit.java b/src/main/java/org/kohsuke/github/GHCommit.java index ec5dfbffc1..a817da2fd6 100644 --- a/src/main/java/org/kohsuke/github/GHCommit.java +++ b/src/main/java/org/kohsuke/github/GHCommit.java @@ -2,6 +2,7 @@ import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import java.io.IOException; import java.net.URL; import java.util.AbstractList; diff --git a/src/main/java/org/kohsuke/github/GHCommitComment.java b/src/main/java/org/kohsuke/github/GHCommitComment.java index 646badf5c3..f5ee76e478 100644 --- a/src/main/java/org/kohsuke/github/GHCommitComment.java +++ b/src/main/java/org/kohsuke/github/GHCommitComment.java @@ -1,9 +1,11 @@ package org.kohsuke.github; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import java.io.IOException; import java.net.URL; -import static org.kohsuke.github.Previews.SQUIRREL_GIRL; + +import static org.kohsuke.github.Previews.*; /** * A comment attached to a commit (or a specific line in a specific file of a commit.) diff --git a/src/main/java/org/kohsuke/github/GHCommitSearchBuilder.java b/src/main/java/org/kohsuke/github/GHCommitSearchBuilder.java index 65136dc0a4..23960528f2 100644 --- a/src/main/java/org/kohsuke/github/GHCommitSearchBuilder.java +++ b/src/main/java/org/kohsuke/github/GHCommitSearchBuilder.java @@ -1,9 +1,9 @@ package org.kohsuke.github; -import java.io.IOException; - import org.apache.commons.lang.StringUtils; +import java.io.IOException; + /** * Search commits. * diff --git a/src/main/java/org/kohsuke/github/GHDeployKey.java b/src/main/java/org/kohsuke/github/GHDeployKey.java index eb2c2c00fb..bfa03b2508 100644 --- a/src/main/java/org/kohsuke/github/GHDeployKey.java +++ b/src/main/java/org/kohsuke/github/GHDeployKey.java @@ -1,9 +1,9 @@ package org.kohsuke.github; -import java.io.IOException; - import org.apache.commons.lang.builder.ToStringBuilder; +import java.io.IOException; + public class GHDeployKey { protected String url, key, title; diff --git a/src/main/java/org/kohsuke/github/GHEventInfo.java b/src/main/java/org/kohsuke/github/GHEventInfo.java index 0268924ea2..e875f2df59 100644 --- a/src/main/java/org/kohsuke/github/GHEventInfo.java +++ b/src/main/java/org/kohsuke/github/GHEventInfo.java @@ -1,11 +1,11 @@ package org.kohsuke.github; -import java.io.IOException; -import java.util.Date; - import com.fasterxml.jackson.databind.node.ObjectNode; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.io.IOException; +import java.util.Date; + /** * Represents an event. * diff --git a/src/main/java/org/kohsuke/github/GHEventPayload.java b/src/main/java/org/kohsuke/github/GHEventPayload.java index 29f69bb3eb..8f5799430f 100644 --- a/src/main/java/org/kohsuke/github/GHEventPayload.java +++ b/src/main/java/org/kohsuke/github/GHEventPayload.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSetter; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import java.io.Reader; import java.util.List; diff --git a/src/main/java/org/kohsuke/github/GHHook.java b/src/main/java/org/kohsuke/github/GHHook.java index 4aa32e1946..b7f450307a 100644 --- a/src/main/java/org/kohsuke/github/GHHook.java +++ b/src/main/java/org/kohsuke/github/GHHook.java @@ -1,6 +1,7 @@ package org.kohsuke.github; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import java.io.IOException; import java.net.URL; import java.util.Collections; diff --git a/src/main/java/org/kohsuke/github/GHIssueComment.java b/src/main/java/org/kohsuke/github/GHIssueComment.java index a98f6f6398..3f4d70643d 100644 --- a/src/main/java/org/kohsuke/github/GHIssueComment.java +++ b/src/main/java/org/kohsuke/github/GHIssueComment.java @@ -26,7 +26,7 @@ import java.io.IOException; import java.net.URL; -import static org.kohsuke.github.Previews.SQUIRREL_GIRL; +import static org.kohsuke.github.Previews.*; /** * Comment to the issue diff --git a/src/main/java/org/kohsuke/github/GHLicense.java b/src/main/java/org/kohsuke/github/GHLicense.java index 2c5c4299c1..a7dad4b5ca 100644 --- a/src/main/java/org/kohsuke/github/GHLicense.java +++ b/src/main/java/org/kohsuke/github/GHLicense.java @@ -32,7 +32,7 @@ import java.util.ArrayList; import java.util.List; -import static org.kohsuke.github.Previews.DRAX; +import static org.kohsuke.github.Previews.*; /** * The GitHub Preview API's license information diff --git a/src/main/java/org/kohsuke/github/GHObject.java b/src/main/java/org/kohsuke/github/GHObject.java index d368af0aec..e091981909 100644 --- a/src/main/java/org/kohsuke/github/GHObject.java +++ b/src/main/java/org/kohsuke/github/GHObject.java @@ -4,6 +4,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; + import java.io.IOException; import java.lang.reflect.Field; import java.net.URL; diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 078603d6fa..677d6bede6 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.CheckForNull; import java.io.IOException; import java.net.URL; import java.util.ArrayList; @@ -30,9 +31,8 @@ import java.util.Collection; import java.util.Date; import java.util.List; -import javax.annotation.CheckForNull; -import static org.kohsuke.github.Previews.BLACK_CAT; +import static org.kohsuke.github.Previews.*; /** * A pull request. diff --git a/src/main/java/org/kohsuke/github/GHPullRequestReview.java b/src/main/java/org/kohsuke/github/GHPullRequestReview.java index b25f28b59a..d7afe59aad 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestReview.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestReview.java @@ -26,7 +26,7 @@ import java.io.IOException; import java.net.URL; -import static org.kohsuke.github.Previews.BLACK_CAT; +import static org.kohsuke.github.Previews.*; /** * Review to the pull request diff --git a/src/main/java/org/kohsuke/github/GHRateLimit.java b/src/main/java/org/kohsuke/github/GHRateLimit.java index b9b900d785..9500b0a736 100644 --- a/src/main/java/org/kohsuke/github/GHRateLimit.java +++ b/src/main/java/org/kohsuke/github/GHRateLimit.java @@ -1,6 +1,7 @@ package org.kohsuke.github; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import java.util.Date; /** diff --git a/src/main/java/org/kohsuke/github/GHReaction.java b/src/main/java/org/kohsuke/github/GHReaction.java index 55b26365e0..6a00eb305c 100644 --- a/src/main/java/org/kohsuke/github/GHReaction.java +++ b/src/main/java/org/kohsuke/github/GHReaction.java @@ -3,7 +3,7 @@ import java.io.IOException; import java.net.URL; -import static org.kohsuke.github.Previews.SQUIRREL_GIRL; +import static org.kohsuke.github.Previews.*; /** * Reaction to issue, comment, PR, and so on. diff --git a/src/main/java/org/kohsuke/github/GHRef.java b/src/main/java/org/kohsuke/github/GHRef.java index 8212dc2c3b..c8462d3fe6 100644 --- a/src/main/java/org/kohsuke/github/GHRef.java +++ b/src/main/java/org/kohsuke/github/GHRef.java @@ -1,6 +1,7 @@ package org.kohsuke.github; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import java.io.IOException; import java.net.URL; diff --git a/src/main/java/org/kohsuke/github/GHRelease.java b/src/main/java/org/kohsuke/github/GHRelease.java index 96421da415..524bce70b4 100644 --- a/src/main/java/org/kohsuke/github/GHRelease.java +++ b/src/main/java/org/kohsuke/github/GHRelease.java @@ -8,7 +8,7 @@ import java.util.Date; import java.util.List; -import static java.lang.String.format; +import static java.lang.String.*; /** * Release in a github repository. diff --git a/src/main/java/org/kohsuke/github/GHThread.java b/src/main/java/org/kohsuke/github/GHThread.java index a1964b10de..faf4c87b7b 100644 --- a/src/main/java/org/kohsuke/github/GHThread.java +++ b/src/main/java/org/kohsuke/github/GHThread.java @@ -1,6 +1,7 @@ package org.kohsuke.github; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; diff --git a/src/main/java/org/kohsuke/github/GHTreeBuilder.java b/src/main/java/org/kohsuke/github/GHTreeBuilder.java index 46fe43b4ad..cffbc8eafd 100644 --- a/src/main/java/org/kohsuke/github/GHTreeBuilder.java +++ b/src/main/java/org/kohsuke/github/GHTreeBuilder.java @@ -1,7 +1,8 @@ package org.kohsuke.github; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.List; /** * Builder pattern for creating a new tree. diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 49c860e4dc..f9f9f6decf 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -27,6 +27,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import org.apache.commons.codec.Charsets; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.IOUtils; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -48,17 +54,11 @@ import java.util.Set; import java.util.TimeZone; import java.util.logging.Logger; -import javax.annotation.CheckForNull; -import javax.annotation.Nonnull; -import org.apache.commons.codec.Charsets; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.io.IOUtils; -import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY; -import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE; -import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; -import static java.util.logging.Level.FINE; -import static org.kohsuke.github.Previews.DRAX; +import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.*; +import static java.net.HttpURLConnection.*; +import static java.util.logging.Level.*; +import static org.kohsuke.github.Previews.*; /** * Root of the GitHub API. diff --git a/src/main/java/org/kohsuke/github/GitUser.java b/src/main/java/org/kohsuke/github/GitUser.java index 751aabd378..9cd50bb22a 100644 --- a/src/main/java/org/kohsuke/github/GitUser.java +++ b/src/main/java/org/kohsuke/github/GitUser.java @@ -1,6 +1,7 @@ package org.kohsuke.github; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import java.util.Date; /** diff --git a/src/main/java/org/kohsuke/github/HttpException.java b/src/main/java/org/kohsuke/github/HttpException.java index 16c8e68be2..79def83c2a 100644 --- a/src/main/java/org/kohsuke/github/HttpException.java +++ b/src/main/java/org/kohsuke/github/HttpException.java @@ -1,11 +1,10 @@ package org.kohsuke.github; +import javax.annotation.CheckForNull; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; -import javax.annotation.CheckForNull; - /** * {@link IOException} for http exceptions because {@link HttpURLConnection} throws un-discerned * {@link IOException} and it can help to know the http response code to decide how to handle an diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index beeef0d2e2..3e28c342f7 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -25,6 +25,10 @@ import com.fasterxml.jackson.databind.JsonMappingException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; + +import javax.annotation.WillClose; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -49,19 +53,16 @@ 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 javax.annotation.WillClose; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; -import static java.util.Arrays.asList; -import java.util.logging.Level; +import static java.util.Arrays.*; import static java.util.logging.Level.*; -import static org.apache.commons.lang.StringUtils.defaultString; -import static org.kohsuke.github.GitHub.MAPPER; +import static org.apache.commons.lang.StringUtils.*; +import static org.kohsuke.github.GitHub.*; /** * A builder pattern for making HTTP call and parsing its output. From 635350c40e346611506839bb4007be15e3ceeda8 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:02:44 -0700 Subject: [PATCH 21/34] Additional naming consistency change --- .../github/GHRepositoryCloneTraffic.java | 21 ++--- ...fficInfo.java => GHRepositoryTraffic.java} | 24 ++---- .../github/GHRepositoryViewTraffic.java | 21 ++--- .../kohsuke/github/RepositoryTrafficTest.java | 84 +++++++++---------- 4 files changed, 66 insertions(+), 84 deletions(-) rename src/main/java/org/kohsuke/github/{GHRepositoryTrafficInfo.java => GHRepositoryTraffic.java} (50%) diff --git a/src/main/java/org/kohsuke/github/GHRepositoryCloneTraffic.java b/src/main/java/org/kohsuke/github/GHRepositoryCloneTraffic.java index 497392deb2..c75198e4a8 100644 --- a/src/main/java/org/kohsuke/github/GHRepositoryCloneTraffic.java +++ b/src/main/java/org/kohsuke/github/GHRepositoryCloneTraffic.java @@ -1,6 +1,5 @@ package org.kohsuke.github; -import java.util.Date; import java.util.List; /** @@ -8,34 +7,30 @@ * * @see GHRepository#getCloneTraffic() */ -public class GHRepositoryCloneTraffic extends GHRepositoryTrafficInfo { - private List clones; +public class GHRepositoryCloneTraffic extends GHRepositoryTraffic { + private List clones; /*package*/ GHRepositoryCloneTraffic() { } - /*package*/ GHRepositoryCloneTraffic(Integer count, Integer uniques, List clones) { + /*package*/ GHRepositoryCloneTraffic(Integer count, Integer uniques, List clones) { super(count, uniques); this.clones = clones; } - public List getClones() { + public List getClones() { return clones; } - public List getDailyInfo() { + public List getDailyInfo() { return getClones(); } - public static class DayInfo extends GHRepositoryTrafficInfo.DayInfo { - /*package*/ DayInfo() { + public static class DailyInfo extends GHRepositoryTraffic.DailyInfo { + /*package*/ DailyInfo() { } - /*package*/ DayInfo(String timestamp, int count, int uniques) { - super(timestamp, count, uniques); - } - - /*package*/ DayInfo(Date timestamp, int count, int uniques) { + /*package*/ DailyInfo(String timestamp, int count, int uniques) { super(timestamp, count, uniques); } } diff --git a/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java b/src/main/java/org/kohsuke/github/GHRepositoryTraffic.java similarity index 50% rename from src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java rename to src/main/java/org/kohsuke/github/GHRepositoryTraffic.java index 7336c93285..42d07e848d 100644 --- a/src/main/java/org/kohsuke/github/GHRepositoryTrafficInfo.java +++ b/src/main/java/org/kohsuke/github/GHRepositoryTraffic.java @@ -3,14 +3,14 @@ import java.util.Date; import java.util.List; -public abstract class GHRepositoryTrafficInfo implements TrafficInfo { +public abstract class GHRepositoryTraffic implements TrafficInfo { private int count; private int uniques; - /*package*/ GHRepositoryTrafficInfo() { + /*package*/ GHRepositoryTraffic() { } - /*package*/ GHRepositoryTrafficInfo(int count, int uniques) { + /*package*/ GHRepositoryTraffic(int count, int uniques) { this.count = count; this.uniques = uniques; } @@ -23,15 +23,15 @@ public int getUniques() { return uniques; } - public abstract List getDailyInfo(); + public abstract List getDailyInfo(); - public static abstract class DayInfo implements TrafficInfo { - private Date timestamp; + public static abstract class DailyInfo implements TrafficInfo { + private String timestamp; private int count; private int uniques; public Date getTimestamp() { - return timestamp; + return GitHub.parseDate(timestamp); } public int getCount() { @@ -42,16 +42,10 @@ public int getUniques() { return uniques; } - /*package*/ DayInfo() { + /*package*/ DailyInfo() { } - /*package*/ DayInfo(String timestamp, Integer count, Integer uniques) { - this.timestamp = GitHub.parseDate(timestamp); - this.count = count; - this.uniques = uniques; - } - - /*package*/ DayInfo(Date timestamp, Integer count, Integer uniques) { + /*package*/ DailyInfo(String timestamp, Integer count, Integer uniques) { this.timestamp = timestamp; this.count = count; this.uniques = uniques; diff --git a/src/main/java/org/kohsuke/github/GHRepositoryViewTraffic.java b/src/main/java/org/kohsuke/github/GHRepositoryViewTraffic.java index 42c716cc6e..f2f1e5b440 100644 --- a/src/main/java/org/kohsuke/github/GHRepositoryViewTraffic.java +++ b/src/main/java/org/kohsuke/github/GHRepositoryViewTraffic.java @@ -1,6 +1,5 @@ package org.kohsuke.github; -import java.util.Date; import java.util.List; /** @@ -8,34 +7,30 @@ * * @see GHRepository#getViewTraffic() */ -public class GHRepositoryViewTraffic extends GHRepositoryTrafficInfo { - private List views; +public class GHRepositoryViewTraffic extends GHRepositoryTraffic { + private List views; /*package*/ GHRepositoryViewTraffic() { } - /*package*/ GHRepositoryViewTraffic(int count, int uniques, List views) { + /*package*/ GHRepositoryViewTraffic(int count, int uniques, List views) { super(count, uniques); this.views = views; } - public List getViews() { + public List getViews() { return views; } - public List getDailyInfo() { + public List getDailyInfo() { return getViews(); } - public static class Daily extends GHRepositoryTrafficInfo.DayInfo { - /*package*/ Daily() { + public static class DailyInfo extends GHRepositoryTraffic.DailyInfo { + /*package*/ DailyInfo() { } - /*package*/ Daily(String timestamp, int count, int uniques) { - super(timestamp, count, uniques); - } - - /*package*/ Daily(Date timestamp, int count, int uniques) { + /*package*/ DailyInfo(String timestamp, int count, int uniques) { super(timestamp, count, uniques); } } diff --git a/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java b/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java index 64864acfa2..3cc985b2c1 100644 --- a/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java +++ b/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java @@ -4,8 +4,6 @@ import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.Test; -import org.kohsuke.github.GHRepositoryCloneTraffic.DayInfo; -import org.kohsuke.github.GHRepositoryViewTraffic.Daily; import org.mockito.Mockito; import java.io.IOException; @@ -22,29 +20,29 @@ public class RepositoryTrafficTest { final private String login = "kohsuke", repositoryName = "github-api"; @SuppressWarnings("unchecked") - private void checkResponse(T expected, T actual){ + private void checkResponse(T expected, T actual){ Assert.assertEquals(expected.getCount(), actual.getCount()); Assert.assertEquals(expected.getUniques(), actual.getUniques()); - List expectedList = expected.getDailyInfo(); - List actualList = actual.getDailyInfo(); - Iterator expectedIt; - Iterator actualIt; + List expectedList = expected.getDailyInfo(); + List actualList = actual.getDailyInfo(); + Iterator expectedIt; + Iterator actualIt; Assert.assertEquals(expectedList.size(), actualList.size()); expectedIt = expectedList.iterator(); actualIt = actualList.iterator(); while(expectedIt.hasNext() && actualIt.hasNext()) { - GHRepositoryTrafficInfo.DayInfo expectedDayInfo = expectedIt.next(); - GHRepositoryTrafficInfo.DayInfo actualDayInfo = actualIt.next(); - Assert.assertEquals(expectedDayInfo.getCount(), actualDayInfo.getCount()); - Assert.assertEquals(expectedDayInfo.getUniques(), actualDayInfo.getUniques()); - Assert.assertEquals(expectedDayInfo.getTimestamp(), actualDayInfo.getTimestamp()); + DailyInfo expectedDailyInfo = expectedIt.next(); + DailyInfo actualDailyInfo = actualIt.next(); + Assert.assertEquals(expectedDailyInfo.getCount(), actualDailyInfo.getCount()); + Assert.assertEquals(expectedDailyInfo.getUniques(), actualDailyInfo.getUniques()); + Assert.assertEquals(expectedDailyInfo.getTimestamp(), actualDailyInfo.getTimestamp()); } } - private void testTraffic(T expectedResult) throws IOException{ + private void testTraffic(T expectedResult) throws IOException{ SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); ObjectMapper mapper = new ObjectMapper().setDateFormat(dateFormat); @@ -101,21 +99,21 @@ public void testGetViews() throws IOException{ 21523359, 65534, Arrays.asList( - new Daily("2016-10-10T00:00:00Z", 3, 2), - new Daily("2016-10-11T00:00:00Z", 9, 4), - new Daily("2016-10-12T00:00:00Z", 27, 8), - new Daily("2016-10-13T00:00:00Z", 81, 16), - new Daily("2016-10-14T00:00:00Z", 243, 32), - new Daily("2016-10-15T00:00:00Z", 729, 64), - new Daily("2016-10-16T00:00:00Z", 2187, 128), - new Daily("2016-10-17T00:00:00Z", 6561, 256), - new Daily("2016-10-18T00:00:00Z", 19683, 512), - new Daily("2016-10-19T00:00:00Z", 59049, 1024), - new Daily("2016-10-20T00:00:00Z", 177147, 2048), - new Daily("2016-10-21T00:00:00Z", 531441, 4096), - new Daily("2016-10-22T00:00:00Z", 1594323, 8192), - new Daily("2016-10-23T00:00:00Z", 4782969, 16384), - new Daily("2016-10-24T00:00:00Z", 14348907, 32768) + new GHRepositoryViewTraffic.DailyInfo("2016-10-10T00:00:00Z", 3, 2), + new GHRepositoryViewTraffic.DailyInfo("2016-10-11T00:00:00Z", 9, 4), + new GHRepositoryViewTraffic.DailyInfo("2016-10-12T00:00:00Z", 27, 8), + new GHRepositoryViewTraffic.DailyInfo("2016-10-13T00:00:00Z", 81, 16), + new GHRepositoryViewTraffic.DailyInfo("2016-10-14T00:00:00Z", 243, 32), + new GHRepositoryViewTraffic.DailyInfo("2016-10-15T00:00:00Z", 729, 64), + new GHRepositoryViewTraffic.DailyInfo("2016-10-16T00:00:00Z", 2187, 128), + new GHRepositoryViewTraffic.DailyInfo("2016-10-17T00:00:00Z", 6561, 256), + new GHRepositoryViewTraffic.DailyInfo("2016-10-18T00:00:00Z", 19683, 512), + new GHRepositoryViewTraffic.DailyInfo("2016-10-19T00:00:00Z", 59049, 1024), + new GHRepositoryViewTraffic.DailyInfo("2016-10-20T00:00:00Z", 177147, 2048), + new GHRepositoryViewTraffic.DailyInfo("2016-10-21T00:00:00Z", 531441, 4096), + new GHRepositoryViewTraffic.DailyInfo("2016-10-22T00:00:00Z", 1594323, 8192), + new GHRepositoryViewTraffic.DailyInfo("2016-10-23T00:00:00Z", 4782969, 16384), + new GHRepositoryViewTraffic.DailyInfo("2016-10-24T00:00:00Z", 14348907, 32768) ) ); testTraffic(expectedResult); @@ -127,21 +125,21 @@ public void testGetClones() throws IOException{ 1500, 455, Arrays.asList( - new DayInfo("2016-10-10T00:00:00Z", 10,3), - new DayInfo("2016-10-11T00:00:00Z", 20,6), - new DayInfo("2016-10-12T00:00:00Z", 30,5), - new DayInfo("2016-10-13T00:00:00Z", 40,7), - new DayInfo("2016-10-14T00:00:00Z", 50,11), - new DayInfo("2016-10-15T00:00:00Z", 60,12), - new DayInfo("2016-10-16T00:00:00Z", 70,19), - new DayInfo("2016-10-17T00:00:00Z", 170,111), - new DayInfo("2016-10-18T00:00:00Z", 180,70), - new DayInfo("2016-10-19T00:00:00Z", 190,10), - new DayInfo("2016-10-20T00:00:00Z", 200,18), - new DayInfo("2016-10-21T00:00:00Z", 210,8), - new DayInfo("2016-10-22T00:00:00Z", 220,168), - new DayInfo("2016-10-23T00:00:00Z", 5,2), - new DayInfo("2016-10-24T00:00:00Z", 45,5) + new GHRepositoryCloneTraffic.DailyInfo("2016-10-10T00:00:00Z", 10,3), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-11T00:00:00Z", 20,6), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-12T00:00:00Z", 30,5), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-13T00:00:00Z", 40,7), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-14T00:00:00Z", 50,11), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-15T00:00:00Z", 60,12), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-16T00:00:00Z", 70,19), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-17T00:00:00Z", 170,111), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-18T00:00:00Z", 180,70), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-19T00:00:00Z", 190,10), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-20T00:00:00Z", 200,18), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-21T00:00:00Z", 210,8), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-22T00:00:00Z", 220,168), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-23T00:00:00Z", 5,2), + new GHRepositoryCloneTraffic.DailyInfo("2016-10-24T00:00:00Z", 45,5) ) ); testTraffic(expectedResult); From e6ad9feb84e89f4722ffbb25b3548d6ae213a6a1 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:05:39 -0700 Subject: [PATCH 22/34] Keeping Findbugs happy --- src/main/java/org/kohsuke/github/GHTreeBuilder.java | 3 +++ src/test/java/org/kohsuke/github/RepositoryTrafficTest.java | 1 + 2 files changed, 4 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GHTreeBuilder.java b/src/main/java/org/kohsuke/github/GHTreeBuilder.java index cffbc8eafd..122c5775b5 100644 --- a/src/main/java/org/kohsuke/github/GHTreeBuilder.java +++ b/src/main/java/org/kohsuke/github/GHTreeBuilder.java @@ -1,5 +1,7 @@ package org.kohsuke.github; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -14,6 +16,7 @@ public class GHTreeBuilder { private final List treeEntries = new ArrayList(); + @SuppressFBWarnings("URF_UNREAD_FIELD") private static final class TreeEntry { private final String path; private final String mode; diff --git a/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java b/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java index 3cc985b2c1..b1f13e6c97 100644 --- a/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java +++ b/src/test/java/org/kohsuke/github/RepositoryTrafficTest.java @@ -4,6 +4,7 @@ import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.Test; +import org.kohsuke.github.GHRepositoryTraffic.DailyInfo; import org.mockito.Mockito; import java.io.IOException; From f721e053f111f112fdf4de95afb250026d838edf Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:11:36 -0700 Subject: [PATCH 23/34] Added convenience connector for OkHttp3 Note that the existing one needs to be kept for compatibility with OkHttp2 --- pom.xml | 6 ++++ .../github/extras/OkHttp3Connector.java | 32 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/main/java/org/kohsuke/github/extras/OkHttp3Connector.java diff --git a/pom.xml b/pom.xml index 9b11b977f3..2258760f43 100644 --- a/pom.xml +++ b/pom.xml @@ -144,6 +144,12 @@ 2.7.5 true + + com.squareup.okhttp3 + okhttp-urlconnection + 3.4.0 + true + org.kohsuke wordnet-random-name diff --git a/src/main/java/org/kohsuke/github/extras/OkHttp3Connector.java b/src/main/java/org/kohsuke/github/extras/OkHttp3Connector.java new file mode 100644 index 0000000000..d2fd8c6978 --- /dev/null +++ b/src/main/java/org/kohsuke/github/extras/OkHttp3Connector.java @@ -0,0 +1,32 @@ +package org.kohsuke.github.extras; + +import okhttp3.OkHttpClient; +import okhttp3.OkUrlFactory; +import org.kohsuke.github.HttpConnector; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * {@link HttpConnector} for {@link OkHttpClient}. + * + * Unlike {@link #DEFAULT}, OkHttp does response caching. + * Making a conditional request against GitHubAPI and receiving a 304 + * response does not count against the rate limit. + * See http://developer.github.com/v3/#conditional-requests + * + * @author Roberto Tyley + * @author Kohsuke Kawaguchi + */ +public class OkHttp3Connector implements HttpConnector { + private final OkUrlFactory urlFactory; + + public OkHttp3Connector(OkUrlFactory urlFactory) { + this.urlFactory = urlFactory; + } + + public HttpURLConnection connect(URL url) throws IOException { + return urlFactory.open(url); + } +} From fe2af19e42c818560e49d8c74282fc8d5f62e076 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:15:21 -0700 Subject: [PATCH 24/34] Unused constant --- src/main/java/org/kohsuke/github/Previews.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/Previews.java b/src/main/java/org/kohsuke/github/Previews.java index 3b7eeb5939..238b062b8b 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 KORRA = "application/vnd.github.korra-preview"; - static final String POLARIS = "application/vnd.github.polaris-preview"; } From 9012820c0343240ac53fd2fbb5f1f8306d761be8 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:17:21 -0700 Subject: [PATCH 25/34] Massage the signature a bit. AFAICT sha and merge_method are not mutually exclusive. --- src/main/java/org/kohsuke/github/GHPullRequest.java | 13 +++++++------ .../org/kohsuke/github/extras/OkHttpConnector.java | 1 + .../java/org/kohsuke/github/PullRequestTest.java | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHPullRequest.java b/src/main/java/org/kohsuke/github/GHPullRequest.java index 096adcf92e..4985f552cb 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequest.java +++ b/src/main/java/org/kohsuke/github/GHPullRequest.java @@ -277,7 +277,7 @@ public GHPullRequestReviewComment createReviewComment(String body, String sha, S * Commit message. If null, the default one will be used. */ public void merge(String msg) throws IOException { - merge(msg,(String)null); + merge(msg,null); } /** @@ -291,7 +291,7 @@ public void merge(String msg) throws IOException { * SHA that pull request head must match to allow merge. */ public void merge(String msg, String sha) throws IOException { - new Requester(root).method("PUT").with("commit_message",msg).with("sha",sha).to(getApiRoute()+"/merge"); + merge(msg, sha, null); } /** @@ -304,11 +304,12 @@ public void merge(String msg, String sha) throws IOException { * @param method * SHA that pull request head must match to allow merge. */ - public void merge(String msg, MergeMethod method) throws IOException { + public void merge(String msg, String sha, MergeMethod method) throws IOException { new Requester(root).method("PUT") - .with("commit_message",msg) - .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/extras/OkHttpConnector.java b/src/main/java/org/kohsuke/github/extras/OkHttpConnector.java index faa06b0d3b..b7bad2e971 100644 --- a/src/main/java/org/kohsuke/github/extras/OkHttpConnector.java +++ b/src/main/java/org/kohsuke/github/extras/OkHttpConnector.java @@ -30,3 +30,4 @@ public HttpURLConnection connect(URL url) throws IOException { return urlFactory.open(url); } } +GHPul \ No newline at end of file diff --git a/src/test/java/org/kohsuke/github/PullRequestTest.java b/src/test/java/org/kohsuke/github/PullRequestTest.java index ba8f087197..f90c83353d 100644 --- a/src/test/java/org/kohsuke/github/PullRequestTest.java +++ b/src/test/java/org/kohsuke/github/PullRequestTest.java @@ -78,7 +78,7 @@ public void testSquashMerge() throws Exception { Thread.sleep(1000); GHPullRequest p = getRepository().createPullRequest(name, name, "master", "## test squash"); Thread.sleep(1000); - p.merge("squash merge", GHPullRequest.MergeMethod.SQUASH); + p.merge("squash merge", null, GHPullRequest.MergeMethod.SQUASH); branchRef.delete(); } From 353f9bb809c68b0ffd56f205ee23f80afff82e15 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:23:40 -0700 Subject: [PATCH 26/34] pointless null check since the with method already does it --- .../java/org/kohsuke/github/GHReleaseBuilder.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHReleaseBuilder.java b/src/main/java/org/kohsuke/github/GHReleaseBuilder.java index b1daac956e..e427bdf8a5 100644 --- a/src/main/java/org/kohsuke/github/GHReleaseBuilder.java +++ b/src/main/java/org/kohsuke/github/GHReleaseBuilder.java @@ -21,9 +21,7 @@ public GHReleaseBuilder(GHRepository ghRepository, String tag) { * @param body The release notes body. */ public GHReleaseBuilder body(String body) { - if (body != null) { - builder.with("body", body); - } + builder.with("body", body); return this; } @@ -35,9 +33,7 @@ public GHReleaseBuilder body(String body) { * already exists. */ public GHReleaseBuilder commitish(String commitish) { - if (commitish != null) { - builder.with("target_commitish", commitish); - } + builder.with("target_commitish", commitish); return this; } @@ -56,9 +52,7 @@ public GHReleaseBuilder draft(boolean draft) { * @param name the name of the release */ public GHReleaseBuilder name(String name) { - if (name != null) { - builder.with("name", name); - } + builder.with("name", name); return this; } From d8f4bc739595dcf08205648342c52d04a56903e4 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:31:10 -0700 Subject: [PATCH 27/34] Added updater This solves #331 differently --- .../java/org/kohsuke/github/GHRelease.java | 14 ++-- .../org/kohsuke/github/GHReleaseUpdater.java | 81 +++++++++++++++++++ 2 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/GHReleaseUpdater.java diff --git a/src/main/java/org/kohsuke/github/GHRelease.java b/src/main/java/org/kohsuke/github/GHRelease.java index 524bce70b4..a299add2c5 100644 --- a/src/main/java/org/kohsuke/github/GHRelease.java +++ b/src/main/java/org/kohsuke/github/GHRelease.java @@ -45,10 +45,12 @@ public boolean isDraft() { return draft; } + /** + * @deprecated + * Use {@link #update()} + */ public GHRelease setDraft(boolean draft) throws IOException { - edit("draft", draft); - this.draft = draft; - return this; + return update().draft(draft).update(); } public URL getHtmlUrl() { @@ -149,10 +151,10 @@ public void delete() throws IOException { } /** - * Edit this release. + * Updates this release via a builder. */ - private void edit(String key, Object value) throws IOException { - new Requester(root)._with(key, value).method("PATCH").to(owner.getApiTailUrl("releases/"+id)); + public GHReleaseUpdater update() { + return new GHReleaseUpdater(this); } private String getApiTailUrl(String end) { diff --git a/src/main/java/org/kohsuke/github/GHReleaseUpdater.java b/src/main/java/org/kohsuke/github/GHReleaseUpdater.java new file mode 100644 index 0000000000..a34a5b0bc2 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHReleaseUpdater.java @@ -0,0 +1,81 @@ +package org.kohsuke.github; + +import java.io.IOException; + +/** + * Modifies {@link GHRelease}. + * + * @author Kohsuke Kawaguchi + * @see GHRelease#update() + */ +public class GHReleaseUpdater { + private final GHRelease base; + private final Requester builder; + + GHReleaseUpdater(GHRelease base) { + this.base = base; + this.builder = new Requester(base.root); + } + + public GHReleaseUpdater tag(String tag) { + builder.with("tag_name",tag); + return this; + } + + /** + * @param body The release notes body. + */ + public GHReleaseUpdater body(String body) { + builder.with("body", body); + return this; + } + + /** + * Specifies the commitish value that determines where the Git tag is created from. Can be any branch or + * commit SHA. + * + * @param commitish Defaults to the repository’s default branch (usually "master"). Unused if the Git tag + * already exists. + */ + public GHReleaseUpdater commitish(String commitish) { + builder.with("target_commitish", commitish); + return this; + } + + /** + * Optional. + * + * @param draft {@code true} to create a draft (unpublished) release, {@code false} to create a published one. + * Default is {@code false}. + */ + public GHReleaseUpdater draft(boolean draft) { + builder.with("draft", draft); + return this; + } + + /** + * @param name the name of the release + */ + public GHReleaseUpdater name(String name) { + builder.with("name", name); + return this; + } + + /** + * Optional + * + * @param prerelease {@code true} to identify the release as a prerelease. {@code false} to identify the release + * as a full release. Default is {@code false}. + */ + public GHReleaseUpdater prerelease(boolean prerelease) { + builder.with("prerelease", prerelease); + return this; + } + + public GHRelease update() throws IOException { + return builder + .method("PATCH") + .to(base.owner.getApiTailUrl("releases/"+base.id), GHRelease.class).wrap(base.owner); + } + +} From 2d3557e049c8c365dcaf44991ba42d5a394668c4 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:44:12 -0700 Subject: [PATCH 28/34] Improved the intern logic if the user record does not exist yet, there's no need to fetch that eagerly, as they are fetched on demand via the populate() method. --- .../org/kohsuke/github/GHCommitPointer.java | 2 +- .../java/org/kohsuke/github/GHCommitStatus.java | 3 +-- .../java/org/kohsuke/github/GHDeployment.java | 3 +-- src/main/java/org/kohsuke/github/GHGist.java | 2 +- src/main/java/org/kohsuke/github/GHIssue.java | 17 ++++++++++------- .../java/org/kohsuke/github/GHMilestone.java | 2 +- src/main/java/org/kohsuke/github/GitHub.java | 17 +++++++++++++++-- 7 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHCommitPointer.java b/src/main/java/org/kohsuke/github/GHCommitPointer.java index 6b3f414f43..b6c347864e 100644 --- a/src/main/java/org/kohsuke/github/GHCommitPointer.java +++ b/src/main/java/org/kohsuke/github/GHCommitPointer.java @@ -40,7 +40,7 @@ public class GHCommitPointer { * the {@link #getRepository()}. */ public GHUser getUser() throws IOException { - if (user != null) return user.root.getUser(user.getLogin()); + if (user != null) return user.root.intern(user); return user; } diff --git a/src/main/java/org/kohsuke/github/GHCommitStatus.java b/src/main/java/org/kohsuke/github/GHCommitStatus.java index f71be99622..63a62ae8d0 100644 --- a/src/main/java/org/kohsuke/github/GHCommitStatus.java +++ b/src/main/java/org/kohsuke/github/GHCommitStatus.java @@ -47,8 +47,7 @@ public String getDescription() { } public GHUser getCreator() throws IOException { - if (creator != null) return creator.root.getUser(creator.getLogin()); - return creator; + return root.intern(creator); } public String getContext() { diff --git a/src/main/java/org/kohsuke/github/GHDeployment.java b/src/main/java/org/kohsuke/github/GHDeployment.java index ff8b4d6afc..0cef10ee52 100644 --- a/src/main/java/org/kohsuke/github/GHDeployment.java +++ b/src/main/java/org/kohsuke/github/GHDeployment.java @@ -42,8 +42,7 @@ public String getEnvironment() { return environment; } public GHUser getCreator() throws IOException { - if(creator != null) return root.getUser(creator.getLogin()); - return creator; + return root.intern(creator); } public String getRef() { return ref; diff --git a/src/main/java/org/kohsuke/github/GHGist.java b/src/main/java/org/kohsuke/github/GHGist.java index e0954175d0..a9bf3fef42 100644 --- a/src/main/java/org/kohsuke/github/GHGist.java +++ b/src/main/java/org/kohsuke/github/GHGist.java @@ -39,7 +39,7 @@ public class GHGist extends GHObject { * User that owns this Gist. */ public GHUser getOwner() throws IOException { - return root.getUser(owner.getLogin()); + return root.intern(owner); } public String getForksUrl() { diff --git a/src/main/java/org/kohsuke/github/GHIssue.java b/src/main/java/org/kohsuke/github/GHIssue.java index 9a3b31f11b..6b416ca1d3 100644 --- a/src/main/java/org/kohsuke/github/GHIssue.java +++ b/src/main/java/org/kohsuke/github/GHIssue.java @@ -289,8 +289,7 @@ protected String getIssuesApiRoute() { } public GHUser getAssignee() throws IOException { - if (assignee != null) return owner.root.getUser(assignee.getLogin()); - return assignee; + return root.intern(assignee); } public List getAssignees() { @@ -301,7 +300,7 @@ public List getAssignees() { * User who submitted the issue. */ public GHUser getUser() throws IOException { - return owner.root.getUser(user.getLogin()); + return root.intern(user); } /** @@ -314,10 +313,14 @@ public GHUser getUser() throws IOException { */ public GHUser getClosedBy() throws IOException { if(!"closed".equals(state)) return null; - if(closed_by != null) return owner.root.getUser(closed_by.getLogin());; - - //TODO closed_by = owner.getIssue(number).getClosed_by(); - return closed_by; + + //TODO + /* + if (closed_by==null) { + closed_by = owner.getIssue(number).getClosed_by(); + } + */ + return root.intern(closed_by); } public int getCommentsCount(){ diff --git a/src/main/java/org/kohsuke/github/GHMilestone.java b/src/main/java/org/kohsuke/github/GHMilestone.java index 950dea2574..50ad549e82 100644 --- a/src/main/java/org/kohsuke/github/GHMilestone.java +++ b/src/main/java/org/kohsuke/github/GHMilestone.java @@ -28,7 +28,7 @@ public GHRepository getOwner() { } public GHUser getCreator() throws IOException { - return root.getUser(creator.getLogin()); + return root.intern(creator); } public Date getDueOn() { diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index bde74b1262..201ccaff33 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -48,6 +48,7 @@ import java.util.Set; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.logging.Logger; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -80,8 +81,8 @@ public class GitHub { */ /*package*/ final String encodedAuthorization; - private final Map users; - private final Map orgs; + private final ConcurrentMap users; + private final ConcurrentMap orgs; // Cache of myself object. private GHMyself myself; private final String apiUrl; @@ -647,6 +648,18 @@ public boolean isCredentialValid() throws IOException { } } + /*package*/ GHUser intern(GHUser user) throws IOException { + if (user==null) return user; + + // if we already have this user in our map, use it + GHUser u = users.get(user.getLogin()); + if (u!=null) return u; + + // if not, remember this new user + users.putIfAbsent(user.getLogin(),user); + return user; + } + private static class GHApiInfo { private String rate_limit_url; From 40fb38a9ba98fc6de8defd8f3fbb497ea1e17753 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:45:58 -0700 Subject: [PATCH 29/34] Window focus problem --- src/main/java/org/kohsuke/github/extras/OkHttpConnector.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/extras/OkHttpConnector.java b/src/main/java/org/kohsuke/github/extras/OkHttpConnector.java index b7bad2e971..faa06b0d3b 100644 --- a/src/main/java/org/kohsuke/github/extras/OkHttpConnector.java +++ b/src/main/java/org/kohsuke/github/extras/OkHttpConnector.java @@ -30,4 +30,3 @@ public HttpURLConnection connect(URL url) throws IOException { return urlFactory.open(url); } } -GHPul \ No newline at end of file From 6178d3889546e7eb5de5f4bdb3ab17d0e6c16f5f Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:47:18 -0700 Subject: [PATCH 30/34] connector usage is unsynchronized --- src/main/java/org/kohsuke/github/GitHub.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index e248372ad1..62c1b4e80c 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -269,7 +269,7 @@ public String getApiUrl() { /** * Sets the custom connector used to make requests to GitHub. */ - public synchronized void setConnector(HttpConnector connector) { + public void setConnector(HttpConnector connector) { this.connector = connector; } From 92caf986835b711cd602792c5faa47bed99970c6 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 12:57:52 -0700 Subject: [PATCH 31/34] Reverting java1.6 change which I assume is accidental. Not that I really care about Java5 but I think that change should be done separatel & intentionally --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9f372d703d..fe8e0faff7 100644 --- a/pom.xml +++ b/pom.xml @@ -41,13 +41,13 @@ org.codehaus.mojo.signature - java16 + java15 1.0 - ensure-java-1.6-class-library + ensure-java-1.5-class-library test check From 692dccf110ceb2281c1d8ac887b6a66c70387f3a Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 13:03:18 -0700 Subject: [PATCH 32/34] Massaging the change a bit --- .../GHFileNotFoundException.java | 4 +-- .../github/{exception => }/GHIOException.java | 12 +++---- .../java/org/kohsuke/github/GHObject.java | 16 +++++++-- .../java/org/kohsuke/github/Requester.java | 34 ++++++------------- .../java/org/kohsuke/github/GHHookTest.java | 1 - 5 files changed, 33 insertions(+), 34 deletions(-) rename src/main/java/org/kohsuke/github/{exception => }/GHFileNotFoundException.java (85%) rename src/main/java/org/kohsuke/github/{exception => }/GHIOException.java (66%) diff --git a/src/main/java/org/kohsuke/github/exception/GHFileNotFoundException.java b/src/main/java/org/kohsuke/github/GHFileNotFoundException.java similarity index 85% rename from src/main/java/org/kohsuke/github/exception/GHFileNotFoundException.java rename to src/main/java/org/kohsuke/github/GHFileNotFoundException.java index 27606de595..9f4b37c560 100644 --- a/src/main/java/org/kohsuke/github/exception/GHFileNotFoundException.java +++ b/src/main/java/org/kohsuke/github/GHFileNotFoundException.java @@ -1,4 +1,4 @@ -package org.kohsuke.github.exception; +package org.kohsuke.github; import javax.annotation.CheckForNull; import java.io.FileNotFoundException; @@ -27,7 +27,7 @@ public Map> getResponseHeaderFields() { return responseHeaderFields; } - public GHFileNotFoundException withResponseHeaderFields(HttpURLConnection urlConnection) { + GHFileNotFoundException withResponseHeaderFields(HttpURLConnection urlConnection) { this.responseHeaderFields = urlConnection.getHeaderFields(); return this; } diff --git a/src/main/java/org/kohsuke/github/exception/GHIOException.java b/src/main/java/org/kohsuke/github/GHIOException.java similarity index 66% rename from src/main/java/org/kohsuke/github/exception/GHIOException.java rename to src/main/java/org/kohsuke/github/GHIOException.java index 7bb614092e..5cdc9e541a 100644 --- a/src/main/java/org/kohsuke/github/exception/GHIOException.java +++ b/src/main/java/org/kohsuke/github/GHIOException.java @@ -1,4 +1,4 @@ -package org.kohsuke.github.exception; +package org.kohsuke.github; import javax.annotation.CheckForNull; import java.io.IOException; @@ -13,7 +13,7 @@ * @author Kanstantsin Shautsou */ public class GHIOException extends IOException { - protected Map> responceHeaderFields; + protected Map> responseHeaderFields; public GHIOException() { } @@ -31,12 +31,12 @@ public GHIOException(Throwable cause) { } @CheckForNull - public Map> getResponceHeaderFields() { - return responceHeaderFields; + public Map> getResponseHeaderFields() { + return responseHeaderFields; } - public GHIOException withResponceHeaderFields(HttpURLConnection urlConnection) { - this.responceHeaderFields = urlConnection.getHeaderFields(); + GHIOException withResponseHeaderFields(HttpURLConnection urlConnection) { + this.responseHeaderFields = urlConnection.getHeaderFields(); return this; } } diff --git a/src/main/java/org/kohsuke/github/GHObject.java b/src/main/java/org/kohsuke/github/GHObject.java index 3a1cde1908..96e41a2559 100644 --- a/src/main/java/org/kohsuke/github/GHObject.java +++ b/src/main/java/org/kohsuke/github/GHObject.java @@ -19,7 +19,9 @@ @SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"}, justification = "JSON API") public abstract class GHObject { - // not data but information related to data from responce + /** + * Capture response HTTP headers on the state object. + */ protected Map> responseHeaderFields; protected String url; @@ -30,7 +32,17 @@ public abstract class GHObject { /*package*/ GHObject() { } - @CheckForNull + /** + * Returns the HTTP response headers given along with the state of this object. + * + *

+ * Some of the HTTP headers have nothing to do with the object, for example "Cache-Control" + * and others are different depending on how this object was retrieved. + * + * This method was added as a kind of hack to allow the caller to retrieve OAuth scopes and such. + * Use with caution. The method might be removed in the future. + */ + @CheckForNull @Deprecated public Map> getResponseHeaderFields() { return responseHeaderFields; } diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index 64aefe68fe..57ce89f0b1 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -26,8 +26,6 @@ import com.fasterxml.jackson.databind.JsonMappingException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.apache.commons.io.IOUtils; -import org.kohsuke.github.exception.GHFileNotFoundException; -import org.kohsuke.github.exception.GHIOException; import java.io.FileNotFoundException; import java.io.IOException; @@ -274,7 +272,7 @@ private T _to(String tailApiUrl, Class type, T instance) throws IOExcepti if (nextLinkMatcher.find()) { final String link = nextLinkMatcher.group(1); T nextResult = _to(link, type, instance); - injectInResult(nextResult); + setResponseHeaders(nextResult); final int resultLength = Array.getLength(result); final int nextResultLength = Array.getLength(nextResult); T concatResult = (T) Array.newInstance(type.getComponentType(), resultLength + nextResultLength); @@ -284,8 +282,7 @@ private T _to(String tailApiUrl, Class type, T instance) throws IOExcepti } } } - injectInResult(result); - return result; + return setResponseHeaders(result); } catch (IOException e) { handleApiError(e); } finally { @@ -605,16 +602,12 @@ private T parse(Class type, T instance) throws IOException { String data = IOUtils.toString(r); if (type!=null) try { - final T readValue = MAPPER.readValue(data, type); - injectInResult(readValue); - return readValue; + return setResponseHeaders(MAPPER.readValue(data, type)); } catch (JsonMappingException e) { throw (IOException)new IOException("Failed to deserialize " +data).initCause(e); } if (instance!=null) { - final T readValue = MAPPER.readerForUpdating(instance).readValue(data); - injectInResult(readValue); - return readValue; + return setResponseHeaders(MAPPER.readerForUpdating(instance).readValue(data)); } return null; } catch (FileNotFoundException e) { @@ -628,24 +621,19 @@ private T parse(Class type, T instance) throws IOException { } } - private void injectInResult(T readValue) { + private T setResponseHeaders(T readValue) { if (readValue instanceof GHObject[]) { for (GHObject ghObject : (GHObject[]) readValue) { - injectInResult(ghObject); + setResponseHeaders(ghObject); } } else if (readValue instanceof GHObject) { - injectInResult((GHObject) readValue); + setResponseHeaders((GHObject) readValue); } + return readValue; } - private void injectInResult(GHObject readValue) { - try { - final Field field = GHObject.class.getDeclaredField("responseHeaderFields"); - field.setAccessible(true); - field.set(readValue, uc.getHeaderFields()); - } catch (NoSuchFieldException ignore) { - } catch (IllegalAccessException ignore) { - } + private void setResponseHeaders(GHObject readValue) { + readValue.responseHeaderFields = uc.getHeaderFields(); } /** @@ -700,7 +688,7 @@ private InputStream wrapStream(InputStream in) throws IOException { HttpException http = (HttpException) e; throw (IOException) new HttpException(error, http.getResponseCode(), http.getResponseMessage(), http.getUrl(), e); } else { - throw (IOException) new GHIOException(error).withResponceHeaderFields(uc).initCause(e); + throw (IOException) new GHIOException(error).withResponseHeaderFields(uc).initCause(e); } } else { throw e; diff --git a/src/test/java/org/kohsuke/github/GHHookTest.java b/src/test/java/org/kohsuke/github/GHHookTest.java index 2cbab48cb7..b27484b5e5 100644 --- a/src/test/java/org/kohsuke/github/GHHookTest.java +++ b/src/test/java/org/kohsuke/github/GHHookTest.java @@ -3,7 +3,6 @@ import org.apache.commons.lang.StringUtils; import org.junit.Ignore; import org.junit.Test; -import org.kohsuke.github.exception.GHFileNotFoundException; import java.io.IOException; import java.util.Arrays; From 60bfea2d3b46a423aa0b3d7d43944b9acfdfef50 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 13:22:16 -0700 Subject: [PATCH 33/34] Bug fix --- src/main/java/org/kohsuke/github/GHEventPayload.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHEventPayload.java b/src/main/java/org/kohsuke/github/GHEventPayload.java index 8f5799430f..3d23973fd5 100644 --- a/src/main/java/org/kohsuke/github/GHEventPayload.java +++ b/src/main/java/org/kohsuke/github/GHEventPayload.java @@ -78,7 +78,7 @@ void wrapUp(GitHub root) { throw new IllegalStateException("Expected pull_request payload, but got something else. Maybe we've got another type of event?"); if (repository!=null) { repository.wrap(root); - pull_request.wrap(repository); + pull_request.wrapUp(repository); } else { pull_request.wrapUp(root); } From 47409a9a999eecd5507837b602a6e1f342894568 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 9 Sep 2017 13:28:31 -0700 Subject: [PATCH 34/34] [maven-release-plugin] prepare release github-api-1.89 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a1074f7024..fffadeffd9 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.89-SNAPSHOT + 1.89 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.89