From 280b8d3b5a6b5d0779a1d1949dbcf3b30aaece12 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Tue, 23 Nov 2010 21:52:30 -0800 Subject: [PATCH 01/18] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fec4cefb66..e0c940c63b 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.kohsuke github-api jar - 1.3 + 1.4-SNAPSHOT GitHub API for Java http://kohsuke.org/github-api/ GitHub API for Java From 1f3b8866e72e202f7f02edafa7194a9b1a93d101 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Thu, 9 Dec 2010 10:00:54 -0800 Subject: [PATCH 02/18] added support for repository commit hook access --- .../java/org/kohsuke/github/GHException.java | 14 +++ .../java/org/kohsuke/github/GHRepository.java | 114 +++++++++++++++++- src/test/java/org/kohsuke/AppTest.java | 23 +++- 3 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/GHException.java diff --git a/src/main/java/org/kohsuke/github/GHException.java b/src/main/java/org/kohsuke/github/GHException.java new file mode 100644 index 0000000000..c238e53c9e --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHException.java @@ -0,0 +1,14 @@ +package org.kohsuke.github; + +/** + * @author Kohsuke Kawaguchi + */ +public class GHException extends RuntimeException { + public GHException(String message) { + super(message); + } + + public GHException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 116b454b3e..c1c7c25d11 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -23,14 +23,23 @@ */ package org.kohsuke.github; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlInput; +import com.gargoylesoftware.htmlunit.html.HtmlPage; + import java.io.IOException; import java.net.URL; +import java.util.AbstractSet; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; +import java.util.List; import java.util.Set; -import static java.util.Arrays.asList; +import static java.util.Arrays.*; /** * A repository on GitHub. @@ -52,6 +61,9 @@ public String getHomepage() { return homepage; } + /** + * URL of this repository, like 'http://github.com/kohsuke/hudson' + */ public String getUrl() { return url; } @@ -154,6 +166,106 @@ private void verifyMine() throws IOException { throw new IOException("Operation not applicable to a repository owned by someone else: "+owner); } + /** + * Returns a set that represents the post-commit hook URLs. + * The returned set is live, and changes made to them are reflected to GitHub. + */ + public Set getPostCommitHooks() { + return postCommitHooks; + } + + /** + * Live set view of the post-commit hook. + */ + private final Set postCommitHooks = new AbstractSet() { + private List getPostCommitHooks() { + try { + verifyMine(); + + HtmlForm f = getForm(); + + List r = new ArrayList(); + for (HtmlInput i : f.getInputsByName("urls[]")) { + String v = i.getValueAttribute(); + if (v.length()==0) continue; + r.add(new URL(v)); + } + return r; + } catch (IOException e) { + throw new GHException("Failed to retrieve post-commit hooks",e); + } + } + + @Override + public Iterator iterator() { + return getPostCommitHooks().iterator(); + } + + @Override + public int size() { + return getPostCommitHooks().size(); + } + + @Override + public boolean add(URL url) { + try { + String u = url.toExternalForm(); + + verifyMine(); + + HtmlForm f = getForm(); + + List controls = f.getInputsByName("urls[]"); + for (HtmlInput i : controls) { + String v = i.getValueAttribute(); + if (v.length()==0) continue; + if (v.equals(u)) + return false; // already there + } + + controls.get(controls.size()-1).setValueAttribute(u); + f.submit(null); + return true; + } catch (IOException e) { + throw new GHException("Failed to update post-commit hooks",e); + } + } + + @Override + public boolean remove(Object o) { + try { + String u = ((URL)o).toExternalForm(); + + verifyMine(); + + HtmlForm f = getForm(); + + List controls = f.getInputsByName("urls[]"); + for (HtmlInput i : controls) { + String v = i.getValueAttribute(); + if (v.length()==0) continue; + if (v.equals(u)) { + i.setValueAttribute(""); + f.submit(null); + return true; + } + } + + return false; + } catch (IOException e) { + throw new GHException("Failed to update post-commit hooks",e); + } + } + + private HtmlForm getForm() throws IOException { + WebClient wc = root.createWebClient(); + HtmlPage pg = (HtmlPage)wc.getPage(getUrl()+"/admin"); + HtmlForm f = (HtmlForm) pg.getElementById("new_service"); + return f; + } + }; + + @Override public String toString() { return "Repository:"+owner+":"+name; diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java index 84ba0d6d8d..32cbb3edb2 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/AppTest.java @@ -9,6 +9,8 @@ import org.kohsuke.github.GitHub; import java.io.IOException; +import java.net.URL; +import java.util.Set; /** * Unit test for simple App. @@ -16,10 +18,9 @@ public class AppTest extends TestCase { public void testApp() throws IOException { GitHub gitHub = GitHub.connect(); - GHOrganization labs = gitHub.getOrganization("HudsonLabs"); - GHTeam t = labs.getTeams().get("Core Developers"); +// testOrganization(gitHub); - t.add(labs.getRepository("xyz")); + testPostCommitHook(gitHub); // t.add(gitHub.getMyself()); // System.out.println(t.getMembers()); @@ -35,4 +36,20 @@ public void testApp() throws IOException { // // System.out.println(hub.getUser("kohsuke").getRepository("hudson").getCollaborators()); } + + private void testPostCommitHook(GitHub gitHub) throws IOException { + GHRepository r = gitHub.getMyself().getRepository("foo"); + Set hooks = r.getPostCommitHooks(); + hooks.add(new URL("http://kohsuke.org/test")); + System.out.println(hooks); + hooks.remove(new URL("http://kohsuke.org/test")); + System.out.println(hooks); + } + + private void testOrganization(GitHub gitHub) throws IOException { + GHOrganization labs = gitHub.getOrganization("HudsonLabs"); + GHTeam t = labs.getTeams().get("Core Developers"); + + t.add(labs.getRepository("xyz")); + } } From a7c63e5d6c9d57206548d1060c2e89c19502ab3a Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Thu, 9 Dec 2010 15:31:51 -0800 Subject: [PATCH 03/18] added another factory method --- src/main/java/org/kohsuke/github/GitHub.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 616c123908..15cebd1b33 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -34,18 +34,15 @@ import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; -import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Properties; -import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.ANY; -import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE; +import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.*; /** * Root of the GitHub API. @@ -85,6 +82,10 @@ public static GitHub connect(String login, String apiToken) throws IOException { return new GitHub(login,apiToken,null); } + public static GitHub connect(String login, String apiToken, String password) throws IOException { + return new GitHub(login,apiToken,password); + } + /** * Connects to GitHub anonymously. * From c6558c6527a66502750868d9ff4de5c8ad8c6a91 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Thu, 9 Dec 2010 15:58:33 -0800 Subject: [PATCH 04/18] added a method to test credential. --- src/main/java/org/kohsuke/github/GitHub.java | 12 ++++++++++++ src/test/java/org/kohsuke/AppTest.java | 7 +++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 15cebd1b33..2a912eac5a 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -188,6 +188,18 @@ public GHRepository createRepository(String name, String description, String hom .with("public", isPublic ? 1 : 0).to(getApiURL("/repos/create"), JsonRepository.class).wrap(this); } + /** + * Ensures that the credential is valid. + */ + public boolean isCredentialValid() throws IOException { + try { + retrieveWithAuth(getApiURL("/user/show"),JsonUser.class); + return true; + } catch (IOException e) { + return false; + } + } + WebClient createWebClient() throws IOException { WebClient wc = new WebClient(); wc.setJavaScriptEnabled(false); diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java index 32cbb3edb2..fdcba4769a 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/AppTest.java @@ -1,8 +1,6 @@ package org.kohsuke; -import junit.framework.Test; import junit.framework.TestCase; -import junit.framework.TestSuite; import org.kohsuke.github.GHOrganization; import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHTeam; @@ -16,6 +14,11 @@ * Unit test for simple App. */ public class AppTest extends TestCase { + public void testCredentialValid() throws IOException { + assertTrue(GitHub.connect().isCredentialValid()); + assertFalse(GitHub.connect("totally","bogus").isCredentialValid()); + } + public void testApp() throws IOException { GitHub gitHub = GitHub.connect(); // testOrganization(gitHub); From e413912edd4d79c64b46a5b99c74d550d61d88ec Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Thu, 9 Dec 2010 16:04:17 -0800 Subject: [PATCH 05/18] unified the handling of the password and API token. --- src/main/java/org/kohsuke/github/GitHub.java | 17 ++++++++++------- src/main/java/org/kohsuke/github/Poster.java | 6 +++++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 2a912eac5a..58faa3757e 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -51,16 +51,22 @@ */ public class GitHub { /*package*/ final String login; - /*package*/ final String token; - /*package*/ final String password; + /*package*/ final String encodedAuthorization; + final String password; private final Map users = new HashMap(); private final Map orgs = new HashMap(); private GitHub(String login, String apiToken, String password) { this.login = login; - this.token = apiToken; this.password = password; + + BASE64Encoder enc = new sun.misc.BASE64Encoder(); + if (apiToken!=null || password!=null) { + String userpassword = apiToken!=null ? (login + "/token" + ":" + apiToken) : (login + ':'+password); + encodedAuthorization = enc.encode(userpassword.getBytes()); + } else + encodedAuthorization = null; } /** @@ -96,7 +102,7 @@ public static GitHub connectAnonymously() { } /*package*/ void requireCredential() { - if (login ==null || token ==null) + if (login==null || encodedAuthorization==null) throw new IllegalStateException("This operation requires a credential but none is given to the GitHub constructor"); } @@ -114,9 +120,6 @@ public static GitHub connectAnonymously() { /*package*/ T retrieveWithAuth(URL url, Class type, String method) throws IOException { HttpURLConnection uc = (HttpURLConnection) url.openConnection(); - BASE64Encoder enc = new sun.misc.BASE64Encoder(); - String userpassword = login + "/token" + ":" + token; - String encodedAuthorization = enc.encode(userpassword.getBytes()); uc.setRequestProperty("Authorization", "Basic " + encodedAuthorization); uc.setRequestMethod(method); diff --git a/src/main/java/org/kohsuke/github/Poster.java b/src/main/java/org/kohsuke/github/Poster.java index 0f4a939358..7eb27a588e 100644 --- a/src/main/java/org/kohsuke/github/Poster.java +++ b/src/main/java/org/kohsuke/github/Poster.java @@ -45,6 +45,7 @@ class Poster { private final GitHub root; private final Map args = new HashMap(); + private boolean authenticate; Poster(GitHub root) { this.root = root; @@ -52,7 +53,8 @@ class Poster { public Poster withCredential() { root.requireCredential(); - return with("login",root.login).with("token",root.token); + authenticate = true; + return this; } public Poster with(String key, int value) { @@ -86,6 +88,8 @@ public T to(URL url, Class type, String method) throws IOException { uc.setDoOutput(true); uc.setRequestProperty("Content-type","application/x-www-form-urlencoded"); + if (authenticate) + uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization); uc.setRequestMethod(method); From f96fda2d86be5335d87cac6218997bbafc78fe37 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 11 Dec 2010 22:16:17 -0800 Subject: [PATCH 06/18] support deleting a repository from organization --- src/main/java/org/kohsuke/github/GHRepository.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index c1c7c25d11..62d77b4172 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -146,9 +146,8 @@ private void modifyCollaborators(Collection users, String op) throws IOE * Deletes this repository. */ public void delete() throws IOException { - verifyMine(); Poster poster = new Poster(root).withCredential(); - URL url = root.getApiURL("/repos/delete/" + name); + URL url = root.getApiURL("/repos/delete/" + owner +"/"+name); DeleteToken token = poster.to(url, DeleteToken.class); poster.with("delete_token",token.delete_token).to(url); From 0212dce1e8ba29b947cb0c0c3af28162b3ecc226 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 11 Dec 2010 22:26:04 -0800 Subject: [PATCH 07/18] support multiple values for the same key. --- src/main/java/org/kohsuke/github/Poster.java | 25 +++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/kohsuke/github/Poster.java b/src/main/java/org/kohsuke/github/Poster.java index 7eb27a588e..4df4aa9d2e 100644 --- a/src/main/java/org/kohsuke/github/Poster.java +++ b/src/main/java/org/kohsuke/github/Poster.java @@ -29,14 +29,14 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; +import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; +import java.util.ArrayList; +import java.util.List; -import static org.kohsuke.github.GitHub.MAPPER; +import static org.kohsuke.github.GitHub.*; /** * Handles HTTP POST. @@ -44,7 +44,7 @@ */ class Poster { private final GitHub root; - private final Map args = new HashMap(); + private final List args = new ArrayList(); private boolean authenticate; Poster(GitHub root) { @@ -62,8 +62,13 @@ public Poster with(String key, int value) { } public Poster with(String key, String value) { - if (value!=null) - this.args.put(key,value); + if (value!=null) { + try { + args.add(URLEncoder.encode(key,"UTF-8")+'='+URLEncoder.encode(value,"UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new Error(e); // impossible + } + } return this; } @@ -94,11 +99,9 @@ public T to(URL url, Class type, String method) throws IOException { StringBuilder body = new StringBuilder(); - for (Entry e : args.entrySet()) { + for (String e : args) { if (body.length()>0) body.append('&'); - body.append(URLEncoder.encode(e.getKey(),"UTF-8")); - body.append('='); - body.append(URLEncoder.encode(e.getValue(),"UTF-8")); + body.append(e); } OutputStreamWriter o = new OutputStreamWriter(uc.getOutputStream(), "UTF-8"); From 2e544ed8ed64570b6c75db1eb7a6de1647106af4 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 11 Dec 2010 22:34:47 -0800 Subject: [PATCH 08/18] keeping up with GitHub API changes --- src/main/java/org/kohsuke/github/GHTeam.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHTeam.java b/src/main/java/org/kohsuke/github/GHTeam.java index 84d5efc789..f429499661 100644 --- a/src/main/java/org/kohsuke/github/GHTeam.java +++ b/src/main/java/org/kohsuke/github/GHTeam.java @@ -57,6 +57,6 @@ public void remove(GHRepository r) throws IOException { } private URL getApiURL(String tail) throws IOException { - return org.root.getApiURL("/organizations/"+org.getLogin()+"/teams/"+id+tail); + return org.root.getApiURL("/teams/"+id+tail); } } From f2271e8ee302d0b5af6def6529ddd07394886278 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 11 Dec 2010 22:35:03 -0800 Subject: [PATCH 09/18] added an operation to create a team. --- .../org/kohsuke/github/GHOrganization.java | 20 +++++++++++++++++++ .../java/org/kohsuke/github/JsonTeam.java | 13 ++++++++++++ src/test/java/org/kohsuke/AppTest.java | 6 +++++- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/kohsuke/github/JsonTeam.java diff --git a/src/main/java/org/kohsuke/github/GHOrganization.java b/src/main/java/org/kohsuke/github/GHOrganization.java index 24405373b6..596629af49 100644 --- a/src/main/java/org/kohsuke/github/GHOrganization.java +++ b/src/main/java/org/kohsuke/github/GHOrganization.java @@ -5,6 +5,8 @@ import com.gargoylesoftware.htmlunit.html.HtmlPage; import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; import java.util.Map; /** @@ -43,4 +45,22 @@ public GHRepository createRepository(String name, String description, String hom public Map getTeams() throws IOException { return root.retrieveWithAuth(root.getApiURL("/organizations/"+login+"/teams"),JsonTeams.class).toMap(this); } + + public enum Permission { ADMIN, PUSH, PULL } + + /** + * Creates a new team and assigns the repositories. + */ + public GHTeam createTeam(String name, Permission p, Collection repositories) throws IOException { + Poster post = new Poster(root).withCredential().with("team[name]", name).with("team[permission]", p.name().toLowerCase()); + for (GHRepository r : repositories) { + post.with("team[repo_names][]",r.getOwnerName()+'/'+r.getName()); + } + return post.to(root.getApiURL("/organizations/"+login+"/teams"),JsonTeam.class).wrap(this); + } + + public GHTeam createTeam(String name, Permission p, GHRepository... repositories) throws IOException { + return createTeam(name,p, Arrays.asList(repositories)); + } + } diff --git a/src/main/java/org/kohsuke/github/JsonTeam.java b/src/main/java/org/kohsuke/github/JsonTeam.java new file mode 100644 index 0000000000..63fde02765 --- /dev/null +++ b/src/main/java/org/kohsuke/github/JsonTeam.java @@ -0,0 +1,13 @@ +package org.kohsuke.github; + +/** + * @author Kohsuke Kawaguchi + */ +public class JsonTeam { + public GHTeam team; + + GHTeam wrap(GHOrganization org) { + team.org = org; + return team; + } +} diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java index fdcba4769a..032a87c699 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/AppTest.java @@ -2,6 +2,7 @@ import junit.framework.TestCase; import org.kohsuke.github.GHOrganization; +import org.kohsuke.github.GHOrganization.Permission; import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHTeam; import org.kohsuke.github.GitHub; @@ -22,8 +23,11 @@ public void testCredentialValid() throws IOException { public void testApp() throws IOException { GitHub gitHub = GitHub.connect(); // testOrganization(gitHub); +// testPostCommitHook(gitHub); - testPostCommitHook(gitHub); + GHOrganization o = gitHub.getOrganization("HudsonLabs"); + GHTeam t = o.createTeam("auto team", Permission.PUSH); + t.add(o.getRepository("auto-test")); // t.add(gitHub.getMyself()); // System.out.println(t.getMembers()); From 75144f156341d78f4464c75adfe8816bdf515eea Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sat, 11 Dec 2010 23:19:57 -0800 Subject: [PATCH 10/18] shouldn't be a part of test --- src/test/java/org/kohsuke/AppTest.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java index 032a87c699..a327c59b85 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/AppTest.java @@ -25,9 +25,7 @@ public void testApp() throws IOException { // testOrganization(gitHub); // testPostCommitHook(gitHub); - GHOrganization o = gitHub.getOrganization("HudsonLabs"); - GHTeam t = o.createTeam("auto team", Permission.PUSH); - t.add(o.getRepository("auto-test")); +// tryTeamCreation(gitHub); // t.add(gitHub.getMyself()); // System.out.println(t.getMembers()); @@ -44,6 +42,12 @@ public void testApp() throws IOException { // System.out.println(hub.getUser("kohsuke").getRepository("hudson").getCollaborators()); } + private void tryTeamCreation(GitHub gitHub) throws IOException { + GHOrganization o = gitHub.getOrganization("HudsonLabs"); + GHTeam t = o.createTeam("auto team", Permission.PUSH); + t.add(o.getRepository("auto-test")); + } + private void testPostCommitHook(GitHub gitHub) throws IOException { GHRepository r = gitHub.getMyself().getRepository("foo"); Set hooks = r.getPostCommitHooks(); From 9484a5f2acc4ce4a09696b6b8126a3df7fff027f Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Dec 2010 09:33:09 -0800 Subject: [PATCH 11/18] fixed a bug in createRepository --- .../java/org/kohsuke/github/GHOrganization.java | 2 +- src/main/java/org/kohsuke/github/GHPerson.java | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHOrganization.java b/src/main/java/org/kohsuke/github/GHOrganization.java index 596629af49..ae6bc34219 100644 --- a/src/main/java/org/kohsuke/github/GHOrganization.java +++ b/src/main/java/org/kohsuke/github/GHOrganization.java @@ -30,7 +30,7 @@ public GHRepository createRepository(String name, String description, String hom f.getSelectByName("team_id").getOptionByText(team).setSelected(true); f.submit(f.getButtonByCaption("Create Repository")); - return root.getUser(login).getRepository(name); + return refreshRepository(name); // GHRepository r = new Poster(root).withCredential() // .with("name", name).with("description", description).with("homepage", homepage) diff --git a/src/main/java/org/kohsuke/github/GHPerson.java b/src/main/java/org/kohsuke/github/GHPerson.java index db87442484..959453d3c1 100644 --- a/src/main/java/org/kohsuke/github/GHPerson.java +++ b/src/main/java/org/kohsuke/github/GHPerson.java @@ -28,11 +28,10 @@ public abstract class GHPerson { /** * Gets the repositories this user owns. */ - public Map getRepositories() throws IOException { + public synchronized Map getRepositories() throws IOException { if (repositories==null) { - repositories = new TreeMap(); - URL url = new URL("http://github.com/api/v2/json/repos/show/" + login); - for (GHRepository r : MAPPER.readValue(url, JsonRepositories.class).repositories) { + repositories = Collections.synchronizedMap(new TreeMap()); + for (GHRepository r : root.retrieve("/repos/show/" + login, JsonRepositories.class).repositories) { r.root = root; repositories.put(r.getName(),r); } @@ -41,6 +40,15 @@ public Map getRepositories() throws IOException { return Collections.unmodifiableMap(repositories); } + /** + * Fetches the repository of the given name from GitHub, and return it. + */ + protected GHRepository refreshRepository(String name) throws IOException { + GHRepository r = root.retrieve("/repos/show/" + login + '/' + name, JsonRepository.class).wrap(root); + repositories.put(name,r); + return r; + } + public GHRepository getRepository(String name) throws IOException { return getRepositories().get(name); } From 01257b4b86c065137541a10ab7c379fd78a08901 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Dec 2010 09:50:14 -0800 Subject: [PATCH 12/18] simplified a bit --- .../org/kohsuke/github/GHOrganization.java | 4 +-- .../java/org/kohsuke/github/GHRepository.java | 6 ++--- src/main/java/org/kohsuke/github/GHTeam.java | 10 ++++---- src/main/java/org/kohsuke/github/GHUser.java | 4 +-- src/main/java/org/kohsuke/github/GitHub.java | 25 ++++++++++--------- src/main/java/org/kohsuke/github/Poster.java | 8 ++++++ 6 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHOrganization.java b/src/main/java/org/kohsuke/github/GHOrganization.java index ae6bc34219..8f08877862 100644 --- a/src/main/java/org/kohsuke/github/GHOrganization.java +++ b/src/main/java/org/kohsuke/github/GHOrganization.java @@ -43,7 +43,7 @@ public GHRepository createRepository(String name, String description, String hom * Teams by their names. */ public Map getTeams() throws IOException { - return root.retrieveWithAuth(root.getApiURL("/organizations/"+login+"/teams"),JsonTeams.class).toMap(this); + return root.retrieveWithAuth("/organizations/"+login+"/teams",JsonTeams.class).toMap(this); } public enum Permission { ADMIN, PUSH, PULL } @@ -56,7 +56,7 @@ public GHTeam createTeam(String name, Permission p, Collection rep for (GHRepository r : repositories) { post.with("team[repo_names][]",r.getOwnerName()+'/'+r.getName()); } - return post.to(root.getApiURL("/organizations/"+login+"/teams"),JsonTeam.class).wrap(this); + return post.to("/organizations/"+login+"/teams",JsonTeam.class).wrap(this); } public GHTeam createTeam(String name, Permission p, GHRepository... repositories) throws IOException { diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 62d77b4172..d07ab6029b 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -138,7 +138,7 @@ public void removeCollaborators(Collection users) throws IOException { private void modifyCollaborators(Collection users, String op) throws IOException { verifyMine(); for (GHUser user : users) { - new Poster(root).withCredential().to(root.getApiURL("/repos/collaborators/"+name+ op +user.getLogin())); + new Poster(root).withCredential().to("/repos/collaborators/"+name+ op +user.getLogin()); } } @@ -147,7 +147,7 @@ private void modifyCollaborators(Collection users, String op) throws IOE */ public void delete() throws IOException { Poster poster = new Poster(root).withCredential(); - URL url = root.getApiURL("/repos/delete/" + owner +"/"+name); + String url = "/repos/delete/" + owner +"/"+name; DeleteToken token = poster.to(url, DeleteToken.class); poster.with("delete_token",token.delete_token).to(url); @@ -157,7 +157,7 @@ public void delete() throws IOException { * Forks this repository. */ public GHRepository fork() throws IOException { - return new Poster(root).withCredential().to(root.getApiURL("/repos/fork/" + owner + "/" + name), JsonRepository.class).wrap(root); + return new Poster(root).withCredential().to("/repos/fork/" + owner + "/" + name, JsonRepository.class).wrap(root); } private void verifyMine() throws IOException { diff --git a/src/main/java/org/kohsuke/github/GHTeam.java b/src/main/java/org/kohsuke/github/GHTeam.java index f429499661..e58a989505 100644 --- a/src/main/java/org/kohsuke/github/GHTeam.java +++ b/src/main/java/org/kohsuke/github/GHTeam.java @@ -31,29 +31,29 @@ public int getId() { * Retrieves the current members. */ public Set getMembers() throws IOException { - return org.root.retrieveWithAuth(getApiURL("/members"),JsonUsersWithDetails.class).toSet(org.root); + return org.root.retrieveWithAuth("/members",JsonUsersWithDetails.class).toSet(org.root); } /** * Adds a member to the team. */ public void add(GHUser u) throws IOException { - org.root.retrieveWithAuth(getApiURL("/members?name="+u.getLogin()),null, "POST"); + org.root.retrieveWithAuth("/members?name="+u.getLogin(),null, "POST"); } /** * Removes a member to the team. */ public void remove(GHUser u) throws IOException { - org.root.retrieveWithAuth(getApiURL("/members?name="+u.getLogin()),null, "DELETE"); + org.root.retrieveWithAuth("/members?name="+u.getLogin(),null, "DELETE"); } public void add(GHRepository r) throws IOException { - org.root.retrieveWithAuth(getApiURL("/repositories?name="+r.getOwnerName()+'/'+r.getName()),null, "POST"); + org.root.retrieveWithAuth("/repositories?name="+r.getOwnerName()+'/'+r.getName(),null, "POST"); } public void remove(GHRepository r) throws IOException { - org.root.retrieveWithAuth(getApiURL("/repositories?name="+r.getOwnerName()+'/'+r.getName()),null, "DELETE"); + org.root.retrieveWithAuth("/repositories?name="+r.getOwnerName()+'/'+r.getName(),null, "DELETE"); } private URL getApiURL(String tail) throws IOException { diff --git a/src/main/java/org/kohsuke/github/GHUser.java b/src/main/java/org/kohsuke/github/GHUser.java index 205b466c0e..178ea0e68b 100644 --- a/src/main/java/org/kohsuke/github/GHUser.java +++ b/src/main/java/org/kohsuke/github/GHUser.java @@ -108,14 +108,14 @@ public int getFollowersCount() { * Follow this user. */ public void follow() throws IOException { - new Poster(root).withCredential().to(root.getApiURL("/user/follow/"+login)); + new Poster(root).withCredential().to("/user/follow/"+login); } /** * Unfollow this user. */ public void unfollow() throws IOException { - new Poster(root).withCredential().to(root.getApiURL("/user/unfollow/"+login)); + new Poster(root).withCredential().to("/user/unfollow/"+login); } /** diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 58faa3757e..38698a41b0 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -106,19 +106,20 @@ public static GitHub connectAnonymously() { throw new IllegalStateException("This operation requires a credential but none is given to the GitHub constructor"); } - /*package*/ URL getApiURL(String tail) throws IOException { - return new URL("http://github.com/api/v2/json"+tail); + /*package*/ URL getApiURL(String tailApiUrl) throws IOException { + return new URL("http://github.com/api/v2/json"+tailApiUrl); } - /*package*/ T retrieve(String tail, Class type) throws IOException { - return MAPPER.readValue(getApiURL(tail),type); + /*package*/ T retrieve(String tailApiUrl, Class type) throws IOException { + return MAPPER.readValue(getApiURL(tailApiUrl),type); } - /*package*/ T retrieveWithAuth(URL url, Class type) throws IOException { - return retrieveWithAuth(url,type,"GET"); + /*package*/ T retrieveWithAuth(String tailApiUrl, Class type) throws IOException { + return retrieveWithAuth(tailApiUrl,type,"GET"); } - /*package*/ T retrieveWithAuth(URL url, Class type, String method) throws IOException { - HttpURLConnection uc = (HttpURLConnection) url.openConnection(); + + /*package*/ T retrieveWithAuth(String tailApiUrl, Class type, String method) throws IOException { + HttpURLConnection uc = (HttpURLConnection) getApiURL(tailApiUrl).openConnection(); uc.setRequestProperty("Authorization", "Basic " + encodedAuthorization); uc.setRequestMethod(method); @@ -141,7 +142,7 @@ public static GitHub connectAnonymously() { public GHUser getUser(String login) throws IOException { GHUser u = users.get(login); if (u==null) { - u = MAPPER.readValue(getApiURL("/user/show/"+login), JsonUser.class).user; + u = retrieve("/user/show/"+login,JsonUser.class).user; u.root = this; users.put(login,u); } @@ -164,7 +165,7 @@ protected GHUser getUser(GHUser orig) throws IOException { public GHOrganization getOrganization(String name) throws IOException { GHOrganization o = orgs.get(name); if (o==null) { - o = MAPPER.readValue(getApiURL("/organizations/"+name), JsonOrganization.class).organization; + o = retrieve("/organizations/"+name,JsonOrganization.class).organization; o.root = this; orgs.put(name,o); } @@ -188,7 +189,7 @@ public GHUser getMyself() throws IOException { public GHRepository createRepository(String name, String description, String homepage, boolean isPublic) throws IOException { return new Poster(this).withCredential() .with("name", name).with("description", description).with("homepage", homepage) - .with("public", isPublic ? 1 : 0).to(getApiURL("/repos/create"), JsonRepository.class).wrap(this); + .with("public", isPublic ? 1 : 0).to("/repos/create", JsonRepository.class).wrap(this); } /** @@ -196,7 +197,7 @@ public GHRepository createRepository(String name, String description, String hom */ public boolean isCredentialValid() throws IOException { try { - retrieveWithAuth(getApiURL("/user/show"),JsonUser.class); + retrieveWithAuth("/user/show",JsonUser.class); return true; } catch (IOException e) { return false; diff --git a/src/main/java/org/kohsuke/github/Poster.java b/src/main/java/org/kohsuke/github/Poster.java index 4df4aa9d2e..6ba219ed27 100644 --- a/src/main/java/org/kohsuke/github/Poster.java +++ b/src/main/java/org/kohsuke/github/Poster.java @@ -72,6 +72,14 @@ public Poster with(String key, String value) { return this; } + public void to(String tailApiUrl) throws IOException { + to(root.getApiURL(tailApiUrl)); + } + + public T to(String tailApiUrl, Class type) throws IOException { + return to(root.getApiURL(tailApiUrl),type); + } + public void to(URL url) throws IOException { to(url,null); } From ac1c003d54fb5593c56540cd31a60d4c894263a3 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Dec 2010 09:52:00 -0800 Subject: [PATCH 13/18] simplified. --- src/main/java/org/kohsuke/github/Poster.java | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/kohsuke/github/Poster.java b/src/main/java/org/kohsuke/github/Poster.java index 6ba219ed27..021b25404e 100644 --- a/src/main/java/org/kohsuke/github/Poster.java +++ b/src/main/java/org/kohsuke/github/Poster.java @@ -31,7 +31,6 @@ import java.io.Reader; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; -import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; @@ -73,15 +72,7 @@ public Poster with(String key, String value) { } public void to(String tailApiUrl) throws IOException { - to(root.getApiURL(tailApiUrl)); - } - - public T to(String tailApiUrl, Class type) throws IOException { - return to(root.getApiURL(tailApiUrl),type); - } - - public void to(URL url) throws IOException { - to(url,null); + to(tailApiUrl,null); } /** @@ -92,12 +83,12 @@ public void to(URL url) throws IOException { * @return * {@link Reader} that reads the response. */ - public T to(URL url, Class type) throws IOException { - return to(url,type,"POST"); + public T to(String tailApiUrl, Class type) throws IOException { + return to(tailApiUrl,type,"POST"); } - public T to(URL url, Class type, String method) throws IOException { - HttpURLConnection uc = (HttpURLConnection) url.openConnection(); + public T to(String tailApiUrl, Class type, String method) throws IOException { + HttpURLConnection uc = (HttpURLConnection) root.getApiURL(tailApiUrl).openConnection(); uc.setDoOutput(true); uc.setRequestProperty("Content-type","application/x-www-form-urlencoded"); From 94c307238f8ba5053cd5d7230c184e8ced0eac0e Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Dec 2010 09:52:34 -0800 Subject: [PATCH 14/18] unused method --- src/main/java/org/kohsuke/github/GHTeam.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHTeam.java b/src/main/java/org/kohsuke/github/GHTeam.java index e58a989505..40c24d4b0c 100644 --- a/src/main/java/org/kohsuke/github/GHTeam.java +++ b/src/main/java/org/kohsuke/github/GHTeam.java @@ -55,8 +55,4 @@ public void add(GHRepository r) throws IOException { public void remove(GHRepository r) throws IOException { org.root.retrieveWithAuth("/repositories?name="+r.getOwnerName()+'/'+r.getName(),null, "DELETE"); } - - private URL getApiURL(String tail) throws IOException { - return org.root.getApiURL("/teams/"+id+tail); - } } From a282cd3f74f7668f2d6986756fb7eb5ad9e7e25f Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Dec 2010 10:30:24 -0800 Subject: [PATCH 15/18] handle API rate limit --- src/main/java/org/kohsuke/github/GitHub.java | 52 +++++++++++++++----- src/main/java/org/kohsuke/github/Poster.java | 47 +++++++++--------- 2 files changed, 63 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 38698a41b0..db791305a1 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -36,6 +36,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.io.InterruptedIOException; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; @@ -111,7 +112,7 @@ public static GitHub connectAnonymously() { } /*package*/ T retrieve(String tailApiUrl, Class type) throws IOException { - return MAPPER.readValue(getApiURL(tailApiUrl),type); + return _retrieve(tailApiUrl, type, "GET", false); } /*package*/ T retrieveWithAuth(String tailApiUrl, Class type) throws IOException { @@ -119,21 +120,46 @@ public static GitHub connectAnonymously() { } /*package*/ T retrieveWithAuth(String tailApiUrl, Class type, String method) throws IOException { - HttpURLConnection uc = (HttpURLConnection) getApiURL(tailApiUrl).openConnection(); + return _retrieve(tailApiUrl, type, method, true); + } + + private T _retrieve(String tailApiUrl, Class type, String method, boolean withAuth) throws IOException { + while (true) {// loop while API rate limit is hit + HttpURLConnection uc = (HttpURLConnection) getApiURL(tailApiUrl).openConnection(); + + if (withAuth) + uc.setRequestProperty("Authorization", "Basic " + encodedAuthorization); + uc.setRequestMethod(method); + + try { + InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8"); + if (type==null) { + String data = IOUtils.toString(r); + return null; + } + return MAPPER.readValue(r,type); + } catch (IOException e) { + handleApiError(e,uc); + } + } + } - uc.setRequestProperty("Authorization", "Basic " + encodedAuthorization); - uc.setRequestMethod(method); - - try { - InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8"); - if (type==null) { - String data = IOUtils.toString(r); - return null; + /** + * If the error is because of the API limit, wait 10 sec and return normally. + * Otherwise throw an exception reporting an error. + */ + /*package*/ void handleApiError(IOException e, HttpURLConnection uc) throws IOException { + if ("0".equals(uc.getHeaderField("X-RateLimit-Remaining"))) { + // API limit reached. wait 10 secs and return normally + try { + Thread.sleep(10000); + return; + } catch (InterruptedException _) { + throw (InterruptedIOException)new InterruptedIOException().initCause(e); } - return MAPPER.readValue(r,type); - } catch (IOException e) { - throw (IOException)new IOException(IOUtils.toString(uc.getErrorStream(),"UTF-8")).initCause(e); } + + throw (IOException)new IOException(IOUtils.toString(uc.getErrorStream(),"UTF-8")).initCause(e); } /** diff --git a/src/main/java/org/kohsuke/github/Poster.java b/src/main/java/org/kohsuke/github/Poster.java index 021b25404e..700eb5f532 100644 --- a/src/main/java/org/kohsuke/github/Poster.java +++ b/src/main/java/org/kohsuke/github/Poster.java @@ -88,35 +88,36 @@ public T to(String tailApiUrl, Class type) throws IOException { } public T to(String tailApiUrl, Class type, String method) throws IOException { - HttpURLConnection uc = (HttpURLConnection) root.getApiURL(tailApiUrl).openConnection(); + while (true) {// loop while API rate limit is hit + HttpURLConnection uc = (HttpURLConnection) root.getApiURL(tailApiUrl).openConnection(); - uc.setDoOutput(true); - uc.setRequestProperty("Content-type","application/x-www-form-urlencoded"); - if (authenticate) - uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization); - uc.setRequestMethod(method); + uc.setDoOutput(true); + uc.setRequestProperty("Content-type","application/x-www-form-urlencoded"); + if (authenticate) + uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization); + uc.setRequestMethod(method); - StringBuilder body = new StringBuilder(); - for (String e : args) { - if (body.length()>0) body.append('&'); - body.append(e); - } - - OutputStreamWriter o = new OutputStreamWriter(uc.getOutputStream(), "UTF-8"); - o.write(body.toString()); - o.close(); + StringBuilder body = new StringBuilder(); + for (String e : args) { + if (body.length()>0) body.append('&'); + body.append(e); + } + OutputStreamWriter o = new OutputStreamWriter(uc.getOutputStream(), "UTF-8"); + o.write(body.toString()); + o.close(); - try { - InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8"); - if (type==null) { - String data = IOUtils.toString(r); - return null; + try { + InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8"); + if (type==null) { + String data = IOUtils.toString(r); + return null; + } + return MAPPER.readValue(r,type); + } catch (IOException e) { + root.handleApiError(e,uc); } - return MAPPER.readValue(r,type); - } catch (IOException e) { - throw (IOException)new IOException(IOUtils.toString(uc.getErrorStream(),"UTF-8")).initCause(e); } } } From bbf045dbf1e05f465aa2e836de72a59b2e94e578 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Dec 2010 21:17:08 -0800 Subject: [PATCH 16/18] bug fix --- src/main/java/org/kohsuke/github/GHPerson.java | 1 + src/main/java/org/kohsuke/github/GHTeam.java | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHPerson.java b/src/main/java/org/kohsuke/github/GHPerson.java index 959453d3c1..69db48772f 100644 --- a/src/main/java/org/kohsuke/github/GHPerson.java +++ b/src/main/java/org/kohsuke/github/GHPerson.java @@ -44,6 +44,7 @@ public synchronized Map getRepositories() throws IOExceptio * Fetches the repository of the given name from GitHub, and return it. */ protected GHRepository refreshRepository(String name) throws IOException { + if (repositories==null) getRepositories(); // fetch the base first GHRepository r = root.retrieve("/repos/show/" + login + '/' + name, JsonRepository.class).wrap(root); repositories.put(name,r); return r; diff --git a/src/main/java/org/kohsuke/github/GHTeam.java b/src/main/java/org/kohsuke/github/GHTeam.java index 40c24d4b0c..51f8b4a99b 100644 --- a/src/main/java/org/kohsuke/github/GHTeam.java +++ b/src/main/java/org/kohsuke/github/GHTeam.java @@ -1,7 +1,6 @@ package org.kohsuke.github; import java.io.IOException; -import java.net.URL; import java.util.Set; /** @@ -31,28 +30,32 @@ public int getId() { * Retrieves the current members. */ public Set getMembers() throws IOException { - return org.root.retrieveWithAuth("/members",JsonUsersWithDetails.class).toSet(org.root); + return org.root.retrieveWithAuth(api("/members"),JsonUsersWithDetails.class).toSet(org.root); } /** * Adds a member to the team. */ public void add(GHUser u) throws IOException { - org.root.retrieveWithAuth("/members?name="+u.getLogin(),null, "POST"); + org.root.retrieveWithAuth(api("/members?name="+u.getLogin()),null, "POST"); } /** * Removes a member to the team. */ public void remove(GHUser u) throws IOException { - org.root.retrieveWithAuth("/members?name="+u.getLogin(),null, "DELETE"); + org.root.retrieveWithAuth(api("/members?name="+u.getLogin()),null, "DELETE"); } public void add(GHRepository r) throws IOException { - org.root.retrieveWithAuth("/repositories?name="+r.getOwnerName()+'/'+r.getName(),null, "POST"); + org.root.retrieveWithAuth(api("/repositories?name="+r.getOwnerName()+'/'+r.getName()),null, "POST"); } public void remove(GHRepository r) throws IOException { - org.root.retrieveWithAuth("/repositories?name="+r.getOwnerName()+'/'+r.getName(),null, "DELETE"); + org.root.retrieveWithAuth(api("/repositories?name="+r.getOwnerName()+'/'+r.getName()),null, "DELETE"); + } + + private String api(String tail) { + return "/teams/"+id+tail; } } From d6b1aad91fa58524109bf65466760982cef979d5 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Dec 2010 21:21:31 -0800 Subject: [PATCH 17/18] added an operation to retrieve repositories from a team. --- src/main/java/org/kohsuke/github/GHPerson.java | 5 +---- src/main/java/org/kohsuke/github/GHTeam.java | 5 +++++ .../java/org/kohsuke/github/JsonRepositories.java | 11 +++++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHPerson.java b/src/main/java/org/kohsuke/github/GHPerson.java index 69db48772f..719fb978f2 100644 --- a/src/main/java/org/kohsuke/github/GHPerson.java +++ b/src/main/java/org/kohsuke/github/GHPerson.java @@ -31,10 +31,7 @@ public abstract class GHPerson { public synchronized Map getRepositories() throws IOException { if (repositories==null) { repositories = Collections.synchronizedMap(new TreeMap()); - for (GHRepository r : root.retrieve("/repos/show/" + login, JsonRepositories.class).repositories) { - r.root = root; - repositories.put(r.getName(),r); - } + repositories.putAll(root.retrieve("/repos/show/" + login, JsonRepositories.class).wrap(root)); } return Collections.unmodifiableMap(repositories); diff --git a/src/main/java/org/kohsuke/github/GHTeam.java b/src/main/java/org/kohsuke/github/GHTeam.java index 51f8b4a99b..dee87bc4e3 100644 --- a/src/main/java/org/kohsuke/github/GHTeam.java +++ b/src/main/java/org/kohsuke/github/GHTeam.java @@ -1,6 +1,7 @@ package org.kohsuke.github; import java.io.IOException; +import java.util.Map; import java.util.Set; /** @@ -33,6 +34,10 @@ public Set getMembers() throws IOException { return org.root.retrieveWithAuth(api("/members"),JsonUsersWithDetails.class).toSet(org.root); } + public Map getRepositories() throws IOException { + return org.root.retrieveWithAuth(api("/repositories"),JsonRepositories.class).wrap(org.root); + } + /** * Adds a member to the team. */ diff --git a/src/main/java/org/kohsuke/github/JsonRepositories.java b/src/main/java/org/kohsuke/github/JsonRepositories.java index b3a08853ae..69e0b138c7 100644 --- a/src/main/java/org/kohsuke/github/JsonRepositories.java +++ b/src/main/java/org/kohsuke/github/JsonRepositories.java @@ -24,10 +24,21 @@ package org.kohsuke.github; import java.util.List; +import java.util.Map; +import java.util.TreeMap; /** * @author Kohsuke Kawaguchi */ class JsonRepositories { public List repositories; + + public Map wrap(GitHub root) { + Map map = new TreeMap(); + for (GHRepository r : repositories) { + r.root = root; + map.put(r.getName(),r); + } + return map; + } } From 83a45f9adc961ed859d66a05814f8654887f3604 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Tue, 14 Dec 2010 09:54:18 -0800 Subject: [PATCH 18/18] [maven-release-plugin] prepare release github-api-1.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e0c940c63b..6298239952 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.kohsuke github-api jar - 1.4-SNAPSHOT + 1.4 GitHub API for Java http://kohsuke.org/github-api/ GitHub API for Java