mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-11 08:21:23 +00:00
Compare commits
45 Commits
github-api
...
github-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e62776905 | ||
|
|
9ba74b945d | ||
|
|
66656ce612 | ||
|
|
73a20ad829 | ||
|
|
6fc9a546cb | ||
|
|
3f6c225948 | ||
|
|
c7e9650a39 | ||
|
|
fd28a36b74 | ||
|
|
86543c84db | ||
|
|
706cdac4cc | ||
|
|
0b69743792 | ||
|
|
dd54a00172 | ||
|
|
b5514b891a | ||
|
|
31a6eca97f | ||
|
|
8557676561 | ||
|
|
39631461ae | ||
|
|
a124d7f714 | ||
|
|
fff07bf70b | ||
|
|
53d09bb5d8 | ||
|
|
a8ecf0bef0 | ||
|
|
74b3902d5f | ||
|
|
7433ed968e | ||
|
|
ddf2d69a68 | ||
|
|
f5b34861bd | ||
|
|
f0ff31a1af | ||
|
|
8ce76fba62 | ||
|
|
a947672320 | ||
|
|
5496e2b553 | ||
|
|
2f9edc65dd | ||
|
|
6372337456 | ||
|
|
b843606ebe | ||
|
|
7cda083b31 | ||
|
|
095604d4ca | ||
|
|
7e799d02e3 | ||
|
|
7f4612f872 | ||
|
|
6f6ff56338 | ||
|
|
27701a75d9 | ||
|
|
3717d2ed32 | ||
|
|
3a9b6665ee | ||
|
|
bbc42f8898 | ||
|
|
f6aea47c2c | ||
|
|
23069ac2fc | ||
|
|
0b2fdc598b | ||
|
|
aac30b923c | ||
|
|
318caf6123 |
2
README
2
README
@@ -1,3 +1,3 @@
|
|||||||
Java API for GitHub
|
Java API for GitHub
|
||||||
|
|
||||||
See http://kohsuke.org/github-api/ for more details
|
See http://github-api.kohsuke.org/ for more details
|
||||||
|
|||||||
4
pom.xml
4
pom.xml
@@ -3,11 +3,11 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.kohsuke</groupId>
|
<groupId>org.kohsuke</groupId>
|
||||||
<artifactId>pom</artifactId>
|
<artifactId>pom</artifactId>
|
||||||
<version>1</version>
|
<version>3</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>github-api</artifactId>
|
<artifactId>github-api</artifactId>
|
||||||
<version>1.18</version>
|
<version>1.25</version>
|
||||||
<name>GitHub API for Java</name>
|
<name>GitHub API for Java</name>
|
||||||
<url>http://github-api.kohsuke.org/</url>
|
<url>http://github-api.kohsuke.org/</url>
|
||||||
<description>GitHub API for Java</description>
|
<description>GitHub API for Java</description>
|
||||||
|
|||||||
51
src/main/java/org/kohsuke/github/GHBranch.java
Normal file
51
src/main/java/org/kohsuke/github/GHBranch.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A branch in a repository.
|
||||||
|
*
|
||||||
|
* @author Yusuke Kokubo
|
||||||
|
*/
|
||||||
|
public class GHBranch {
|
||||||
|
private GitHub root;
|
||||||
|
private GHRepository owner;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private Commit commit;
|
||||||
|
|
||||||
|
public static class Commit {
|
||||||
|
String sha,url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GitHub getRoot() {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repository that this branch is in.
|
||||||
|
*/
|
||||||
|
public GHRepository getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The commit that this branch currently points to.
|
||||||
|
*/
|
||||||
|
public String getSHA1() {
|
||||||
|
return commit.sha;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Branch:" + name + " in " + owner.getUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ GHBranch wrap(GHRepository repo) {
|
||||||
|
this.owner = repo;
|
||||||
|
this.root = repo.root;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
243
src/main/java/org/kohsuke/github/GHCommit.java
Normal file
243
src/main/java/org/kohsuke/github/GHCommit.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
125
src/main/java/org/kohsuke/github/GHCommitComment.java
Normal file
125
src/main/java/org/kohsuke/github/GHCommitComment.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/main/java/org/kohsuke/github/GHKey.java
Normal file
48
src/main/java/org/kohsuke/github/GHKey.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,16 @@ public class GHMyself extends GHUser {
|
|||||||
String[] addresses = root.retrieveWithAuth3("/user/emails",String[].class);
|
String[] addresses = root.retrieveWithAuth3("/user/emails",String[].class);
|
||||||
return Collections.unmodifiableList(Arrays.asList(addresses));
|
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 {
|
// public void addEmails(Collection<String> emails) throws IOException {
|
||||||
//// new Poster(root,ApiVersion.V3).withCredential().to("/user/emails");
|
//// new Poster(root,ApiVersion.V3).withCredential().to("/user/emails");
|
||||||
|
|||||||
@@ -43,15 +43,6 @@ public class GHOrganization extends GHPerson {
|
|||||||
return root.retrieveWithAuth("/organizations/"+login+"/teams",JsonTeams.class).toMap(this);
|
return root.retrieveWithAuth("/organizations/"+login+"/teams",JsonTeams.class).toMap(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public GHRepository getRepository(String name) throws IOException {
|
|
||||||
try {
|
|
||||||
return root.retrieveWithAuth3("/repos/" + login + '/' + name, GHRepository.class).wrap(root);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publicizes the membership.
|
* Publicizes the membership.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import static org.kohsuke.github.ApiVersion.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common part of {@link GHUser} and {@link GHOrganization}.
|
* Common part of {@link GHUser} and {@link GHOrganization}.
|
||||||
*
|
*
|
||||||
@@ -31,18 +38,48 @@ public abstract class GHPerson {
|
|||||||
*/
|
*/
|
||||||
public synchronized Map<String,GHRepository> getRepositories() throws IOException {
|
public synchronized Map<String,GHRepository> getRepositories() throws IOException {
|
||||||
Map<String,GHRepository> repositories = new TreeMap<String, GHRepository>();
|
Map<String,GHRepository> repositories = new TreeMap<String, GHRepository>();
|
||||||
for (int i=1; ; i++) {
|
for (List<GHRepository> batch : iterateRepositories(100)) {
|
||||||
GHRepository[] array = root.retrieve3("/users/" + login + "/repos?per_page=100&page=" + i, GHRepository[].class);
|
for (GHRepository r : batch)
|
||||||
for (GHRepository r : array) {
|
|
||||||
r.root = root;
|
|
||||||
repositories.put(r.getName(),r);
|
repositories.put(r.getName(),r);
|
||||||
}
|
|
||||||
if (array.length==0) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Collections.unmodifiableMap(repositories);
|
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
|
* @return
|
||||||
@@ -50,7 +87,7 @@ public abstract class GHPerson {
|
|||||||
*/
|
*/
|
||||||
public GHRepository getRepository(String name) throws IOException {
|
public GHRepository getRepository(String name) throws IOException {
|
||||||
try {
|
try {
|
||||||
return root.retrieve3("/repos/" + login + '/' + name, GHRepository.class).wrap(root);
|
return root.retrieveWithAuth3("/repos/" + login + '/' + name, GHRepository.class).wrap(root);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -58,11 +95,26 @@ public abstract class GHPerson {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gravatar ID of this user, like 0cb9832a01c22c083390f3c5dcb64105
|
* Gravatar ID of this user, like 0cb9832a01c22c083390f3c5dcb64105
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
* No longer available in the v3 API.
|
||||||
*/
|
*/
|
||||||
public String getGravatarId() {
|
public String getGravatarId() {
|
||||||
return gravatar_id;
|
return gravatar_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string like 'https://secure.gravatar.com/avatar/0cb9832a01c22c083390f3c5dcb64105'
|
||||||
|
* that indicates the avatar image URL.
|
||||||
|
*/
|
||||||
|
public String getAvatarUrl() {
|
||||||
|
if (avatar_url!=null)
|
||||||
|
return avatar_url;
|
||||||
|
if (gravatar_id!=null)
|
||||||
|
return "https://secure.gravatar.com/avatar/"+gravatar_id;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the login ID of this user, like 'kohsuke'
|
* Gets the login ID of this user, like 'kohsuke'
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -68,9 +68,19 @@ public class GHRepository {
|
|||||||
private String html_url; // this is the UI
|
private String html_url; // this is the UI
|
||||||
private GHUser owner; // not fully populated. beware.
|
private GHUser owner; // not fully populated. beware.
|
||||||
private boolean has_issues, has_wiki, fork, _private, has_downloads;
|
private boolean has_issues, has_wiki, fork, _private, has_downloads;
|
||||||
private int watchers,forks,open_issues;
|
private int watchers,forks,open_issues,size;
|
||||||
private String created_at, pushed_at;
|
private String created_at, pushed_at;
|
||||||
private Map<Integer,GHMilestone> milestones = new HashMap<Integer, GHMilestone>();
|
private Map<Integer,GHMilestone> milestones = new HashMap<Integer, GHMilestone>();
|
||||||
|
|
||||||
|
private String master_branch,language;
|
||||||
|
private Map<String,GHCommit> commits = new HashMap<String, GHCommit>();
|
||||||
|
|
||||||
|
private GHRepoPermission permissions;
|
||||||
|
|
||||||
|
private static class GHRepoPermission {
|
||||||
|
boolean pull,push,admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return description;
|
return description;
|
||||||
@@ -110,6 +120,25 @@ public class GHRepository {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasPullAccess() {
|
||||||
|
return permissions!=null && permissions.pull;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPushAccess() {
|
||||||
|
return permissions!=null && permissions.push;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAdminAccess() {
|
||||||
|
return permissions!=null && permissions.admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary programming language.
|
||||||
|
*/
|
||||||
|
public String getLanguage() {
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
public GHUser getOwner() throws IOException {
|
public GHUser getOwner() throws IOException {
|
||||||
return root.getUser(owner.login); // because 'owner' isn't fully populated
|
return root.getUser(owner.login); // because 'owner' isn't fully populated
|
||||||
}
|
}
|
||||||
@@ -154,6 +183,11 @@ public class GHRepository {
|
|||||||
return open_issues;
|
return open_issues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* null if the repository was never pushed at.
|
||||||
|
*/
|
||||||
public Date getPushedAt() {
|
public Date getPushedAt() {
|
||||||
return GitHub.parseDate(pushed_at);
|
return GitHub.parseDate(pushed_at);
|
||||||
}
|
}
|
||||||
@@ -162,6 +196,19 @@ public class GHRepository {
|
|||||||
return GitHub.parseDate(created_at);
|
return GitHub.parseDate(created_at);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the primary branch you'll configure in the "Admin > Options" config page.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* This field is null until the user explicitly configures the master branch.
|
||||||
|
*/
|
||||||
|
public String getMasterBranch() {
|
||||||
|
return master_branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the collaborators on this repository.
|
* Gets the collaborators on this repository.
|
||||||
@@ -251,7 +298,7 @@ public class GHRepository {
|
|||||||
String url = "/repos/delete/" + owner.login +"/"+name;
|
String url = "/repos/delete/" + owner.login +"/"+name;
|
||||||
|
|
||||||
DeleteToken token = poster.to(url, DeleteToken.class);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -340,6 +387,51 @@ public class GHRepository {
|
|||||||
return root.retrieveWithAuth3(String.format("/repos/%s/%s/hooks/%d",owner.login,name,id),GHHook.class).wrap(this);
|
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.
|
* See https://api.github.com/hooks for possible names and their configuration scheme.
|
||||||
@@ -461,6 +553,18 @@ public class GHRepository {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets branches by {@linkplain GHBranch#getName() their names}.
|
||||||
|
*/
|
||||||
|
public Map<String,GHBranch> getBranches() throws IOException {
|
||||||
|
Map<String,GHBranch> r = new TreeMap<String,GHBranch>();
|
||||||
|
for (GHBranch p : root.retrieve3("/repos/"+owner.login+"/"+name+"/branches", GHBranch[].class)) {
|
||||||
|
p.wrap(this);
|
||||||
|
r.put(p.getName(),p);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<Integer, GHMilestone> getMilestones() throws IOException {
|
public Map<Integer, GHMilestone> getMilestones() throws IOException {
|
||||||
Map<Integer,GHMilestone> milestones = new TreeMap<Integer, GHMilestone>();
|
Map<Integer,GHMilestone> milestones = new TreeMap<Integer, GHMilestone>();
|
||||||
GHMilestone[] ms = root.retrieve3("/repos/"+owner.login+"/"+name+"/milestones", GHMilestone[].class);
|
GHMilestone[] ms = root.retrieve3("/repos/"+owner.login+"/"+name+"/milestones", GHMilestone[].class);
|
||||||
|
|||||||
@@ -44,13 +44,17 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.codehaus.jackson.JsonParseException;
|
||||||
import org.codehaus.jackson.map.DeserializationConfig.Feature;
|
import org.codehaus.jackson.map.DeserializationConfig.Feature;
|
||||||
import org.codehaus.jackson.map.ObjectMapper;
|
import org.codehaus.jackson.map.ObjectMapper;
|
||||||
import org.codehaus.jackson.map.introspect.VisibilityChecker.Std;
|
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 {
|
/*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 {
|
/*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 {
|
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
|
while (true) {// loop while API rate limit is hit
|
||||||
|
HttpURLConnection uc = setupConnection(method, withAuth, getApiURL(v, tailApiUrl));
|
||||||
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 {
|
try {
|
||||||
InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8");
|
return parse(uc,type);
|
||||||
if (type==null) {
|
|
||||||
String data = IOUtils.toString(r);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return MAPPER.readValue(r,type);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
handleApiError(e,uc);
|
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.
|
* If the error is because of the API limit, wait 10 sec and return normally.
|
||||||
* Otherwise throw an exception reporting an error.
|
* Otherwise throw an exception reporting an error.
|
||||||
@@ -231,11 +344,15 @@ public class GitHub {
|
|||||||
if (e instanceof FileNotFoundException)
|
if (e instanceof FileNotFoundException)
|
||||||
throw e; // pass through 404 Not Found to allow the caller to handle it intelligently
|
throw e; // pass through 404 Not Found to allow the caller to handle it intelligently
|
||||||
|
|
||||||
InputStream es = uc.getErrorStream();
|
InputStream es = wrapStream(uc, uc.getErrorStream());
|
||||||
if (es!=null)
|
try {
|
||||||
throw (IOException)new IOException(IOUtils.toString(es,"UTF-8")).initCause(e);
|
if (es!=null)
|
||||||
else
|
throw (IOException)new IOException(IOUtils.toString(es,"UTF-8")).initCause(e);
|
||||||
throw e;
|
else
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(es);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -245,7 +362,7 @@ public class GitHub {
|
|||||||
public GHMyself getMyself() throws IOException {
|
public GHMyself getMyself() throws IOException {
|
||||||
requireCredential();
|
requireCredential();
|
||||||
|
|
||||||
GHMyself u = retrieveWithAuth("/user/show", JsonMyself.class).user;
|
GHMyself u = retrieveWithAuth3("/user", GHMyself.class);
|
||||||
|
|
||||||
u.root = this;
|
u.root = this;
|
||||||
users.put(u.getLogin(), u);
|
users.put(u.getLogin(), u);
|
||||||
@@ -259,17 +376,9 @@ public class GitHub {
|
|||||||
public GHUser getUser(String login) throws IOException {
|
public GHUser getUser(String login) throws IOException {
|
||||||
GHUser u = users.get(login);
|
GHUser u = users.get(login);
|
||||||
if (u == null) {
|
if (u == null) {
|
||||||
|
u = retrieve3("/users/" + login, GHUser.class);
|
||||||
if (oauthAccessToken != null) {
|
u.root = this;
|
||||||
u = retrieve("/user/show/" + login, JsonUser.class).user;
|
users.put(u.getLogin(), u);
|
||||||
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;
|
return u;
|
||||||
}
|
}
|
||||||
@@ -352,7 +461,7 @@ public class GitHub {
|
|||||||
*/
|
*/
|
||||||
public boolean isCredentialValid() throws IOException {
|
public boolean isCredentialValid() throws IOException {
|
||||||
try {
|
try {
|
||||||
retrieveWithAuth("/user/show",JsonUser.class);
|
retrieveWithAuth3("/user",GHUser.class);
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return false;
|
return false;
|
||||||
@@ -380,6 +489,7 @@ public class GitHub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ static Date parseDate(String timestamp) {
|
/*package*/ static Date parseDate(String timestamp) {
|
||||||
|
if (timestamp==null) return null;
|
||||||
for (String f : TIME_FORMATS) {
|
for (String f : TIME_FORMATS) {
|
||||||
try {
|
try {
|
||||||
SimpleDateFormat df = new SimpleDateFormat(f);
|
SimpleDateFormat df = new SimpleDateFormat(f);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* The MIT License
|
* The MIT License
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010, Kohsuke Kawaguchi
|
* Copyright (c) 2011, Eric Maupin
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -21,11 +21,16 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kohsuke Kawaguchi
|
* @author Eric Maupin
|
||||||
*/
|
*/
|
||||||
class JsonUser {
|
class JsonBranch {
|
||||||
public GHUser user;
|
GHBranch branch;
|
||||||
|
|
||||||
|
GHBranch wrap(GHRepository r) {
|
||||||
|
return branch.wrap(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
40
src/main/java/org/kohsuke/github/JsonBranches.java
Normal file
40
src/main/java/org/kohsuke/github/JsonBranches.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Eric Maupin
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Maupin
|
||||||
|
*/
|
||||||
|
class JsonBranches {
|
||||||
|
List<GHBranch> branches;
|
||||||
|
|
||||||
|
public List<GHBranch> wrap(GHRepository owner) {
|
||||||
|
for (GHBranch branch : branches)
|
||||||
|
branch.wrap(owner);
|
||||||
|
return branches;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/main/java/org/kohsuke/github/PagedIterable.java
Normal file
8
src/main/java/org/kohsuke/github/PagedIterable.java
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public interface PagedIterable<T> extends Iterable<T> {
|
||||||
|
PagedIterator<T> iterator();
|
||||||
|
}
|
||||||
64
src/main/java/org/kohsuke/github/PagedIterator.java
Normal file
64
src/main/java/org/kohsuke/github/PagedIterator.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,7 +33,9 @@ import java.io.InputStreamReader;
|
|||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.ProtocolException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -86,6 +88,12 @@ class Poster {
|
|||||||
return _with(key, value);
|
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) {
|
public Poster with(String key, boolean value) {
|
||||||
return _with(key, value);
|
return _with(key, value);
|
||||||
}
|
}
|
||||||
@@ -136,7 +144,18 @@ class Poster {
|
|||||||
uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization);
|
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) {
|
if (v==ApiVersion.V2) {
|
||||||
|
|||||||
@@ -1,20 +1,31 @@
|
|||||||
package org.kohsuke;
|
package org.kohsuke;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
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.GHEvent;
|
||||||
import org.kohsuke.github.GHEventInfo;
|
import org.kohsuke.github.GHEventInfo;
|
||||||
import org.kohsuke.github.GHEventPayload;
|
import org.kohsuke.github.GHEventPayload;
|
||||||
import org.kohsuke.github.GHHook;
|
import org.kohsuke.github.GHHook;
|
||||||
|
import org.kohsuke.github.GHBranch;
|
||||||
import org.kohsuke.github.GHIssueState;
|
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;
|
||||||
import org.kohsuke.github.GHOrganization.Permission;
|
import org.kohsuke.github.GHOrganization.Permission;
|
||||||
import org.kohsuke.github.GHRepository;
|
import org.kohsuke.github.GHRepository;
|
||||||
import org.kohsuke.github.GHTeam;
|
import org.kohsuke.github.GHTeam;
|
||||||
|
import org.kohsuke.github.GHUser;
|
||||||
import org.kohsuke.github.GitHub;
|
import org.kohsuke.github.GitHub;
|
||||||
|
import org.kohsuke.github.PagedIterable;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit test for simple App.
|
* Unit test for simple App.
|
||||||
@@ -28,10 +39,39 @@ public class AppTest extends TestCase {
|
|||||||
public void testFetchPullRequest() throws Exception {
|
public void testFetchPullRequest() throws Exception {
|
||||||
GitHub gh = GitHub.connect();
|
GitHub gh = GitHub.connect();
|
||||||
GHRepository r = gh.getOrganization("jenkinsci").getRepository("jenkins");
|
GHRepository r = gh.getOrganization("jenkinsci").getRepository("jenkins");
|
||||||
|
assertEquals("master",r.getMasterBranch());
|
||||||
r.getPullRequest(1);
|
r.getPullRequest(1);
|
||||||
r.getPullRequests(GHIssueState.OPEN);
|
r.getPullRequests(GHIssueState.OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testRepoPermissions() throws Exception {
|
||||||
|
GitHub gh = GitHub.connect();
|
||||||
|
GHRepository r = gh.getOrganization("jenkinsci").getRepository("jenkins");
|
||||||
|
assertTrue(r.hasPullAccess());
|
||||||
|
|
||||||
|
r = gh.getOrganization("github").getRepository("tire");
|
||||||
|
assertFalse(r.hasAdminAccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tryGetMyself() throws Exception {
|
||||||
|
GitHub hub = GitHub.connect();
|
||||||
|
GHMyself me = hub.getMyself();
|
||||||
|
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 {
|
public void tryOrgFork() throws Exception {
|
||||||
GitHub gh = GitHub.connect();
|
GitHub gh = GitHub.connect();
|
||||||
gh.getUser("kohsuke").getRepository("rubywm").forkTo(gh.getOrganization("jenkinsci"));
|
gh.getUser("kohsuke").getRepository("rubywm").forkTo(gh.getOrganization("jenkinsci"));
|
||||||
@@ -55,6 +95,58 @@ public class AppTest extends TestCase {
|
|||||||
System.out.println(o);
|
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 {
|
public void tryHook() throws Exception {
|
||||||
GitHub gitHub = GitHub.connect();
|
GitHub gitHub = GitHub.connect();
|
||||||
GHRepository r = gitHub.getMyself().getRepository("test2");
|
GHRepository r = gitHub.getMyself().getRepository("test2");
|
||||||
@@ -171,6 +263,15 @@ public class AppTest extends TestCase {
|
|||||||
System.out.println(hooks);
|
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 {
|
public void testOrganization() throws IOException {
|
||||||
GitHub gitHub = GitHub.connect();
|
GitHub gitHub = GitHub.connect();
|
||||||
GHOrganization j = gitHub.getOrganization("jenkinsci");
|
GHOrganization j = gitHub.getOrganization("jenkinsci");
|
||||||
|
|||||||
Reference in New Issue
Block a user