Compare commits

..

27 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
6fc9a546cb [maven-release-plugin] prepare release github-api-1.24 2012-05-21 22:16:47 -07:00
Kohsuke Kawaguchi
3f6c225948 updated URL 2012-05-21 22:16:09 -07:00
Kohsuke Kawaguchi
c7e9650a39 added code to list up public keys 2012-05-21 22:15:34 -07:00
Kohsuke Kawaguchi
fd28a36b74 [maven-release-plugin] prepare for next development iteration 2012-04-24 17:22:19 -07:00
Kohsuke Kawaguchi
86543c84db [maven-release-plugin] prepare release github-api-1.23 2012-04-24 17:22:14 -07:00
Kohsuke Kawaguchi
706cdac4cc bug fix 2012-04-24 17:21:33 -07:00
Kohsuke Kawaguchi
0b69743792 added comment deletion 2012-04-24 17:17:35 -07:00
Kohsuke Kawaguchi
dd54a00172 added update 2012-04-24 17:13:48 -07:00
Kohsuke Kawaguchi
b5514b891a added a method to create a new commit comment 2012-04-24 17:06:23 -07:00
Kohsuke Kawaguchi
31a6eca97f added commit comment support 2012-04-24 16:54:05 -07:00
Kohsuke Kawaguchi
8557676561 making names consistent with GHBranch 2012-04-24 16:36:18 -07:00
Kohsuke Kawaguchi
39631461ae added list commits 2012-04-24 16:30:01 -07:00
Kohsuke Kawaguchi
a124d7f714 added some tests 2012-04-24 16:16:13 -07:00
Kohsuke Kawaguchi
fff07bf70b fixed a bug in error handling 2012-04-24 16:14:13 -07:00
Kohsuke Kawaguchi
53d09bb5d8 added object representation for GitHub commit 2012-04-24 16:11:55 -07:00
Kohsuke Kawaguchi
a8ecf0bef0 [maven-release-plugin] prepare for next development iteration 2012-04-12 11:36:57 -07:00
Kohsuke Kawaguchi
74b3902d5f [maven-release-plugin] prepare release github-api-1.22 2012-04-12 11:36:49 -07:00
Kohsuke Kawaguchi
7433ed968e monkey test code 2012-04-12 11:05:18 -07:00
Kohsuke Kawaguchi
ddf2d69a68 this method can return null 2012-04-12 11:05:04 -07:00
Kohsuke Kawaguchi
f5b34861bd avoid NPE 2012-04-12 11:01:43 -07:00
Kohsuke Kawaguchi
f0ff31a1af [maven-release-plugin] prepare for next development iteration 2012-04-11 18:16:16 -07:00
Kohsuke Kawaguchi
8ce76fba62 [maven-release-plugin] prepare release github-api-1.21 2012-04-11 18:16:10 -07:00
Kohsuke Kawaguchi
a947672320 doc improvement 2012-04-11 16:34:37 -07:00
Kohsuke Kawaguchi
5496e2b553 added pagenation support 2012-04-11 16:30:31 -07:00
Kohsuke Kawaguchi
2f9edc65dd support gzip for better performance 2012-04-11 15:45:08 -07:00
Kohsuke Kawaguchi
6372337456 Use gzip to improve transfer performance 2012-04-11 15:44:04 -07:00
Kohsuke Kawaguchi
b843606ebe [maven-release-plugin] prepare for next development iteration 2012-04-11 09:32:51 -07:00
13 changed files with 831 additions and 37 deletions

2
README
View File

@@ -1,3 +1,3 @@
Java API for GitHub
See http://kohsuke.org/github-api/ for more details
See http://github-api.kohsuke.org/ for more details

View File

@@ -7,7 +7,7 @@
</parent>
<artifactId>github-api</artifactId>
<version>1.20</version>
<version>1.24</version>
<name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description>

View File

@@ -0,0 +1,243 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.kohsuke.github.ApiVersion.V3;
/**
* A commit in a repository.
*
* @author Kohsuke Kawaguchi
* @see GHRepository#getCommit(String)
* @see GHCommitComment#getCommit()
*/
public class GHCommit {
private GHRepository owner;
public static class Stats {
int total,additions,deletions;
}
/**
* A file that was modified.
*/
public static class File {
String status;
int changes,additions,deletions;
String raw_url, blob_url, filename, sha, patch;
/**
* Number of lines added + removed.
*/
public int getLinesChanged() {
return changes;
}
/**
* Number of lines added.
*/
public int getLinesAdded() {
return additions;
}
/**
* Number of lines removed.
*/
public int getLinesDeleted() {
return deletions;
}
/**
* "modified", "added", or "deleted"
*/
public String getStatus() {
return status;
}
/**
* Just the base name and the extension without any directory name.
*/
public String getFileName() {
return filename;
}
/**
* The actual change.
*/
public String getPatch() {
return patch;
}
/**
* URL like 'https://raw.github.com/jenkinsci/jenkins/4eb17c197dfdcf8ef7ff87eb160f24f6a20b7f0e/core/pom.xml'
* that resolves to the actual content of the file.
*/
public URL getRawUrl() {
return GitHub.parseURL(raw_url);
}
/**
* URL like 'https://github.com/jenkinsci/jenkins/blob/1182e2ebb1734d0653142bd422ad33c21437f7cf/core/pom.xml'
* that resolves to the HTML page that describes this file.
*/
public URL getBlobUrl() {
return GitHub.parseURL(blob_url);
}
/**
* [0-9a-f]{40} SHA1 checksum.
*/
public String getSha() {
return sha;
}
}
public static class Parent {
String url,sha;
}
static class User {
// TODO: what if someone who doesn't have an account on GitHub makes a commit?
String url,avatar_url,login,gravatar_id;
int id;
}
String url,sha;
List<File> files;
Stats stats;
List<Parent> parents;
User author,committer;
/**
* The repository that contains the commit.
*/
public GHRepository getOwner() {
return owner;
}
/**
* Number of lines added + removed.
*/
public int getLinesChanged() {
return stats.total;
}
/**
* Number of lines added.
*/
public int getLinesAdded() {
return stats.additions;
}
/**
* Number of lines removed.
*/
public int getLinesDeleted() {
return stats.deletions;
}
/**
* [0-9a-f]{40} SHA1 checksum.
*/
public String getSHA1() {
return sha;
}
/**
* List of files changed/added/removed in this commit.
*
* @return
* Can be empty but never null.
*/
public List<File> getFiles() {
return files!=null ? Collections.unmodifiableList(files) : Collections.<File>emptyList();
}
/**
* Returns the SHA1 of parent commit objects.
*/
public List<String> getParentSHA1s() {
if (parents==null) return Collections.emptyList();
return new AbstractList<String>() {
@Override
public String get(int index) {
return parents.get(index).sha;
}
@Override
public int size() {
return parents.size();
}
};
}
/**
* Resolves the parent commit objects and return them.
*/
public List<GHCommit> getParents() throws IOException {
List<GHCommit> r = new ArrayList<GHCommit>();
for (String sha1 : getParentSHA1s())
r.add(owner.getCommit(sha1));
return r;
}
public GHUser getAuthor() throws IOException {
return resolveUser(author);
}
public GHUser getCommitter() throws IOException {
return resolveUser(committer);
}
private GHUser resolveUser(User author) throws IOException {
if (author==null || author.login==null) return null;
return owner.root.getUser(author.login);
}
/**
* Lists up all the commit comments in this repository.
*/
public PagedIterable<GHCommitComment> listComments() {
return new PagedIterable<GHCommitComment>() {
public PagedIterator<GHCommitComment> iterator() {
return new PagedIterator<GHCommitComment>(owner.root.retrievePaged(String.format("/repos/%s/%s/commits/%s/comments",owner.getOwnerName(),owner.getName(),sha),GHCommitComment[].class,false,V3)) {
@Override
protected void wrapUp(GHCommitComment[] page) {
for (GHCommitComment c : page)
c.wrap(owner);
}
};
}
};
}
/**
* Creates a commit comment.
*
* I'm not sure how path/line/position parameters interact with each other.
*/
public GHCommitComment createComment(String body, String path, Integer line, Integer position) throws IOException {
GHCommitComment r = new Poster(owner.root,V3)
.with("body",body)
.with("path",path)
.with("line",line)
.with("position",position)
.withCredential()
.to(String.format("/repos/%s/%s/commits/%s/comments",owner.getOwnerName(),owner.getName(),sha),GHCommitComment.class);
return r.wrap(owner);
}
public GHCommitComment createComment(String body) throws IOException {
return createComment(body,null,null,null);
}
GHCommit wrapUp(GHRepository owner) {
this.owner = owner;
return this;
}
}

View File

@@ -0,0 +1,125 @@
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import static org.kohsuke.github.ApiVersion.V3;
/**
* A comment attached to a commit (or a specific line in a specific file of a commit.)
*
* @author Kohsuke Kawaguchi
* @see GHRepository#listCommitComments()
* @see GHCommit#listComments()
* @see GHCommit#createComment(String, String, Integer, Integer)
*/
public class GHCommitComment {
private GHRepository owner;
String updated_at, created_at;
String body, url, html_url, commit_id;
Integer line;
int id;
String path;
User user;
static class User {
// TODO: what if someone who doesn't have an account on GitHub makes a commit?
String url,avatar_url,login,gravatar_id;
int id;
}
public GHRepository getOwner() {
return owner;
}
public Date getCreatedAt() {
return GitHub.parseDate(created_at);
}
public Date getUpdatedAt() {
return GitHub.parseDate(updated_at);
}
/**
* URL like 'https://github.com/kohsuke/sandbox-ant/commit/8ae38db0ea5837313ab5f39d43a6f73de3bd9000#commitcomment-1252827' to
* show this commit comment in a browser.
*/
public URL getHtmlUrl() {
return GitHub.parseURL(html_url);
}
public String getSHA1() {
return commit_id;
}
/**
* Commit comment in the GitHub flavored markdown format.
*/
public String getBody() {
return body;
}
/**
* A commit comment can be on a specific line of a specific file, if so, this field points to a file.
* Otherwise null.
*/
public String getPath() {
return path;
}
/**
* A commit comment can be on a specific line of a specific file, if so, this field points to the line number in the file.
* Otherwise -1.
*/
public int getLine() {
return line!=null ? line : -1;
}
public int getId() {
return id;
}
/**
* Gets the user who put this comment.
*/
public GHUser getUser() throws IOException {
return owner.root.getUser(user.login);
}
/**
* Gets the commit to which this comment is associated with.
*/
public GHCommit getCommit() throws IOException {
return getOwner().getCommit(getSHA1());
}
/**
* Updates the body of the commit message.
*/
public void update(String body) throws IOException {
GHCommitComment r = new Poster(owner.root,V3)
.with("body",body)
.withCredential()
.to(getApiTail(),GHCommitComment.class,"PATCH");
this.body = body;
}
/**
* Deletes this comment.
*/
public void delete() throws IOException {
new Poster(owner.root,V3).withCredential().to(getApiTail(),null,"DELETE");
}
private String getApiTail() {
return String.format("/repos/%s/%s/comments/%s",owner.getOwnerName(),owner.getName(),id);
}
GHCommitComment wrap(GHRepository owner) {
this.owner = owner;
return this;
}
}

View File

@@ -0,0 +1,48 @@
package org.kohsuke.github;
import org.apache.commons.lang.builder.ToStringBuilder;
/**
* SSH public key.
*
* @author Kohsuke Kawaguchi
*/
public class GHKey {
/*package almost final*/ GitHub root;
private String url, key, title;
private boolean verified;
private int id;
public int getId() {
return id;
}
public String getKey() {
return key;
}
public String getTitle() {
return title;
}
/**
* Something like "https://api.github.com/user/keys/73593"
*/
public String getUrl() {
return url;
}
public boolean isVerified() {
return verified;
}
/*package*/ GHKey wrap(GitHub root) {
this.root = root;
return this;
}
public String toString() {
return new ToStringBuilder(this).append("title",title).append("id",id).append("key",key).toString();
}
}

View File

@@ -26,6 +26,16 @@ public class GHMyself extends GHUser {
String[] addresses = root.retrieveWithAuth3("/user/emails",String[].class);
return Collections.unmodifiableList(Arrays.asList(addresses));
}
/**
* Returns the read-only list of all the pulic keys of the current user.
*
* @return
* Always non-null.
*/
public List<GHKey> getPublicKeys() throws IOException {
return Collections.unmodifiableList(Arrays.asList(root.retrieveWithAuth3("/user/keys",GHKey[].class)));
}
// public void addEmails(Collection<String> emails) throws IOException {
//// new Poster(root,ApiVersion.V3).withCredential().to("/user/emails");

View File

@@ -1,11 +1,18 @@
package org.kohsuke.github;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import static org.kohsuke.github.ApiVersion.*;
/**
* Common part of {@link GHUser} and {@link GHOrganization}.
*
@@ -31,18 +38,48 @@ public abstract class GHPerson {
*/
public synchronized Map<String,GHRepository> getRepositories() throws IOException {
Map<String,GHRepository> repositories = new TreeMap<String, GHRepository>();
for (int i=1; ; i++) {
GHRepository[] array = root.retrieve3("/users/" + login + "/repos?per_page=100&page=" + i, GHRepository[].class);
for (GHRepository r : array) {
r.root = root;
for (List<GHRepository> batch : iterateRepositories(100)) {
for (GHRepository r : batch)
repositories.put(r.getName(),r);
}
if (array.length==0) break;
}
return Collections.unmodifiableMap(repositories);
}
/**
* Loads repository list in a pagenated fashion.
*
* <p>
* For a person with a lot of repositories, GitHub returns the list of repositories in a pagenated fashion.
* Unlike {@link #getRepositories()}, this method allows the caller to start processing data as it arrives.
*
* Every {@link Iterator#next()} call results in I/O. Exceptions that occur during the processing is wrapped
* into {@link Error}.
*/
public synchronized Iterable<List<GHRepository>> iterateRepositories(final int pageSize) {
return new Iterable<List<GHRepository>>() {
public Iterator<List<GHRepository>> iterator() {
final Iterator<GHRepository[]> pager = root.retrievePaged("/users/" + login + "/repos?per_page="+pageSize,GHRepository[].class,false, V3);
return new Iterator<List<GHRepository>>() {
public boolean hasNext() {
return pager.hasNext();
}
public List<GHRepository> next() {
GHRepository[] batch = pager.next();
for (GHRepository r : batch)
r.root = root;
return Arrays.asList(batch);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
/**
*
* @return

View File

@@ -73,6 +73,7 @@ public class GHRepository {
private Map<Integer,GHMilestone> milestones = new HashMap<Integer, GHMilestone>();
private String master_branch;
private Map<String,GHCommit> commits = new HashMap<String, GHCommit>();
public String getDescription() {
return description;
@@ -156,6 +157,11 @@ public class GHRepository {
return open_issues;
}
/**
*
* @return
* null if the repository was never pushed at.
*/
public Date getPushedAt() {
return GitHub.parseDate(pushed_at);
}
@@ -266,7 +272,7 @@ public class GHRepository {
String url = "/repos/delete/" + owner.login +"/"+name;
DeleteToken token = poster.to(url, DeleteToken.class);
poster.with("delete_token",token.delete_token).to(url);
poster.with("delete_token", token.delete_token).to(url);
}
/**
@@ -355,6 +361,51 @@ public class GHRepository {
return root.retrieveWithAuth3(String.format("/repos/%s/%s/hooks/%d",owner.login,name,id),GHHook.class).wrap(this);
}
/**
* Gets a commit object in this repository.
*/
public GHCommit getCommit(String sha1) throws IOException {
GHCommit c = commits.get(sha1);
if (c==null) {
c = root.retrieve3(String.format("/repos/%s/%s/commits/%s",owner.login,name,sha1),GHCommit.class).wrapUp(this);
commits.put(sha1,c);
}
return c;
}
/**
* Lists all the commits.
*/
public PagedIterable<GHCommit> listCommits() {
return new PagedIterable<GHCommit>() {
public PagedIterator<GHCommit> iterator() {
return new PagedIterator<GHCommit>(root.retrievePaged(String.format("/repos/%s/%s/commits",owner.login,name),GHCommit[].class,false,V3)) {
protected void wrapUp(GHCommit[] page) {
for (GHCommit c : page)
c.wrapUp(GHRepository.this);
}
};
}
};
}
/**
* Lists up all the commit comments in this repository.
*/
public PagedIterable<GHCommitComment> listCommitComments() {
return new PagedIterable<GHCommitComment>() {
public PagedIterator<GHCommitComment> iterator() {
return new PagedIterator<GHCommitComment>(root.retrievePaged(String.format("/repos/%s/%s/comments",owner.login,name),GHCommitComment[].class,false,V3)) {
@Override
protected void wrapUp(GHCommitComment[] page) {
for (GHCommitComment c : page)
c.wrap(GHRepository.this);
}
};
}
};
}
/**
*
* See https://api.github.com/hooks for possible names and their configuration scheme.

View File

@@ -44,13 +44,17 @@ import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.TimeZone;
import java.util.zip.GZIPInputStream;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import org.apache.commons.io.IOUtils;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.DeserializationConfig.Feature;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.introspect.VisibilityChecker.Std;
@@ -170,7 +174,7 @@ public class GitHub {
}
/*package*/ <T> T retrieveWithAuth(String tailApiUrl, Class<T> type) throws IOException {
return retrieveWithAuth(tailApiUrl,type,"GET");
return retrieveWithAuth(tailApiUrl, type, "GET");
}
/*package*/ <T> T retrieveWithAuth3(String tailApiUrl, Class<T> type) throws IOException {
@@ -187,32 +191,141 @@ public class GitHub {
private <T> T _retrieve(String tailApiUrl, Class<T> type, String method, boolean withAuth, ApiVersion v) throws IOException {
while (true) {// loop while API rate limit is hit
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();
}
HttpURLConnection uc = setupConnection(method, withAuth, getApiURL(v, tailApiUrl));
try {
InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8");
if (type==null) {
String data = IOUtils.toString(r);
return null;
}
return MAPPER.readValue(r,type);
return parse(uc,type);
} catch (IOException e) {
handleApiError(e,uc);
}
}
}
/**
* Loads pagenated resources.
*
* Every iterator call reports a new batch.
*/
/*package*/ <T> Iterator<T> retrievePaged(final String tailApiUrl, final Class<T> type, final boolean withAuth, final ApiVersion v) {
return new Iterator<T>() {
/**
* The next batch to be returned from {@link #next()}.
*/
T next;
/**
* URL of the next resource to be retrieved, or null if no more data is available.
*/
URL url;
{
try {
url = getApiURL(v, tailApiUrl);
} catch (IOException e) {
throw new Error(e);
}
}
public boolean hasNext() {
fetch();
return next!=null;
}
public T next() {
fetch();
T r = next;
if (r==null) throw new NoSuchElementException();
next = null;
return r;
}
public void remove() {
throw new UnsupportedOperationException();
}
private void fetch() {
if (next!=null) return; // already fetched
if (url==null) return; // no more data to fetch
try {
while (true) {// loop while API rate limit is hit
HttpURLConnection uc = setupConnection("GET", withAuth, url);
try {
next = parse(uc,type);
assert next!=null;
findNextURL(uc);
return;
} catch (IOException e) {
handleApiError(e,uc);
}
}
} catch (IOException e) {
throw new Error(e);
}
}
/**
* Locate the next page from the pagination "Link" tag.
*/
private void findNextURL(HttpURLConnection uc) throws MalformedURLException {
url = null; // start defensively
String link = uc.getHeaderField("Link");
if (link==null) return;
for (String token : link.split(", ")) {
if (token.endsWith("rel=\"next\"")) {
// found the next page. This should look something like
// <https://api.github.com/repos?page=3&per_page=100>; rel="next"
int idx = token.indexOf('>');
url = new URL(token.substring(1,idx));
return;
}
}
// no more "next" link. we are done.
}
};
}
private HttpURLConnection setupConnection(String method, boolean withAuth, URL url) throws IOException {
HttpURLConnection uc = (HttpURLConnection) url.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();
}
uc.setRequestProperty("Accept-Encoding", "gzip");
return uc;
}
private <T> T parse(HttpURLConnection uc, Class<T> type) throws IOException {
InputStreamReader r = null;
try {
r = new InputStreamReader(wrapStream(uc, uc.getInputStream()), "UTF-8");
if (type==null) {
String data = IOUtils.toString(r);
return null;
}
return MAPPER.readValue(r,type);
} finally {
IOUtils.closeQuietly(r);
}
}
/**
* Handles the "Content-Encoding" header.
*/
private InputStream wrapStream(HttpURLConnection uc, InputStream in) throws IOException {
String encoding = uc.getContentEncoding();
if (encoding==null || in==null) return in;
if (encoding.equals("gzip")) return new GZIPInputStream(in);
throw new UnsupportedOperationException("Unexpected Content-Encoding: "+encoding);
}
/**
* If the error is because of the API limit, wait 10 sec and return normally.
* Otherwise throw an exception reporting an error.
@@ -231,11 +344,15 @@ public class GitHub {
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;
InputStream es = wrapStream(uc, uc.getErrorStream());
try {
if (es!=null)
throw (IOException)new IOException(IOUtils.toString(es,"UTF-8")).initCause(e);
else
throw e;
} finally {
IOUtils.closeQuietly(es);
}
}
/**
@@ -372,6 +489,7 @@ public class GitHub {
}
/*package*/ static Date parseDate(String timestamp) {
if (timestamp==null) return null;
for (String f : TIME_FORMATS) {
try {
SimpleDateFormat df = new SimpleDateFormat(f);

View File

@@ -0,0 +1,8 @@
package org.kohsuke.github;
/**
* @author Kohsuke Kawaguchi
*/
public interface PagedIterable<T> extends Iterable<T> {
PagedIterator<T> iterator();
}

View File

@@ -0,0 +1,64 @@
package org.kohsuke.github;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* Iterator over a pagenated data source.
*
* Aside from the normal iterator operation, this method exposes {@link #nextPage()}
* that allows the caller to retrieve items per page.
*
* @author Kohsuke Kawaguchi
*/
public abstract class PagedIterator<T> implements Iterator<T> {
private final Iterator<T[]> base;
/**
* Current batch that we retrieved but haven't returned to the caller.
*/
private T[] current;
private int pos;
/*package*/ PagedIterator(Iterator<T[]> base) {
this.base = base;
}
protected abstract void wrapUp(T[] page);
public boolean hasNext() {
return (current!=null && pos<current.length) || base.hasNext();
}
public T next() {
fetch();
return current[pos++];
}
private void fetch() {
while (current==null || current.length<=pos) {
current = base.next();
wrapUp(current);
pos = 0;
}
// invariant at the end: there's some data to retrieve
}
public void remove() {
throw new UnsupportedOperationException();
}
/**
* Gets the next page worth of data.
*/
public List<T> nextPage() {
fetch();
List<T> r = Arrays.asList(current);
r = r.subList(pos,r.size());
current = null;
pos = 0;
return r;
}
}

View File

@@ -33,7 +33,9 @@ import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
@@ -86,6 +88,12 @@ class Poster {
return _with(key, value);
}
public Poster with(String key, Integer value) {
if (value!=null)
_with(key, value.intValue());
return this;
}
public Poster with(String key, boolean value) {
return _with(key, value);
}
@@ -136,7 +144,18 @@ class Poster {
uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization);
}
}
uc.setRequestMethod(method);
try {
uc.setRequestMethod(method);
} catch (ProtocolException e) {
// JDK only allows one of the fixed set of verbs. Try to override that
try {
Field $method = HttpURLConnection.class.getDeclaredField("method");
$method.setAccessible(true);
$method.set(uc,method);
} catch (Exception x) {
throw (IOException)new IOException("Failed to set the custom verb").initCause(x);
}
}
if (v==ApiVersion.V2) {

View File

@@ -1,12 +1,16 @@
package org.kohsuke;
import junit.framework.TestCase;
import org.kohsuke.github.GHCommit;
import org.kohsuke.github.GHCommit.File;
import org.kohsuke.github.GHCommitComment;
import org.kohsuke.github.GHEvent;
import org.kohsuke.github.GHEventInfo;
import org.kohsuke.github.GHEventPayload;
import org.kohsuke.github.GHHook;
import org.kohsuke.github.GHBranch;
import org.kohsuke.github.GHIssueState;
import org.kohsuke.github.GHKey;
import org.kohsuke.github.GHMyself;
import org.kohsuke.github.GHOrganization;
import org.kohsuke.github.GHOrganization.Permission;
@@ -14,9 +18,11 @@ import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GHTeam;
import org.kohsuke.github.GHUser;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.PagedIterable;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.List;
@@ -44,6 +50,17 @@ public class AppTest extends TestCase {
System.out.println(me);
GHUser u = hub.getUser("kohsuke2");
System.out.println(u);
for (List<GHRepository> lst : me.iterateRepositories(100)) {
for (GHRepository r : lst) {
System.out.println(r.getPushedAt());
}
}
}
public void testPublicKeys() throws Exception {
GitHub gh = GitHub.connect();
List<GHKey> keys = gh.getMyself().getPublicKeys();
System.out.println(keys);
}
public void tryOrgFork() throws Exception {
@@ -69,13 +86,58 @@ public class AppTest extends TestCase {
System.out.println(o);
}
public void testCommit() throws Exception {
GitHub gitHub = GitHub.connect();
GHCommit commit = gitHub.getUser("jenkinsci").getRepository("jenkins").getCommit("08c1c9970af4d609ae754fbe803e06186e3206f7");
System.out.println(commit);
assertEquals(1, commit.getParents().size());
assertEquals(1,commit.getFiles().size());
File f = commit.getFiles().get(0);
assertEquals(48,f.getLinesChanged());
assertEquals("modified",f.getStatus());
assertEquals("changelog.html",f.getFileName());
}
public void testListCommits() throws Exception {
GitHub gitHub = GitHub.connect();
List<String> sha1 = new ArrayList<String>();
for (GHCommit c : gitHub.getUser("kohsuke").getRepository("empty-commit").listCommits()) {
System.out.println(c.getSHA1());
sha1.add(c.getSHA1());
}
assertEquals("fdfad6be4db6f96faea1f153fb447b479a7a9cb7",sha1.get(0));
assertEquals(1,sha1.size());
}
public void testBranches() throws Exception {
GitHub gitHub = GitHub.connect();
Map<String,GHBranch> b =
gitHub.getUser("jenkinsci").getRepository("jenkins").getBranches();
System.out.println(b);
}
public void testCommitComment() throws Exception {
GitHub gitHub = GitHub.connect();
GHRepository r = gitHub.getUser("jenkinsci").getRepository("jenkins");
PagedIterable<GHCommitComment> comments = r.listCommitComments();
List<GHCommitComment> batch = comments.iterator().nextPage();
for (GHCommitComment comment : batch) {
System.out.println(comment.getBody());
assertSame(comment.getOwner(), r);
}
}
public void tryCreateCommitComment() throws Exception {
GitHub gitHub = GitHub.connect();
GHCommit commit = gitHub.getUser("kohsuke").getRepository("sandbox-ant").getCommit("8ae38db0ea5837313ab5f39d43a6f73de3bd9000");
GHCommitComment c = commit.createComment("[testing](http://kohsuse.org/)");
System.out.println(c);
c.update("updated text");
System.out.println(c);
c.delete();
}
public void tryHook() throws Exception {
GitHub gitHub = GitHub.connect();
GHRepository r = gitHub.getMyself().getRepository("test2");
@@ -192,6 +254,15 @@ public class AppTest extends TestCase {
System.out.println(hooks);
}
public void testOrgRepositories() throws IOException {
GitHub gitHub = GitHub.connect();
GHOrganization j = gitHub.getOrganization("jenkinsci");
long start = System.currentTimeMillis();
Map<String, GHRepository> repos = j.getRepositories();
long end = System.currentTimeMillis();
System.out.printf("%d repositories in %dms\n",repos.size(),end-start);
}
public void testOrganization() throws IOException {
GitHub gitHub = GitHub.connect();
GHOrganization j = gitHub.getOrganization("jenkinsci");