diff --git a/pom.xml b/pom.xml index 89825f5056..f756423936 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.9 + 1.10 GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java diff --git a/src/main/java/org/kohsuke/github/GHOrganization.java b/src/main/java/org/kohsuke/github/GHOrganization.java index 04e4cd068e..6aec2259b5 100644 --- a/src/main/java/org/kohsuke/github/GHOrganization.java +++ b/src/main/java/org/kohsuke/github/GHOrganization.java @@ -33,7 +33,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 refreshRepository(name); + return getRepository(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 3e905c05b1..625ae03d1e 100644 --- a/src/main/java/org/kohsuke/github/GHPerson.java +++ b/src/main/java/org/kohsuke/github/GHPerson.java @@ -17,43 +17,22 @@ public abstract class GHPerson { protected int public_gist_count,public_repo_count,following_count,id; - /** - * Repositories that this user owns. - */ - private transient Map repositories; - /** * Gets the repositories this user owns. */ public synchronized Map getRepositories() throws IOException { - if (repositories==null) { - repositories = Collections.synchronizedMap(new TreeMap()); - for (int i=1; ; i++) { - Map map = root.retrieve("/repos/show/" + login + "?page=" + i, JsonRepositories.class).wrap(root); - repositories.putAll(map); - if (map.isEmpty()) break; - } + Map repositories = new TreeMap(); + for (int i=1; ; i++) { + Map map = root.retrieve("/repos/show/" + login + "?page=" + i, JsonRepositories.class).wrap(root); + repositories.putAll(map); + if (map.isEmpty()) break; } return Collections.unmodifiableMap(repositories); } - /** - * 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 = fetchRepository(name); - repositories.put(name,r); - return r; - } - - protected GHRepository fetchRepository(String name) throws IOException { - return root.retrieve("/repos/show/" + login + '/' + name, JsonRepository.class).wrap(root); - } - public GHRepository getRepository(String name) throws IOException { - return getRepositories().get(name); + return root.retrieve("/repos/show/" + login + '/' + name, JsonRepository.class).wrap(root); } /** diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index f40843ebb5..abfbfbbb14 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -145,6 +145,23 @@ public Set getCollaborators() throws IOException { return Collections.unmodifiableSet(r); } + /** + * Gets the names of the collaborators on this repository. + * This method deviates from the principle of this library but it works a lot faster than {@link #getCollaborators()}. + */ + public Set getCollaboratorNames() throws IOException { + Set r = new HashSet(root.retrieve("/repos/show/"+owner+"/"+name+"/collaborators",JsonCollaborators.class).collaborators); + return Collections.unmodifiableSet(r); + } + + /** + * If this repository belongs to an organization, return a set of teams. + */ + public Set getTeams() throws IOException { + return Collections.unmodifiableSet(root.retrieve("/repos/show/"+owner+"/"+name+"/teams",JsonTeams.class).toSet( + root.getOrganization(owner))); + } + public void addCollaborators(GHUser... users) throws IOException { addCollaborators(asList(users)); } @@ -224,7 +241,7 @@ public GHRepository forkTo(GHOrganization org) throws IOException { if (org.getLogin().equals(f.getInputByName("organization").getValueAttribute())) { // found it f.submit((HtmlButton)f.getElementsByTagName("button").get(0)); - return org.refreshRepository(name); + return org.getRepository(name); } } catch (ElementNotFoundException e) { // continue @@ -247,7 +264,7 @@ public void renameTo(String newName) throws IOException { f.submit((HtmlButton)f.getElementsByTagName("button").get(0)); // overwrite fields - final GHRepository r = getOwner().fetchRepository(newName); + final GHRepository r = getOwner().getRepository(newName); for (Field fi : getClass().getDeclaredFields()) { if (Modifier.isStatic(fi.getModifiers())) continue; fi.setAccessible(true); diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index c5dae6ec0c..c4f5b893c4 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -42,10 +42,13 @@ import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Properties; +import java.util.Set; import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.*; @@ -61,6 +64,7 @@ public class GitHub { private final Map users = new HashMap(); private final Map orgs = new HashMap(); + private String oauthAccessToken; private GitHub(String login, String apiToken, String password) { this.login = login; @@ -74,6 +78,17 @@ private GitHub(String login, String apiToken, String password) { encodedAuthorization = null; } + private GitHub (String oauthAccessToken) throws IOException { + + this.password = null; + this.encodedAuthorization = null; + + this.oauthAccessToken = oauthAccessToken; + + this.login = getMyself().getLogin(); + + + } /** * Obtains the credential from "~/.github" */ @@ -97,6 +112,9 @@ public static GitHub connect(String login, String apiToken, String password) thr return new GitHub(login,apiToken,password); } + public static GitHub connectUsingOAuth (String accessToken) throws IOException { + return new GitHub(accessToken); + } /** * Connects to GitHub anonymously. * @@ -107,12 +125,20 @@ public static GitHub connectAnonymously() { } /*package*/ void requireCredential() { - if (login==null || encodedAuthorization==null) + if ((login==null || encodedAuthorization==null) && oauthAccessToken == null) throw new IllegalStateException("This operation requires a credential but none is given to the GitHub constructor"); } /*package*/ URL getApiURL(String tailApiUrl) throws IOException { - return new URL("http://github.com/api/v2/json"+tailApiUrl); + + if (oauthAccessToken != null) { + // append the access token + + tailApiUrl = tailApiUrl + "?access_token=" + oauthAccessToken; + } + + return new URL("https://github.com/api/v2/json"+tailApiUrl); + } /*package*/ T retrieve(String tailApiUrl, Class type) throws IOException { @@ -129,10 +155,13 @@ public static GitHub connectAnonymously() { 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) + if (withAuth && this.oauthAccessToken == null) uc.setRequestProperty("Authorization", "Basic " + encodedAuthorization); + uc.setRequestMethod(method); try { @@ -172,9 +201,18 @@ private T _retrieve(String tailApiUrl, Class type, String method, boolean public GHUser getUser(String login) throws IOException { GHUser u = users.get(login); if (u==null) { + + if (oauthAccessToken != null) { + u = retrieve("/user/show",JsonUser.class).user; + u.root = this; + users.put(u.getLogin(),u); + } + else { u = retrieve("/user/show/"+login,JsonUser.class).user; u.root = this; users.put(login,u); + } + } return u; } @@ -202,6 +240,10 @@ public GHOrganization getOrganization(String name) throws IOException { return o; } + public Map getMyOrganizations() throws IOException { + return retrieveWithAuth("/organizations",JsonOrganizations.class).wrap(this); + + } /** * Gets the {@link GHUser} that represents yourself. */ diff --git a/src/main/java/org/kohsuke/github/JsonOrganizations.java b/src/main/java/org/kohsuke/github/JsonOrganizations.java new file mode 100644 index 0000000000..620e5e68d2 --- /dev/null +++ b/src/main/java/org/kohsuke/github/JsonOrganizations.java @@ -0,0 +1,44 @@ +/* + * The MIT License + * + * Copyright (c) 2010, Kohsuke Kawaguchi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.kohsuke.github; + +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * + */ +class JsonOrganizations { + public List organizations; + + public Map wrap(GitHub root) { + Map map = new TreeMap(); + for (GHOrganization o : organizations) { + o.root = root; + map.put(o.getLogin(),o); + } + return map; + } +} diff --git a/src/main/java/org/kohsuke/github/JsonTeams.java b/src/main/java/org/kohsuke/github/JsonTeams.java index 1f1db72ba7..85c6664ead 100644 --- a/src/main/java/org/kohsuke/github/JsonTeams.java +++ b/src/main/java/org/kohsuke/github/JsonTeams.java @@ -1,7 +1,9 @@ package org.kohsuke.github; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TreeMap; /** @@ -18,4 +20,13 @@ Map toMap(GHOrganization org) { } return r; } + + Set toSet(GHOrganization org) { + Set r = new HashSet(); + for (GHTeam t : teams) { + t.org = org; + r.add(t); + } + return r; + } } diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java index a039efacfe..d11428fb63 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/AppTest.java @@ -5,6 +5,7 @@ import org.kohsuke.github.GHOrganization.Permission; import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHTeam; +import org.kohsuke.github.GHUser; import org.kohsuke.github.GitHub; import java.io.IOException; @@ -20,8 +21,18 @@ public void testCredentialValid() throws IOException { assertFalse(GitHub.connect("totally","bogus").isCredentialValid()); } + public void testMembership() throws Exception { + GitHub gitHub = GitHub.connect(); + Set members = gitHub.getOrganization("jenkinsci").getRepository("violations-plugin").getCollaboratorNames(); + System.out.println(members.contains("kohsuke")); + } + public void testApp() throws IOException { GitHub gitHub = GitHub.connect(); +// GHPullRequest i = gitHub.getOrganization("jenkinsci").getRepository("sandbox").getPullRequest(1); +// for (GHIssueComment c : i.getComments()) +// System.out.println(c); +// System.out.println(i); // gitHub.getMyself().getRepository("perforce-plugin").setEmailServiceHook("kk@kohsuke.org");