diff --git a/pom.xml b/pom.xml index 82b584aec5..343fee323e 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.14 + 1.15 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 6aec2259b5..96bf191c36 100644 --- a/src/main/java/org/kohsuke/github/GHOrganization.java +++ b/src/main/java/org/kohsuke/github/GHOrganization.java @@ -6,12 +6,15 @@ import com.gargoylesoftware.htmlunit.html.HtmlPage; import java.io.IOException; +import java.util.AbstractList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; +import static org.kohsuke.github.ApiVersion.V3; + /** * @author Kohsuke Kawaguchi */ @@ -23,23 +26,14 @@ public class GHOrganization extends GHPerson { * Newly created repository. */ public GHRepository createRepository(String name, String description, String homepage, String team, boolean isPublic) throws IOException { + return createRepository(name,description,homepage,getTeams().get(team),isPublic); + } + + public GHRepository createRepository(String name, String description, String homepage, GHTeam team, boolean isPublic) throws IOException { // such API doesn't exist, so fall back to HTML scraping - WebClient wc = root.createWebClient(); - HtmlPage pg = (HtmlPage)wc.getPage("https://github.com/organizations/"+login+"/repositories/new"); - HtmlForm f = pg.getForms().get(1); - f.getInputByName("repository[name]").setValueAttribute(name); - f.getInputByName("repository[description]").setValueAttribute(description); - f.getInputByName("repository[homepage]").setValueAttribute(homepage); - f.getSelectByName("team_id").getOptionByText(team).setSelected(true); - f.submit(f.getButtonByCaption("Create Repository")); - - return getRepository(name); - -// GHRepository r = new Poster(root).withCredential() -// .with("name", name).with("description", description).with("homepage", homepage) -// .with("public", isPublic ? 1 : 0).to(root.getApiURL("/organizations/"+login+"/repos/create"), JsonRepository.class).repository; -// r.root = root; -// return r; + return new Poster(root,V3).withCredential() + .with("name", name).with("description", description).with("homepage", homepage) + .with("public", isPublic).with("team_id",team.getId()).to("/orgs/"+login+"/repos", GHRepository.class).wrap(root); } /** @@ -49,6 +43,45 @@ public Map getTeams() throws IOException { return root.retrieveWithAuth("/organizations/"+login+"/teams",JsonTeams.class).toMap(this); } + /** + * Publicizes the membership. + */ + public void publicize(GHUser u) throws IOException { + root.retrieveWithAuth3("/orgs/" + login + "/public_members/" + u.getLogin(), null, "PUT"); + } + + /** + * All the members of this organization. + */ + public List getMembers() throws IOException { + return new AbstractList() { + // these are shallow objects with only some limited values filled out + // TODO: it's better to allow objects to fill themselves in later when missing values are requested + final GHUser[] shallow = root.retrieveWithAuth3("/orgs/" + login + "/members", GHUser[].class); + + @Override + public GHUser get(int index) { + try { + return root.getUser(shallow[index].getLogin()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public int size() { + return shallow.length; + } + }; + } + + /** + * Conceals the membership. + */ + public void conceal(GHUser u) throws IOException { + root.retrieveWithAuth3("/orgs/" + login + "/public_members/" + u.getLogin(), null, "DELETE"); + } + public enum Permission { ADMIN, PUSH, PULL } /** diff --git a/src/main/java/org/kohsuke/github/GHPerson.java b/src/main/java/org/kohsuke/github/GHPerson.java index 625ae03d1e..393c342e35 100644 --- a/src/main/java/org/kohsuke/github/GHPerson.java +++ b/src/main/java/org/kohsuke/github/GHPerson.java @@ -1,5 +1,6 @@ package org.kohsuke.github; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.Collections; import java.util.Map; @@ -23,7 +24,7 @@ public abstract class GHPerson { public synchronized Map getRepositories() throws IOException { Map repositories = new TreeMap(); for (int i=1; ; i++) { - Map map = root.retrieve("/repos/show/" + login + "?page=" + i, JsonRepositories.class).wrap(root); + Map map = root.retrieve3("/user/" + login + "/repos?per_page=100&page=" + i, JsonRepositories.class).wrap(root); repositories.putAll(map); if (map.isEmpty()) break; } @@ -31,8 +32,17 @@ public synchronized Map getRepositories() throws IOExceptio return Collections.unmodifiableMap(repositories); } + /** + * + * @return + * null if the repository was not found + */ public GHRepository getRepository(String name) throws IOException { - return root.retrieve("/repos/show/" + login + '/' + name, JsonRepository.class).wrap(root); + try { + return root.retrieve3("/repos/" + login + '/' + name, GHRepository.class).wrap(root); + } catch (FileNotFoundException e) { + return null; + } } /** diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index db1d37e18d..44abaca1c3 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -59,7 +59,10 @@ public class GHRepository { /*package almost final*/ GitHub root; - private String description, homepage, url, name, owner; + private String description, homepage, name; + private String url; // this is the API url + private String html_url; // this is the UI + private GHUser owner; // not fully populated. beware. private boolean has_issues, has_wiki, fork, _private, has_downloads; private int watchers,forks,open_issues; private String created_at, pushed_at; @@ -76,7 +79,7 @@ public String getHomepage() { * URL of this repository, like 'http://github.com/kohsuke/hudson' */ public String getUrl() { - return url; + return html_url; } public String getName() { @@ -84,15 +87,15 @@ public String getName() { } public GHUser getOwner() throws IOException { - return root.getUser(owner); + return root.getUser(owner.login); // because 'owner' isn't fully populated } public List getIssues(GHIssueState state) throws IOException { - return root.retrieve("/issues/list/" + owner + "/" + name + "/" + state.toString().toLowerCase(), JsonIssues.class).wrap(this); + return root.retrieve("/issues/list/" + owner.login + "/" + name + "/" + state.toString().toLowerCase(), JsonIssues.class).wrap(this); } protected String getOwnerName() { - return owner; + return owner.login; } public boolean hasIssues() { @@ -142,7 +145,7 @@ public Date getCreatedAt() { */ public Set getCollaborators() throws IOException { Set r = new HashSet(); - for (String u : root.retrieve("/repos/show/"+owner+"/"+name+"/collaborators",JsonCollaborators.class).collaborators) + for (String u : root.retrieve("/repos/show/"+owner.login+"/"+name+"/collaborators",JsonCollaborators.class).collaborators) r.add(root.getUser(u)); return Collections.unmodifiableSet(r); } @@ -152,7 +155,7 @@ public Set getCollaborators() throws IOException { * 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); + Set r = new HashSet(root.retrieve("/repos/show/"+owner.login+"/"+name+"/collaborators",JsonCollaborators.class).collaborators); return Collections.unmodifiableSet(r); } @@ -160,8 +163,8 @@ public Set getCollaboratorNames() throws IOException { * If this repository belongs to an organization, return a set of teams. */ public Set getTeams() throws IOException { - return Collections.unmodifiableSet(root.retrieveWithAuth("/repos/show/"+owner+"/"+name+"/teams",JsonTeams.class).toSet( - root.getOrganization(owner))); + return Collections.unmodifiableSet(root.retrieveWithAuth("/repos/show/"+owner.login+"/"+name+"/teams",JsonTeams.class).toSet( + root.getOrganization(owner.login))); } public void addCollaborators(GHUser... users) throws IOException { @@ -204,7 +207,7 @@ public void setEmailServiceHook(String address) throws IOException { */ public void enableIssueTracker(boolean v) throws IOException { new Poster(root).withCredential().with("values[has_issues]",String.valueOf(v)) - .to("/repos/show/" + owner + "/" + name); + .to("/repos/show/" + owner.login + "/" + name); } /** @@ -212,7 +215,7 @@ public void enableIssueTracker(boolean v) throws IOException { */ public void enableWiki(boolean v) throws IOException { new Poster(root).withCredential().with("values[has_wiki]",String.valueOf(v)) - .to("/repos/show/" + owner + "/" + name); + .to("/repos/show/" + owner.login + "/" + name); } /** @@ -220,7 +223,7 @@ public void enableWiki(boolean v) throws IOException { */ public void delete() throws IOException { Poster poster = new Poster(root).withCredential(); - String url = "/repos/delete/" + owner +"/"+name; + String url = "/repos/delete/" + owner.login +"/"+name; DeleteToken token = poster.to(url, DeleteToken.class); poster.with("delete_token",token.delete_token).to(url); @@ -233,7 +236,7 @@ public void delete() throws IOException { * Newly forked repository that belong to you. */ public GHRepository fork() throws IOException { - return new Poster(root).withCredential().to("/repos/fork/" + owner + "/" + name, JsonRepository.class).wrap(root); + return new Poster(root,V3).withCredential().to("/repos/" + owner.login + "/" + name + "/forks", GHRepository.class, "POST").wrap(root); } /** @@ -243,7 +246,7 @@ public GHRepository fork() throws IOException { * Newly forked repository that belong to you. */ public GHRepository forkTo(GHOrganization org) throws IOException { - new Poster(root, V3).withCredential().to(String.format("/repos/%s/%s/forks?org=%s",owner,name,org.getLogin())); + new Poster(root, V3).withCredential().to(String.format("/repos/%s/%s/forks?org=%s",owner.login,name,org.getLogin())); return org.getRepository(name); } @@ -277,21 +280,21 @@ public void renameTo(String newName) throws IOException { } } - throw new IllegalArgumentException("Either you don't have the privilege to rename "+owner+'/'+name+" or there's a bug in HTML scraping"); + throw new IllegalArgumentException("Either you don't have the privilege to rename "+owner.login+'/'+name+" or there's a bug in HTML scraping"); } /** * Retrieves a specified pull request. */ public GHPullRequest getPullRequest(int i) throws IOException { - return root.retrieveWithAuth("/pulls/" + owner + '/' + name + "/" + i, JsonPullRequest.class).wrap(this); + return root.retrieveWithAuth("/pulls/" + owner.login + '/' + name + "/" + i, JsonPullRequest.class).wrap(this); } /** * Retrieves all the pull requests of a particular state. */ public List getPullRequests(GHIssueState state) throws IOException { - return root.retrieveWithAuth("/pulls/"+owner+'/'+name+"/"+state.name().toLowerCase(Locale.ENGLISH),JsonPullRequests.class).wrap(this); + return root.retrieveWithAuth("/pulls/"+owner.login+'/'+name+"/"+state.name().toLowerCase(Locale.ENGLISH),JsonPullRequests.class).wrap(this); } // this is no different from getPullRequests(OPEN) @@ -303,8 +306,8 @@ public List getPullRequests(GHIssueState state) throws IOExceptio // } private void verifyMine() throws IOException { - if (!root.login.equals(owner)) - throw new IOException("Operation not applicable to a repository owned by someone else: "+owner); + if (!root.login.equals(owner.login)) + throw new IOException("Operation not applicable to a repository owned by someone else: "+owner.login); } /** @@ -406,10 +409,14 @@ private HtmlForm getForm() throws IOException { } }; + /*package*/ GHRepository wrap(GitHub root) { + this.root = root; + return this; + } @Override public String toString() { - return "Repository:"+owner+":"+name; + return "Repository:"+owner.login+":"+name; } @Override @@ -421,7 +428,7 @@ public int hashCode() { public boolean equals(Object obj) { if (obj instanceof GHRepository) { GHRepository that = (GHRepository) obj; - return this.owner.equals(that.owner) + return this.owner.login.equals(that.owner.login) && this.name.equals(that.name); } return false; diff --git a/src/main/java/org/kohsuke/github/GHTeam.java b/src/main/java/org/kohsuke/github/GHTeam.java index dee87bc4e3..a9443acb08 100644 --- a/src/main/java/org/kohsuke/github/GHTeam.java +++ b/src/main/java/org/kohsuke/github/GHTeam.java @@ -35,7 +35,7 @@ public Set getMembers() throws IOException { } public Map getRepositories() throws IOException { - return org.root.retrieveWithAuth(api("/repositories"),JsonRepositories.class).wrap(org.root); + return org.root.retrieveWithAuth3(api("/repos"),JsonRepositories.class).wrap(org.root); } /** diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 8eb543b949..118f5a538b 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -34,7 +34,9 @@ import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.InterruptedIOException; import java.net.HttpURLConnection; @@ -42,15 +44,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.*; +import static org.kohsuke.github.ApiVersion.*; /** * Root of the GitHub API. @@ -141,27 +141,44 @@ public static GitHub connectAnonymously() { } /*package*/ T retrieve(String tailApiUrl, Class type) throws IOException { - return _retrieve(tailApiUrl, type, "GET", false); + return _retrieve(tailApiUrl, type, "GET", false, V2); + } + + /*package*/ T retrieve3(String tailApiUrl, Class type) throws IOException { + return _retrieve(tailApiUrl, type, "GET", false, V3); } /*package*/ T retrieveWithAuth(String tailApiUrl, Class type) throws IOException { return retrieveWithAuth(tailApiUrl,type,"GET"); } + /*package*/ T retrieveWithAuth3(String tailApiUrl, Class type) throws IOException { + return _retrieve(tailApiUrl, type, "GET", true, V3); + } + /*package*/ T retrieveWithAuth(String tailApiUrl, Class type, String method) throws IOException { - return _retrieve(tailApiUrl, type, method, true); + return _retrieve(tailApiUrl, type, method, true, V2); } - private T _retrieve(String tailApiUrl, Class type, String method, boolean withAuth) throws IOException { + /*package*/ T retrieveWithAuth3(String tailApiUrl, Class type, String method) throws IOException { + return _retrieve(tailApiUrl, type, method, true, V3); + } + + private T _retrieve(String tailApiUrl, Class type, String method, boolean withAuth, ApiVersion v) throws IOException { while (true) {// loop while API rate limit is hit - HttpURLConnection uc = (HttpURLConnection) getApiURL(ApiVersion.V2,tailApiUrl).openConnection(); + HttpURLConnection uc = (HttpURLConnection) getApiURL(v,tailApiUrl).openConnection(); if (withAuth && this.oauthAccessToken == null) uc.setRequestProperty("Authorization", "Basic " + encodedAuthorization); uc.setRequestMethod(method); + if (method.equals("PUT")) { + uc.setDoOutput(true); + uc.setRequestProperty("Content-Length","0"); + uc.getOutputStream().close(); + } try { InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8"); @@ -191,30 +208,61 @@ private T _retrieve(String tailApiUrl, Class type, String method, boolean } } - throw (IOException)new IOException(IOUtils.toString(uc.getErrorStream(),"UTF-8")).initCause(e); + if (e instanceof FileNotFoundException) + throw e; // pass through 404 Not Found to allow the caller to handle it intelligently + + InputStream es = uc.getErrorStream(); + if (es!=null) + throw (IOException)new IOException(IOUtils.toString(es,"UTF-8")).initCause(e); + else + throw e; } /** - * Obtains the object that represents the named user. - */ - 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; - } + * Gets the {@link GHUser} that represents yourself. + */ + public GHUser getMyself() throws IOException { + requireCredential(); + + GHUser u = null; + + if (oauthAccessToken != null) { + + u = retrieve("/user/show", JsonUser.class).user; + + u.root = this; + users.put(u.getLogin(), u); + + return u; + } + else { + return getUser(login); + } + + + + } + + /** + * Obtains the object that represents the named user. + */ + public GHUser getUser(String login) throws IOException { + GHUser u = users.get(login); + if (u == null) { + + if (oauthAccessToken != null) { + u = retrieve("/user/show/" + login, 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; + } /** * Interns the given {@link GHUser}. @@ -243,14 +291,7 @@ public Map getMyOrganizations() throws IOException { return retrieveWithAuth("/organizations",JsonOrganizations.class).wrap(this); } - /** - * Gets the {@link GHUser} that represents yourself. - */ - public GHUser getMyself() throws IOException { - requireCredential(); - return getUser(login); - } - + /** * Creates a new repository. * @@ -258,9 +299,9 @@ public GHUser getMyself() throws IOException { * Newly created repository. */ public GHRepository createRepository(String name, String description, String homepage, boolean isPublic) throws IOException { - return new Poster(this).withCredential() + return new Poster(this,V3).withCredential() .with("name", name).with("description", description).with("homepage", homepage) - .with("public", isPublic ? 1 : 0).to("/repos/create", JsonRepository.class).wrap(this); + .with("public", isPublic ? 1 : 0).to("/user/repos", GHRepository.class,"POST").wrap(this); } /** diff --git a/src/main/java/org/kohsuke/github/JsonRepository.java b/src/main/java/org/kohsuke/github/JsonRepository.java deleted file mode 100644 index eb8eadd315..0000000000 --- a/src/main/java/org/kohsuke/github/JsonRepository.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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; - -/** - * @author Kohsuke Kawaguchi - */ -class JsonRepository { - public GHRepository repository; - - public GHRepository wrap(GitHub root) { - repository.root = root; - return repository; - } -} diff --git a/src/main/java/org/kohsuke/github/Poster.java b/src/main/java/org/kohsuke/github/Poster.java index 29097a282c..29b024d5de 100644 --- a/src/main/java/org/kohsuke/github/Poster.java +++ b/src/main/java/org/kohsuke/github/Poster.java @@ -24,6 +24,9 @@ package org.kohsuke.github; import org.apache.commons.io.IOUtils; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.impl.WriterBasedGenerator; +import org.codehaus.jackson.node.ObjectNode; import java.io.IOException; import java.io.InputStreamReader; @@ -33,7 +36,9 @@ import java.net.HttpURLConnection; import java.net.URLEncoder; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static org.kohsuke.github.GitHub.*; @@ -43,11 +48,25 @@ */ class Poster { private final GitHub root; - private final List args = new ArrayList(); + private final List args = new ArrayList(); private boolean authenticate; private final ApiVersion v; + private static class Entry { + String key; + Object value; + + private Entry(String key, Object value) { + this.key = key; + this.value = value; + } + + public String toFormArg() throws UnsupportedEncodingException { + return URLEncoder.encode(key,"UTF-8")+'='+URLEncoder.encode(value.toString(),"UTF-8"); + } + } + Poster(GitHub root, ApiVersion v) { this.root = root; this.v = v; @@ -64,16 +83,20 @@ public Poster withCredential() { } public Poster with(String key, int value) { - return with(key,String.valueOf(value)); + return _with(key, value); + } + + public Poster with(String key, boolean value) { + return _with(key, value); } public Poster with(String key, String value) { + return _with(key, value); + } + + private Poster _with(String key, Object 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 - } + args.add(new Entry(key,value)); } return this; } @@ -112,23 +135,31 @@ public T to(String tailApiUrl, Class type, String method) throws IOExcept uc.setRequestMethod(method); - StringBuilder body = new StringBuilder(); - for (String e : args) { - if (body.length()>0) body.append('&'); - body.append(e); - } + if (v==ApiVersion.V2) { + StringBuilder body = new StringBuilder(); + for (Entry e : args) { + if (body.length()>0) body.append('&'); + body.append(e.toFormArg()); + } - OutputStreamWriter o = new OutputStreamWriter(uc.getOutputStream(), "UTF-8"); - o.write(body.toString()); - o.close(); + OutputStreamWriter o = new OutputStreamWriter(uc.getOutputStream(), "UTF-8"); + o.write(body.toString()); + o.close(); + } else { + Map json = new HashMap(); + for (Entry e : args) { + json.put(e.key, e.value); + } + MAPPER.writeValue(uc.getOutputStream(),json); + } try { InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8"); + String data = IOUtils.toString(r); if (type==null) { - String data = IOUtils.toString(r); return null; } - return MAPPER.readValue(r,type); + return MAPPER.readValue(data,type); } catch (IOException e) { root.handleApiError(e,uc); } diff --git a/src/test/java/org/kohsuke/AppTest.java b/src/test/java/org/kohsuke/AppTest.java index 0c8959e482..55d7d1c35e 100644 --- a/src/test/java/org/kohsuke/AppTest.java +++ b/src/test/java/org/kohsuke/AppTest.java @@ -42,6 +42,9 @@ public void testMembership() throws Exception { public void testApp() throws IOException { GitHub gitHub = GitHub.connect(); +// GHRepository r = gitHub.connect().getOrganization("jenkinsci").createRepository("kktest4", "Kohsuke's test", "http://kohsuke.org/", "Everyone", true); +// r.fork(); + // tryDisablingIssueTrackers(gitHub); // tryDisablingWiki(gitHub); @@ -129,10 +132,13 @@ private void testPostCommitHook(GitHub gitHub) throws IOException { System.out.println(hooks); } - private void testOrganization(GitHub gitHub) throws IOException { - GHOrganization labs = gitHub.getOrganization("HudsonLabs"); - GHTeam t = labs.getTeams().get("Core Developers"); + public void testOrganization() throws IOException { + GitHub gitHub = GitHub.connect(); + GHOrganization j = gitHub.getOrganization("jenkinsci"); + GHTeam t = j.getTeams().get("Core Developers"); + + assertNotNull(j.getRepository("jenkins")); - t.add(labs.getRepository("xyz")); +// t.add(labs.getRepository("xyz")); } }