From 8f24f55eb750df48f2588aec0a6164771d0e417c Mon Sep 17 00:00:00 2001 From: vr100 Date: Wed, 19 Mar 2014 11:06:11 +0530 Subject: [PATCH 1/6] Added apis to list commits by author and list the repos of an organization (including the private ones) --- .../org/kohsuke/github/GHOrganization.java | 21 ++++++++++ .../java/org/kohsuke/github/GHRepository.java | 38 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GHOrganization.java b/src/main/java/org/kohsuke/github/GHOrganization.java index ec899c0538..657ab93efd 100644 --- a/src/main/java/org/kohsuke/github/GHOrganization.java +++ b/src/main/java/org/kohsuke/github/GHOrganization.java @@ -173,4 +173,25 @@ protected void wrapUp(GHEventInfo[] page) { } }; } + + /** + * Lists up all the repositories of an organization using the specified page size. (this + * includes private organizations if the caller is authenticated accordingly) + * + * @param pageSize size for each page of items returned by GitHub. Maximum page size is 100. + * + */ + public PagedIterable listRepositories(final int pageSize) { + return new PagedIterable() { + public PagedIterator iterator() { + return new PagedIterator(root.retrieve().asIterator("/orgs/" + login + "/repos?per_page=" + pageSize, GHRepository[].class)) { + @Override + protected void wrapUp(GHRepository[] page) { + for (GHRepository c : page) + c.wrap(root); + } + }; + } + }; + } } diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index c1146f8e4b..685ef07fc3 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -487,6 +487,44 @@ protected void wrapUp(GHCommit[] page) { } }; } + + /** + * Lists all the commit by author + */ + public PagedIterable listCommitsByAuthor(final String author) { + return new PagedIterable() { + public PagedIterator iterator() { + return new PagedIterator(root.retrieve().asIterator(String.format("/repos/%s/%s/commits?author=%s", owner.login, name, author), GHCommit[].class)) { + protected void wrapUp(GHCommit[] page) { + for (GHCommit c : page) + c.wrapUp(GHRepository.this); + } + }; + } + }; + } + + /** + * Lists all the commit by author for the given branch from the startCommitSha (startCommitSha is optional) + */ + public PagedIterable listCommitsByAuthorAndBranch(final String author, final String branch, final String startCommitSha) { + String url =String.format("/repos/%s/%s/commits?author=%s", owner.login, name, author); + url = url + String.format("&sha=%s", branch); + if (startCommitSha != null && !startCommitSha.isEmpty()) { + url = url + String.format("&sha=%s", startCommitSha); + } + final String finalUrl = url; + return new PagedIterable() { + public PagedIterator iterator() { + return new PagedIterator(root.retrieve().asIterator(finalUrl, GHCommit[].class)) { + protected void wrapUp(GHCommit[] page) { + for (GHCommit c : page) + c.wrapUp(GHRepository.this); + } + }; + } + }; + } /** * Lists up all the commit comments in this repository. From 0b74692d62e80d36ce58aaaec10cfa890e6fdf43 Mon Sep 17 00:00:00 2001 From: vr100 Date: Wed, 19 Mar 2014 11:38:03 +0530 Subject: [PATCH 2/6] change in comment --- src/main/java/org/kohsuke/github/GHOrganization.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHOrganization.java b/src/main/java/org/kohsuke/github/GHOrganization.java index 657ab93efd..08b4f4c007 100644 --- a/src/main/java/org/kohsuke/github/GHOrganization.java +++ b/src/main/java/org/kohsuke/github/GHOrganization.java @@ -176,7 +176,7 @@ protected void wrapUp(GHEventInfo[] page) { /** * Lists up all the repositories of an organization using the specified page size. (this - * includes private organizations if the caller is authenticated accordingly) + * includes private repos if the caller is authenticated accordingly) * * @param pageSize size for each page of items returned by GitHub. Maximum page size is 100. * From 15c5c9615e594cdd23aa39e83039a3616bb9bd61 Mon Sep 17 00:00:00 2001 From: vr100 Date: Thu, 20 Mar 2014 15:00:34 +0530 Subject: [PATCH 3/6] Added pagesize parameter to 'Get commits by author and branch' api --- .../java/org/kohsuke/github/GHRepository.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 685ef07fc3..46d79e6c99 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -525,6 +525,30 @@ protected void wrapUp(GHCommit[] page) { } }; } + + /** + * Lists all the commit by author for the given branch from the startCommitSha (startCommitSha is optional) + */ + public PagedIterable listCommitsByAuthorAndBranch(final String author, final String branch, + final String startCommitSha, int pageSize) { + String url =String.format("/repos/%s/%s/commits?author=%s", owner.login, name, author); + url = url + String.format("&sha=%s", branch); + if (startCommitSha != null && !startCommitSha.isEmpty()) { + url = url + String.format("&sha=%s", startCommitSha); + } + url = url + String.format("&per_page=%s", pageSize); + final String finalUrl = url; + return new PagedIterable() { + public PagedIterator iterator() { + return new PagedIterator(root.retrieve().asIterator(finalUrl, GHCommit[].class)) { + protected void wrapUp(GHCommit[] page) { + for (GHCommit c : page) + c.wrapUp(GHRepository.this); + } + }; + } + }; + } /** * Lists up all the commit comments in this repository. From 9c02f918c1a09baa730c5b4ea59c1bf035de7dc2 Mon Sep 17 00:00:00 2001 From: vr100 Date: Wed, 26 Mar 2014 09:23:26 +0530 Subject: [PATCH 4/6] In order to handle http based github enterprise vm url, changing https to http --- src/main/java/org/kohsuke/github/Requester.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index fa9bc3191c..dd825e0b12 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -23,9 +23,8 @@ */ package org.kohsuke.github; -import org.apache.commons.io.IOUtils; +import static org.kohsuke.github.GitHub.MAPPER; -import javax.net.ssl.HttpsURLConnection; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -48,7 +47,7 @@ import java.util.Set; import java.util.zip.GZIPInputStream; -import static org.kohsuke.github.GitHub.MAPPER; +import org.apache.commons.io.IOUtils; /** * A builder pattern for making HTTP call and parsing its output. @@ -294,7 +293,7 @@ private void findNextURL(HttpURLConnection uc) throws MalformedURLException { private HttpURLConnection setupConnection(URL url) throws IOException { - HttpsURLConnection uc = (HttpsURLConnection) url.openConnection(); + HttpURLConnection uc = (HttpURLConnection) url.openConnection(); // if the authentication is needed but no credential is given, try it anyway (so that some calls // that do work with anonymous access in the reduced form should still work.) From d2ac81d7ba4e6ed4424d89c21458b468f4eb46fd Mon Sep 17 00:00:00 2001 From: vr100 Date: Wed, 23 Apr 2014 09:45:11 +0530 Subject: [PATCH 5/6] Using builder pattern to list commits in a repo --- .../java/org/kohsuke/github/GHRepository.java | 92 ++++++++++--------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 46d79e6c99..495bafc4af 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -37,6 +37,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -488,55 +489,60 @@ protected void wrapUp(GHCommit[] page) { }; } - /** - * Lists all the commit by author - */ - public PagedIterable listCommitsByAuthor(final String author) { - return new PagedIterable() { - public PagedIterator iterator() { - return new PagedIterator(root.retrieve().asIterator(String.format("/repos/%s/%s/commits?author=%s", owner.login, name, author), GHCommit[].class)) { - protected void wrapUp(GHCommit[] page) { - for (GHCommit c : page) - c.wrapUp(GHRepository.this); - } - }; - } - }; - } - - /** - * Lists all the commit by author for the given branch from the startCommitSha (startCommitSha is optional) - */ - public PagedIterable listCommitsByAuthorAndBranch(final String author, final String branch, final String startCommitSha) { - String url =String.format("/repos/%s/%s/commits?author=%s", owner.login, name, author); - url = url + String.format("&sha=%s", branch); - if (startCommitSha != null && !startCommitSha.isEmpty()) { - url = url + String.format("&sha=%s", startCommitSha); + public static class GHCommitBuilder { + String author; + String branch; + String startCommitSha; + Integer pageSize; + + public void setAuthor(String author) { + this.author = author; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + public void setStartCommitSha(String startCommitSha) { + this.startCommitSha = startCommitSha; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; } - final String finalUrl = url; - return new PagedIterable() { - public PagedIterator iterator() { - return new PagedIterator(root.retrieve().asIterator(finalUrl, GHCommit[].class)) { - protected void wrapUp(GHCommit[] page) { - for (GHCommit c : page) - c.wrapUp(GHRepository.this); - } - }; - } - }; } /** - * Lists all the commit by author for the given branch from the startCommitSha (startCommitSha is optional) + * Lists all the commit by different builder options */ - public PagedIterable listCommitsByAuthorAndBranch(final String author, final String branch, - final String startCommitSha, int pageSize) { - String url =String.format("/repos/%s/%s/commits?author=%s", owner.login, name, author); - url = url + String.format("&sha=%s", branch); - if (startCommitSha != null && !startCommitSha.isEmpty()) { - url = url + String.format("&sha=%s", startCommitSha); + public PagedIterable listCommits(GHCommitBuilder builder) { + String url = String.format("/repos/%s/%s/commits", owner.login, name); + + List params = new LinkedList(); + if (builder.author != null) { + params.add(String.format("author=%s", builder.author)); + } + if (builder.branch != null) { + params.add(String.format("sha=%s", builder.branch)); + } + if (builder.startCommitSha != null) { + params.add(String.format("sha=%s", builder.startCommitSha)); + } + if (builder.pageSize != null && builder.pageSize > 0) { + params.add(String.format("per_page=%d",builder.pageSize)); + } + + if (params.size() > 0) { + url = url + "?"; + } + for(String p: params) { + url = url + p + "&"; + } + if (params.size() > 0) { + // trimming off the last extra ampersand + url = url.substring(0, url.length() - 1); } - url = url + String.format("&per_page=%s", pageSize); + final String finalUrl = url; return new PagedIterable() { public PagedIterator iterator() { From 926776204b9dc18eedac34a749932c4b8f0510a9 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 9 May 2014 18:28:34 -0700 Subject: [PATCH 6/6] Implemented the builder pattern to my liking --- .../kohsuke/github/GHCommitQueryBuilder.java | 105 ++++++++++++++++++ .../java/org/kohsuke/github/GHRepository.java | 70 +----------- src/main/java/org/kohsuke/github/GitHub.java | 4 + .../java/org/kohsuke/github/Requester.java | 20 +++- src/test/java/org/kohsuke/AppTest.java | 20 +++- 5 files changed, 148 insertions(+), 71 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/GHCommitQueryBuilder.java diff --git a/src/main/java/org/kohsuke/github/GHCommitQueryBuilder.java b/src/main/java/org/kohsuke/github/GHCommitQueryBuilder.java new file mode 100644 index 0000000000..6d0a7ae995 --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHCommitQueryBuilder.java @@ -0,0 +1,105 @@ +package org.kohsuke.github; + +import java.util.Date; + +/** + * Builds up query for listing commits. + * + *

+ * Call various methods that set the filter criteria, then {@link #list()} method to actually list up the commit. + * + *

+ * GHRepository r = ...;
+ * for (GHCommit c : r.queryCommits().since(x).until(y).author("kohsuke")) {
+ *     ...
+ * }
+ * 
+ * + * @author Kohsuke Kawaguchi + * @see GHRepository#queryCommits() +*/ +public class GHCommitQueryBuilder { + private final Requester req; + private final GHRepository repo; + + /*package*/ GHCommitQueryBuilder(GHRepository repo) { + this.repo = repo; + this.req = repo.root.retrieve(); // requester to build up + } + + /** + * GItHub login or email address by which to filter by commit author. + */ + public GHCommitQueryBuilder author(String author) { + req.with("author",author); + return this; + } + + /** + * Only commits containing this file path will be returned. + */ + public GHCommitQueryBuilder path(String path) { + req.with("path",path); + return this; + } + + /** + * Specifies the SHA1 commit / tag / branch / etc to start listing commits from. + * + */ + public GHCommitQueryBuilder from(String ref) { + req.with("sha",ref); + return this; + } + + public GHCommitQueryBuilder pageSize(int pageSize) { + req.with("per_page",pageSize); + return this; + } + + /** + * Only commits after this date will be returned + */ + public GHCommitQueryBuilder since(Date dt) { + req.with("since",GitHub.printDate(dt)); + return this; + } + + /** + * Only commits after this date will be returned + */ + public GHCommitQueryBuilder since(long timestamp) { + return since(new Date(timestamp)); + } + + /** + * Only commits before this date will be returned + */ + public GHCommitQueryBuilder until(Date dt) { + req.with("until",GitHub.printDate(dt)); + return this; + } + + /** + * Only commits before this date will be returned + */ + public GHCommitQueryBuilder until(long timestamp) { + return until(new Date(timestamp)); + } + + /** + * Lists up the commits with the criteria built so far. + */ + public PagedIterable list() { + return new PagedIterable() { + public PagedIterator iterator() { + return new PagedIterator(req.asIterator(repo.getApiTailUrl("commits"), GHCommit[].class)) { + protected void wrapUp(GHCommit[] page) { + for (GHCommit c : page) + c.wrapUp(repo); + } + }; + } + }; + } +} diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 495bafc4af..fd50c63f7b 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -435,7 +435,7 @@ public GHCompare getCompare(String id1, String id2) throws IOException { } public GHCompare getCompare(GHCommit id1, GHCommit id2) throws IOException { - return getCompare(id1.getSHA1(),id2.getSHA1()); + return getCompare(id1.getSHA1(), id2.getSHA1()); } public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException { @@ -488,72 +488,12 @@ protected void wrapUp(GHCommit[] page) { } }; } - - public static class GHCommitBuilder { - String author; - String branch; - String startCommitSha; - Integer pageSize; - - public void setAuthor(String author) { - this.author = author; - } - - public void setBranch(String branch) { - this.branch = branch; - } - - public void setStartCommitSha(String startCommitSha) { - this.startCommitSha = startCommitSha; - } - - public void setPageSize(int pageSize) { - this.pageSize = pageSize; - } - } - + /** - * Lists all the commit by different builder options + * Search commits by specifying filters through a builder pattern. */ - public PagedIterable listCommits(GHCommitBuilder builder) { - String url = String.format("/repos/%s/%s/commits", owner.login, name); - - List params = new LinkedList(); - if (builder.author != null) { - params.add(String.format("author=%s", builder.author)); - } - if (builder.branch != null) { - params.add(String.format("sha=%s", builder.branch)); - } - if (builder.startCommitSha != null) { - params.add(String.format("sha=%s", builder.startCommitSha)); - } - if (builder.pageSize != null && builder.pageSize > 0) { - params.add(String.format("per_page=%d",builder.pageSize)); - } - - if (params.size() > 0) { - url = url + "?"; - } - for(String p: params) { - url = url + p + "&"; - } - if (params.size() > 0) { - // trimming off the last extra ampersand - url = url.substring(0, url.length() - 1); - } - - final String finalUrl = url; - return new PagedIterable() { - public PagedIterator iterator() { - return new PagedIterator(root.retrieve().asIterator(finalUrl, GHCommit[].class)) { - protected void wrapUp(GHCommit[] page) { - for (GHCommit c : page) - c.wrapUp(GHRepository.this); - } - }; - } - }; + public GHCommitQueryBuilder queryCommits() { + return new GHCommitQueryBuilder(this); } /** diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index c96c5de43d..2048f64ce9 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -392,6 +392,10 @@ public boolean isCredentialValid() throws IOException { throw new IllegalStateException("Unable to parse the timestamp: "+timestamp); } + /*package*/ static String printDate(Date dt) { + return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(dt); + } + /*package*/ static final ObjectMapper MAPPER = new ObjectMapper(); private static final String[] TIME_FORMATS = {"yyyy/MM/dd HH:mm:ss ZZZZ","yyyy-MM-dd'T'HH:mm:ss'Z'"}; diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index dd825e0b12..37370630ca 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -31,11 +31,13 @@ import java.io.InputStreamReader; import java.io.InterruptedIOException; import java.io.Reader; +import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -208,9 +210,23 @@ private T _to(String tailApiUrl, Class type, T instance) throws IOExcepti * * Every iterator call reports a new batch. */ - /*package*/ Iterator asIterator(final String tailApiUrl, final Class type) { + /*package*/ Iterator asIterator(String _tailApiUrl, final Class type) { method("GET"); - if (!args.isEmpty()) throw new IllegalStateException(); + + if (!args.isEmpty()) { + boolean first=true; + try { + for (Entry a : args) { + _tailApiUrl += first ? '?' : '&'; + first = false; + _tailApiUrl += URLEncoder.encode(a.key,"UTF-8")+'='+URLEncoder.encode(a.value.toString(),"UTF-8"); + } + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); // UTF-8 is mandatory + } + } + + final String tailApiUrl = _tailApiUrl; return new Iterator() { /** diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java index 0b8177657c..b8bee72d76 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/AppTest.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.net.URL; import java.util.ArrayList; +import java.util.Date; import java.util.Map; import java.util.Set; import java.util.List; @@ -152,7 +153,7 @@ public void testMembership() throws Exception { Set members = gitHub.getOrganization("jenkinsci").getRepository("violations-plugin").getCollaboratorNames(); System.out.println(members.contains("kohsuke")); } - + public void testMemberOrgs() throws Exception { Set o = gitHub.getUser("kohsuke").getOrganizations(); System.out.println(o); @@ -176,8 +177,19 @@ public void testListCommits() throws Exception { System.out.println(c.getSHA1()); sha1.add(c.getSHA1()); } - assertEquals("fdfad6be4db6f96faea1f153fb447b479a7a9cb7",sha1.get(0)); - assertEquals(1,sha1.size()); + assertEquals("fdfad6be4db6f96faea1f153fb447b479a7a9cb7", sha1.get(0)); + assertEquals(1, sha1.size()); + } + + public void testQueryCommits() throws Exception { + List sha1 = new ArrayList(); + for (GHCommit c : gitHub.getUser("jenkinsci").getRepository("jenkins").queryCommits() + .since(new Date(1199174400000L)).until(1201852800000L).path("pom.xml").list()) { + System.out.println(c.getSHA1()); + sha1.add(c.getSHA1()); + } + assertEquals("1cccddb22e305397151b2b7b87b4b47d74ca337b",sha1.get(0)); + assertEquals(29,sha1.size()); } public void testBranches() throws Exception { @@ -339,7 +351,7 @@ public void testCommitStatus() throws Exception { state = lst.get(0); System.out.println(state); assertEquals("oops!",state.getDescription()); - assertEquals("http://jenkins-ci.org/",state.getTargetUrl()); + assertEquals("http://jenkins-ci.org/", state.getTargetUrl()); } public void testCommitShortInfo() throws Exception {