Skip to content

Commit

Permalink
Removed v2 API usage and switched to v3.
Browse files Browse the repository at this point in the history
  • Loading branch information
kohsuke committed Jun 12, 2012
1 parent 3b5bc98 commit b5f7208
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 119 deletions.
1 change: 0 additions & 1 deletion src/main/java/org/kohsuke/github/ApiVersion.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
*/
enum ApiVersion {

V2("https://?/api/v2/json"),
V3("https://api.?");

final String templateUrl;
Expand Down
51 changes: 45 additions & 6 deletions src/main/java/org/kohsuke/github/GHIssue.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@

import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import static org.kohsuke.github.ApiVersion.V3;

/**
* Represents an issue on GitHub.
*
Expand All @@ -46,6 +49,18 @@ public class GHIssue {
private int number,votes,comments;
private int position;

/*package*/ GHIssue wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
return this;
}

/*package*/ static GHIssue[] wrap(GHIssue[] issues, GHRepository owner) {
for (GHIssue i : issues)
i.wrap(owner);
return issues;
}

/**
* Repository to which the issue belongs.
*/
Expand Down Expand Up @@ -99,31 +114,55 @@ public Date getUpdatedAt() {
* Updates the issue by adding a comment.
*/
public void comment(String message) throws IOException {
new Poster(root).withCredential().with("comment",message).to(getApiRoute("comment"));
new Poster(root, V3).withCredential().with("body",message).to(getApiRoute()+"/comments",null,"POST");
}

private void edit(String key, Object value) throws IOException {
new Poster(root,V3).withCredential()._with(key, value)
.to(getApiRoute(),null,"PATCH");
}

/**
* Closes this issue.
*/
public void close() throws IOException {
new Poster(root).withCredential().to(getApiRoute("close"));
edit("state", "closed");
}

/**
* Reopens this issue.
*/
public void reopen() throws IOException {
new Poster(root).withCredential().to(getApiRoute("reopen"));
edit("state", "open");
}

public void setTitle(String title) throws IOException {
edit("title",title);
}

public void setBody(String body) throws IOException {
edit("body",body);
}

public void assignTo(GHUser user) throws IOException {
edit("assignee",user.getLogin());
}

public void setLabels(String... labels) throws IOException {
edit("assignee",labels);
}

/**
* Obtains all the comments associated with this issue.
*/
public List<GHIssueComment> getComments() throws IOException {
return root.retrieve(getApiRoute("comments"), JsonIssueComments.class).wrap(this);
GHIssueComment[] r = root.retrieve3(getApiRoute()+"/comments", GHIssueComment[].class);
for (GHIssueComment c : r)
c.wrapUp(this);
return Arrays.asList(r);
}

private String getApiRoute(String verb) {
return "/issues/"+verb+"/"+owner.getOwnerName()+"/"+owner.getName()+"/"+number;
private String getApiRoute() {
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
}
}
5 changes: 5 additions & 0 deletions src/main/java/org/kohsuke/github/GHIssueComment.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ public class GHIssueComment {
private String body, gravatar_id, user, created_at, updated_at;
private int id;

/*package*/ GHIssueComment wrapUp(GHIssue owner) {
this.owner = owner;
return this;
}

/**
* Gets the issue to which this comment is associated.
*/
Expand Down
21 changes: 16 additions & 5 deletions src/main/java/org/kohsuke/github/GHOrganization.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,25 @@
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

import java.io.FileNotFoundException;
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 java.util.TreeMap;

import static org.kohsuke.github.ApiVersion.*;

/**
* @author Kohsuke Kawaguchi
*/
public class GHOrganization extends GHPerson {
/*package*/ GHOrganization wrapUp(GitHub root) {
return (GHOrganization)super.wrapUp(root);
}

/**
* Creates a new repository.
*
Expand All @@ -40,7 +44,12 @@ public GHRepository createRepository(String name, String description, String hom
* Teams by their names.
*/
public Map<String,GHTeam> getTeams() throws IOException {
return root.retrieveWithAuth("/organizations/"+login+"/teams",JsonTeams.class).toMap(this);
GHTeam[] teams = root.retrieveWithAuth3("/orgs/" + login + "/teams", GHTeam[].class);
Map<String,GHTeam> r = new TreeMap<String, GHTeam>();
for (GHTeam t : teams) {
r.put(t.getName(),t);
}
return r;
}

/**
Expand Down Expand Up @@ -88,11 +97,13 @@ public enum Permission { ADMIN, PUSH, PULL }
* Creates a new team and assigns the repositories.
*/
public GHTeam createTeam(String name, Permission p, Collection<GHRepository> repositories) throws IOException {
Poster post = new Poster(root).withCredential().with("team[name]", name).with("team[permission]", p.name().toLowerCase());
Poster post = new Poster(root,V3).withCredential().with("name", name).with("permission", p.name().toLowerCase());
List<String> repo_names = new ArrayList<String>();
for (GHRepository r : repositories) {
post.with("team[repo_names][]",r.getOwnerName()+'/'+r.getName());
repo_names.add(r.getName());
}
return post.to("/organizations/"+login+"/teams",JsonTeam.class).wrap(this);
post.with("repo_names",repo_names);
return post.to("/orgs/"+login+"/teams",GHTeam.class,"POST").wrapUp(this);
}

public GHTeam createTeam(String name, Permission p, GHRepository... repositories) throws IOException {
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/kohsuke/github/GHPerson.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public abstract class GHPerson {
protected String avatar_url,html_url;
protected int followers,following,public_repos,public_gists;

/*package*/ GHPerson wrapUp(GitHub root) {
this.root = root;
return this;
}

/**
* Gets the repositories this user owns.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/kohsuke/github/GHPersonSet.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.kohsuke.github;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;

Expand All @@ -16,6 +17,10 @@ public GHPersonSet(Collection<? extends T> c) {
super(c);
}

public GHPersonSet(T... c) {
super(Arrays.asList(c));
}

public GHPersonSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
}
Expand Down
101 changes: 43 additions & 58 deletions src/main/java/org/kohsuke/github/GHRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
*/
package org.kohsuke.github;

import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlButton;
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
Expand All @@ -33,8 +32,6 @@
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.AbstractSet;
import java.util.ArrayList;
Expand Down Expand Up @@ -144,7 +141,7 @@ public GHUser getOwner() throws IOException {
}

public List<GHIssue> getIssues(GHIssueState state) throws IOException {
return root.retrieve("/issues/list/" + owner.login + "/" + name + "/" + state.toString().toLowerCase(), JsonIssues.class).wrap(this);
return Arrays.asList(GHIssue.wrap(root.retrieve3("/repos/" + owner.login + "/" + name + "/issues?state=" + state.toString().toLowerCase(), GHIssue[].class), this));
}

protected String getOwnerName() {
Expand Down Expand Up @@ -216,49 +213,47 @@ public int getSize() {
*/
@WithBridgeMethods(Set.class)
public GHPersonSet<GHUser> getCollaborators() throws IOException {
GHPersonSet<GHUser> r = new GHPersonSet<GHUser>();
for (String u : root.retrieve("/repos/show/"+owner.login+"/"+name+"/collaborators",JsonCollaborators.class).collaborators)
r.add(root.getUser(u));
return r;
return new GHPersonSet<GHUser>(GHUser.wrap(root.retrieve3("/repos/"+owner.login+"/"+name+"/collaborators",GHUser[].class),root));
}

/**
* 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<String> getCollaboratorNames() throws IOException {
Set<String> r = new HashSet<String>(root.retrieve("/repos/show/"+owner.login+"/"+name+"/collaborators",JsonCollaborators.class).collaborators);
return Collections.unmodifiableSet(r);
Set<String> r = new HashSet<String>();
for (GHUser u : GHUser.wrap(root.retrieve3("/repos/"+owner.login+"/"+name+"/collaborators",GHUser[].class),root))
r.add(u.login);
return r;
}

/**
* If this repository belongs to an organization, return a set of teams.
*/
public Set<GHTeam> getTeams() throws IOException {
return Collections.unmodifiableSet(root.retrieveWithAuth("/repos/show/"+owner.login+"/"+name+"/teams",JsonTeams.class).toSet(
root.getOrganization(owner.login)));
return Collections.unmodifiableSet(new HashSet<GHTeam>(Arrays.asList(GHTeam.wrapUp(root.retrieveWithAuth3("/repos/" + owner.login + "/" + name + "/teams", GHTeam[].class), root.getOrganization(owner.login)))));
}

public void addCollaborators(GHUser... users) throws IOException {
addCollaborators(asList(users));
}

public void addCollaborators(Collection<GHUser> users) throws IOException {
modifyCollaborators(users, "/add/");
modifyCollaborators(users, "PUT");
}

public void removeCollaborators(GHUser... users) throws IOException {
removeCollaborators(asList(users));
}

public void removeCollaborators(Collection<GHUser> users) throws IOException {
modifyCollaborators(users, "/remove/");
modifyCollaborators(users, "DELETE");
}

private void modifyCollaborators(Collection<GHUser> users, String op) throws IOException {
private void modifyCollaborators(Collection<GHUser> users, String method) throws IOException {
verifyMine();
for (GHUser user : users) {
new Poster(root).withCredential().to("/repos/collaborators/"+name+ op +user.getLogin());
new Poster(root,V3).withCredential().to("/repos/"+owner.login+"/"+name+"/collaborators/"+user.getLogin(),null,method);
}
}

Expand All @@ -274,31 +269,54 @@ public void setEmailServiceHook(String address) throws IOException {
f.submit((HtmlButton) f.getElementsByTagName("button").get(0));
}

private void edit(String key, String value) throws IOException {
new Poster(root,V3).withCredential().with(key,value)
.to("/repos/" + owner.login + "/" + name,null,"PATCH");
}

/**
* Enables or disables the issue tracker for this repository.
*/
public void enableIssueTracker(boolean v) throws IOException {
new Poster(root).withCredential().with("values[has_issues]",String.valueOf(v))
.to("/repos/show/" + owner.login + "/" + name);
edit("has_issues", String.valueOf(v));
}

/**
* Enables or disables Wiki for this repository.
*/
public void enableWiki(boolean v) throws IOException {
new Poster(root).withCredential().with("values[has_wiki]",String.valueOf(v))
.to("/repos/show/" + owner.login + "/" + name);
edit("has_wiki", String.valueOf(v));
}

public void enableDownloads(boolean v) throws IOException {
edit("has_downloads",String.valueOf(v));
}

/**
* Rename this repository.
*/
public void renameTo(String name) throws IOException {
edit("name",name);
}

public void setDescription(String value) throws IOException {
edit("description",value);
}

public void setHomepage(String value) throws IOException {
edit("homepage",value);
}

/**
* Deletes this repository.
*/
public void delete() throws IOException {
Poster poster = new Poster(root).withCredential();
String url = "/repos/delete/" + owner.login +"/"+name;

DeleteToken token = poster.to(url, DeleteToken.class);
poster.with("delete_token", token.delete_token).to(url);
throw new UnsupportedOperationException(); // doesn't appear to be available in V3
// Poster poster = new Poster(root).withCredential();
// String url = "/repos/delete/" + owner.login +"/"+name;
//
// DeleteToken token = poster.to(url, DeleteToken.class);
// poster.with("delete_token", token.delete_token).to(url);
}

/**
Expand All @@ -322,39 +340,6 @@ public GHRepository forkTo(GHOrganization org) throws IOException {
return org.getRepository(name);
}

/**
* Rename this repository.
*/
public void renameTo(String newName) throws IOException {
WebClient wc = root.createWebClient();
HtmlPage pg = (HtmlPage)wc.getPage(getUrl()+"/admin");
for (HtmlForm f : pg.getForms()) {
if (!f.getActionAttribute().endsWith("/rename")) continue;
try {
f.getInputByName("name").setValueAttribute(newName);
f.submit((HtmlButton)f.getElementsByTagName("button").get(0));

// overwrite fields
final GHRepository r = getOwner().getRepository(newName);
for (Field fi : getClass().getDeclaredFields()) {
if (Modifier.isStatic(fi.getModifiers())) continue;
fi.setAccessible(true);
try {
fi.set(this,fi.get(r));
} catch (IllegalAccessException e) {
throw (IllegalAccessError)new IllegalAccessError().initCause(e);
}
}

return;
} catch (ElementNotFoundException e) {
// continue
}
}

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.
*/
Expand Down
Loading

1 comment on commit b5f7208

@ywen
Copy link

@ywen ywen commented on b5f7208 Jun 12, 2012

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome job. thanks

Please sign in to comment.