mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-11 00:11:25 +00:00
Compare commits
103 Commits
github-api
...
github-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63dd1330e9 | ||
|
|
4411650c5a | ||
|
|
1c15751949 | ||
|
|
82acf4f107 | ||
|
|
5525ae8921 | ||
|
|
b5f7208b0d | ||
|
|
3b5bc98053 | ||
|
|
3a9ade667a | ||
|
|
057c32d410 | ||
|
|
33657c9c92 | ||
|
|
4c199256a5 | ||
|
|
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 | ||
|
|
6898893ffb | ||
|
|
cb34f4e91f | ||
|
|
0da4b320f1 | ||
|
|
facb5bd13e | ||
|
|
22bc768868 | ||
|
|
a9b6f7bc9c | ||
|
|
830fb7192d | ||
|
|
e8ff7a4ae8 | ||
|
|
dac2a56671 | ||
|
|
2718cf5ccb | ||
|
|
202a5d435c | ||
|
|
58af8d0e90 | ||
|
|
b950be9626 | ||
|
|
222277ae0a | ||
|
|
fbcf3a17b4 | ||
|
|
748cbdd03b | ||
|
|
57b26b6a21 | ||
|
|
a4026d46ce | ||
|
|
696daf7387 | ||
|
|
4a507a5625 | ||
|
|
ac1dd9a0ee | ||
|
|
44f1038516 | ||
|
|
3e2c9f86da | ||
|
|
44cc3c8556 | ||
|
|
bf65a746b0 | ||
|
|
4a4a469ca4 | ||
|
|
46b2e5dd32 | ||
|
|
8a7adf876f | ||
|
|
c16ebe4fec | ||
|
|
4c61f79e5c | ||
|
|
646dc17e5d | ||
|
|
7977471458 | ||
|
|
9ac2ad957b | ||
|
|
7fead8171d | ||
|
|
70bc5c59e2 | ||
|
|
06ef6e841d | ||
|
|
2bee34da59 | ||
|
|
74415b14be | ||
|
|
1e9a68a16b | ||
|
|
7a3127ed65 | ||
|
|
11b0ac19fd | ||
|
|
c8eab1f53e | ||
|
|
1c613c5f07 | ||
|
|
b8a63541e8 | ||
|
|
f25083fde1 | ||
|
|
c86c974400 | ||
|
|
0ad419b026 |
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
|
||||||
|
|||||||
33
pom.xml
33
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.14</version>
|
<version>1.27</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>
|
||||||
@@ -25,6 +25,23 @@
|
|||||||
</site>
|
</site>
|
||||||
</distributionManagement>
|
</distributionManagement>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.infradna.tool</groupId>
|
||||||
|
<artifactId>bridge-method-injector</artifactId>
|
||||||
|
<version>1.2</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>process</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jvnet.hudson</groupId>
|
<groupId>org.jvnet.hudson</groupId>
|
||||||
@@ -54,6 +71,18 @@
|
|||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
<version>1.4</version>
|
<version>1.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.infradna.tool</groupId>
|
||||||
|
<artifactId>bridge-method-annotation</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.kohsuke.stapler</groupId>
|
||||||
|
<artifactId>stapler-jetty</artifactId>
|
||||||
|
<version>1.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<reporting>
|
<reporting>
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Different API versions.
|
|
||||||
*
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
enum ApiVersion {
|
|
||||||
V2("https://github.com/api/v2/json"),
|
|
||||||
V3("https://api.github.com");
|
|
||||||
|
|
||||||
final String url;
|
|
||||||
|
|
||||||
ApiVersion(String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
241
src/main/java/org/kohsuke/github/GHCommit.java
Normal file
241
src/main/java/org/kohsuke/github/GHCommit.java
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)) {
|
||||||
|
@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)
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
123
src/main/java/org/kohsuke/github/GHCommitComment.java
Normal file
123
src/main/java/org/kohsuke/github/GHCommitComment.java
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
.with("body",body)
|
||||||
|
.withCredential()
|
||||||
|
.to(getApiTail(),GHCommitComment.class,"PATCH");
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes this comment.
|
||||||
|
*/
|
||||||
|
public void delete() throws IOException {
|
||||||
|
new Poster(owner.root).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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ package org.kohsuke.github;
|
|||||||
public class GHCommitPointer {
|
public class GHCommitPointer {
|
||||||
private String ref, sha, label;
|
private String ref, sha, label;
|
||||||
private GHUser user;
|
private GHUser user;
|
||||||
private GHRepository repository;
|
private GHRepository repository/*V2*/,repo/*V3*/;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This points to the user who owns
|
* This points to the user who owns
|
||||||
@@ -45,11 +45,11 @@ public class GHCommitPointer {
|
|||||||
* The repository that contains the commit.
|
* The repository that contains the commit.
|
||||||
*/
|
*/
|
||||||
public GHRepository getRepository() {
|
public GHRepository getRepository() {
|
||||||
return repository;
|
return repo!=null ? repo : repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Named ref to the commit.
|
* Named ref to the commit. This appears to be a "short ref" that doesn't include "refs/heads/" portion.
|
||||||
*/
|
*/
|
||||||
public String getRef() {
|
public String getRef() {
|
||||||
return ref;
|
return ref;
|
||||||
@@ -68,4 +68,10 @@ public class GHCommitPointer {
|
|||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wrapUp(GitHub root) {
|
||||||
|
if (user!=null) user.root = root;
|
||||||
|
if (repo!=null) repo.wrap(root);
|
||||||
|
if (repository!=null) repository.wrap(root);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
src/main/java/org/kohsuke/github/GHEvent.java
Normal file
28
src/main/java/org/kohsuke/github/GHEvent.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook event type.
|
||||||
|
*
|
||||||
|
* See http://developer.github.com/v3/events/types/
|
||||||
|
*
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public enum GHEvent {
|
||||||
|
COMMIT_COMMENT,
|
||||||
|
CREATE,
|
||||||
|
DELETE,
|
||||||
|
DOWNLOAD,
|
||||||
|
FOLLOW,
|
||||||
|
FORK,
|
||||||
|
FORK_APPLY,
|
||||||
|
GIST,
|
||||||
|
GOLLUM,
|
||||||
|
ISSUE_COMMENT,
|
||||||
|
ISSUES,
|
||||||
|
MEMBER,
|
||||||
|
PUBLIC,
|
||||||
|
PULL_REQUEST,
|
||||||
|
PUSH,
|
||||||
|
TEAM_ADD,
|
||||||
|
WATCH
|
||||||
|
}
|
||||||
82
src/main/java/org/kohsuke/github/GHEventInfo.java
Normal file
82
src/main/java/org/kohsuke/github/GHEventInfo.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.node.ObjectNode;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an event.
|
||||||
|
*
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public class GHEventInfo {
|
||||||
|
private GitHub root;
|
||||||
|
|
||||||
|
// we don't want to expose Jackson dependency to the user. This needs databinding
|
||||||
|
private ObjectNode payload;
|
||||||
|
|
||||||
|
private String created_at;
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
// these are all shallow objects
|
||||||
|
private GHEventRepository repo;
|
||||||
|
private GHUser actor;
|
||||||
|
private GHOrganization org;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inside the event JSON model, GitHub uses a slightly different format.
|
||||||
|
*/
|
||||||
|
public static class GHEventRepository {
|
||||||
|
private int id;
|
||||||
|
private String url; // repository API URL
|
||||||
|
private String name; // owner/repo
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHEvent getType() {
|
||||||
|
String t = type;
|
||||||
|
if (t.endsWith("Event")) t=t.substring(0,t.length()-5);
|
||||||
|
for (GHEvent e : GHEvent.values()) {
|
||||||
|
if (e.name().replace("_","").equalsIgnoreCase(t))
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
return null; // unknown event type
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ GHEventInfo wrapUp(GitHub root) {
|
||||||
|
this.root = root;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return GitHub.parseDate(created_at);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repository where the change was made.
|
||||||
|
*/
|
||||||
|
public GHRepository getRepository() throws IOException {
|
||||||
|
return root.getRepository(repo.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHUser getActor() throws IOException {
|
||||||
|
return root.getUser(actor.getLogin());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHOrganization getOrganization() throws IOException {
|
||||||
|
return (org==null || org.getLogin()==null) ? null : root.getOrganization(org.getLogin());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the payload.
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* Specify one of the {@link GHEventPayload} subtype that defines a type-safe access to the payload.
|
||||||
|
* This must match the {@linkplain #getType() event type}.
|
||||||
|
*/
|
||||||
|
public <T extends GHEventPayload> T getPayload(Class<T> type) throws IOException {
|
||||||
|
T v = GitHub.MAPPER.readValue(payload.traverse(), type);
|
||||||
|
v.wrapUp(root);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/main/java/org/kohsuke/github/GHEventPayload.java
Normal file
46
src/main/java/org/kohsuke/github/GHEventPayload.java
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.Reader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base type for types used in databinding of the event payload.
|
||||||
|
*
|
||||||
|
* @see GitHub#parseEventPayload(Reader, Class)
|
||||||
|
* @see GHEventInfo#getPayload(Class)
|
||||||
|
*/
|
||||||
|
public abstract class GHEventPayload {
|
||||||
|
protected GitHub root;
|
||||||
|
|
||||||
|
/*package*/ GHEventPayload() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ void wrapUp(GitHub root) {
|
||||||
|
this.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PullRequest extends GHEventPayload {
|
||||||
|
private String action;
|
||||||
|
private int number;
|
||||||
|
GHPullRequest pull_request;
|
||||||
|
|
||||||
|
public String getAction() {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumber() {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHPullRequest getPullRequest() {
|
||||||
|
pull_request.root = root;
|
||||||
|
return pull_request;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void wrapUp(GitHub root) {
|
||||||
|
super.wrapUp(root);
|
||||||
|
pull_request.wrapUp(root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
60
src/main/java/org/kohsuke/github/GHHook.java
Normal file
60
src/main/java/org/kohsuke/github/GHHook.java
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public final class GHHook {
|
||||||
|
/**
|
||||||
|
* Repository that the hook belongs to.
|
||||||
|
*/
|
||||||
|
/*package*/ transient GHRepository repository;
|
||||||
|
|
||||||
|
String created_at, updated_at, name;
|
||||||
|
List<String> events;
|
||||||
|
boolean active;
|
||||||
|
Map<String,String> config;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
/*package*/ GHHook wrap(GHRepository owner) {
|
||||||
|
this.repository = owner;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnumSet<GHEvent> getEvents() {
|
||||||
|
EnumSet<GHEvent> s = EnumSet.noneOf(GHEvent.class);
|
||||||
|
for (String e : events)
|
||||||
|
Enum.valueOf(GHEvent.class,e.toUpperCase(Locale.ENGLISH));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getConfig() {
|
||||||
|
return Collections.unmodifiableMap(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes this hook.
|
||||||
|
*/
|
||||||
|
public void delete() throws IOException {
|
||||||
|
new Poster(repository.root).withCredential()
|
||||||
|
.to(String.format("/repos/%s/%s/hooks/%d",repository.getOwnerName(),repository.getName(),id),null,"DELETE");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ package org.kohsuke.github;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -46,6 +47,18 @@ public class GHIssue {
|
|||||||
private int number,votes,comments;
|
private int number,votes,comments;
|
||||||
private int position;
|
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.
|
* Repository to which the issue belongs.
|
||||||
*/
|
*/
|
||||||
@@ -99,31 +112,55 @@ public class GHIssue {
|
|||||||
* Updates the issue by adding a comment.
|
* Updates the issue by adding a comment.
|
||||||
*/
|
*/
|
||||||
public void comment(String message) throws IOException {
|
public void comment(String message) throws IOException {
|
||||||
new Poster(root).withCredential().with("comment",message).to(getApiRoute("comment"));
|
new Poster(root).withCredential().with("body",message).to(getApiRoute()+"/comments",null,"POST");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void edit(String key, Object value) throws IOException {
|
||||||
|
new Poster(root).withCredential()._with(key, value)
|
||||||
|
.to(getApiRoute(),null,"PATCH");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes this issue.
|
* Closes this issue.
|
||||||
*/
|
*/
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
new Poster(root).withCredential().to(getApiRoute("close"));
|
edit("state", "closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reopens this issue.
|
* Reopens this issue.
|
||||||
*/
|
*/
|
||||||
public void reopen() throws IOException {
|
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.
|
* Obtains all the comments associated with this issue.
|
||||||
*/
|
*/
|
||||||
public List<GHIssueComment> getComments() throws IOException {
|
public List<GHIssueComment> getComments() throws IOException {
|
||||||
return root.retrieve(getApiRoute("comments"), JsonIssueComments.class).wrap(this);
|
GHIssueComment[] r = root.retrieve(getApiRoute() + "/comments", GHIssueComment[].class);
|
||||||
|
for (GHIssueComment c : r)
|
||||||
|
c.wrapUp(this);
|
||||||
|
return Arrays.asList(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getApiRoute(String verb) {
|
private String getApiRoute() {
|
||||||
return "/issues/"+verb+"/"+owner.getOwnerName()+"/"+owner.getName()+"/"+number;
|
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,6 +37,11 @@ public class GHIssueComment {
|
|||||||
private String body, gravatar_id, user, created_at, updated_at;
|
private String body, gravatar_id, user, created_at, updated_at;
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
|
/*package*/ GHIssueComment wrapUp(GHIssue owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the issue to which this comment is associated.
|
* Gets the issue to which this comment is associated.
|
||||||
*/
|
*/
|
||||||
|
|||||||
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
73
src/main/java/org/kohsuke/github/GHMilestone.java
Normal file
73
src/main/java/org/kohsuke/github/GHMilestone.java
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Yusuke Kokubo
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class GHMilestone {
|
||||||
|
GitHub root;
|
||||||
|
GHRepository owner;
|
||||||
|
|
||||||
|
GHUser creator;
|
||||||
|
private String state, due_on, title, url, created_at, description;
|
||||||
|
private int closed_issues, open_issues, number;
|
||||||
|
|
||||||
|
public GitHub getRoot() {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHRepository getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHUser getCreator() {
|
||||||
|
return creator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDueOn() {
|
||||||
|
if (due_on == null) return null;
|
||||||
|
return GitHub.parseDate(due_on);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return GitHub.parseDate(created_at);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClosedIssues() {
|
||||||
|
return closed_issues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOpenIssues() {
|
||||||
|
return open_issues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumber() {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHMilestoneState getState() {
|
||||||
|
return Enum.valueOf(GHMilestoneState.class, state.toUpperCase(Locale.ENGLISH));
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHMilestone wrap(GHRepository repo) {
|
||||||
|
this.owner = repo;
|
||||||
|
this.root = repo.root;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/main/java/org/kohsuke/github/GHMilestoneState.java
Normal file
11
src/main/java/org/kohsuke/github/GHMilestoneState.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Yusuke Kokubo
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum GHMilestoneState {
|
||||||
|
OPEN,
|
||||||
|
CLOSED
|
||||||
|
}
|
||||||
43
src/main/java/org/kohsuke/github/GHMyself.java
Normal file
43
src/main/java/org/kohsuke/github/GHMyself.java
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the account that's logging into GitHub.
|
||||||
|
*
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public class GHMyself extends GHUser {
|
||||||
|
/**
|
||||||
|
* Returns the read-only list of e-mail addresses configured for you.
|
||||||
|
*
|
||||||
|
* This corresponds to the stuff you configure in https://github.com/settings/emails,
|
||||||
|
* and not to be confused with {@link #getEmail()} that shows your public e-mail address
|
||||||
|
* set in https://github.com/settings/profile
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Always non-null.
|
||||||
|
*/
|
||||||
|
public List<String> getEmails() throws IOException {
|
||||||
|
String[] addresses = root.retrieveWithAuth("/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.retrieveWithAuth("/user/keys", GHKey[].class)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void addEmails(Collection<String> emails) throws IOException {
|
||||||
|
//// new Poster(root,ApiVersion.V3).withCredential().to("/user/emails");
|
||||||
|
// root.retrieveWithAuth3()
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -2,20 +2,25 @@ package org.kohsuke.github;
|
|||||||
|
|
||||||
import com.gargoylesoftware.htmlunit.WebClient;
|
import com.gargoylesoftware.htmlunit.WebClient;
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
|
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlForm;
|
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.AbstractList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kohsuke Kawaguchi
|
* @author Kohsuke Kawaguchi
|
||||||
*/
|
*/
|
||||||
public class GHOrganization extends GHPerson {
|
public class GHOrganization extends GHPerson {
|
||||||
|
/*package*/ GHOrganization wrapUp(GitHub root) {
|
||||||
|
return (GHOrganization)super.wrapUp(root);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new repository.
|
* Creates a new repository.
|
||||||
*
|
*
|
||||||
@@ -23,30 +28,65 @@ public class GHOrganization extends GHPerson {
|
|||||||
* Newly created repository.
|
* Newly created repository.
|
||||||
*/
|
*/
|
||||||
public GHRepository createRepository(String name, String description, String homepage, String team, boolean isPublic) throws IOException {
|
public GHRepository createRepository(String name, String description, String homepage, String team, boolean isPublic) throws IOException {
|
||||||
|
return createRepository(name,description,homepage,getTeams().get(team),isPublic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHRepository createRepository(String name, String description, String homepage, GHTeam team, boolean isPublic) throws IOException {
|
||||||
// such API doesn't exist, so fall back to HTML scraping
|
// such API doesn't exist, so fall back to HTML scraping
|
||||||
WebClient wc = root.createWebClient();
|
return new Poster(root).withCredential()
|
||||||
HtmlPage pg = (HtmlPage)wc.getPage("https://github.com/organizations/"+login+"/repositories/new");
|
.with("name", name).with("description", description).with("homepage", homepage)
|
||||||
HtmlForm f = pg.getForms().get(1);
|
.with("public", isPublic).with("team_id",team.getId()).to("/orgs/"+login+"/repos", GHRepository.class).wrap(root);
|
||||||
f.getInputByName("repository[name]").setValueAttribute(name);
|
|
||||||
f.getInputByName("repository[description]").setValueAttribute(description);
|
|
||||||
f.getInputByName("repository[homepage]").setValueAttribute(homepage);
|
|
||||||
f.getSelectByName("team_id").getOptionByText(team).setSelected(true);
|
|
||||||
f.submit(f.getButtonByCaption("Create Repository"));
|
|
||||||
|
|
||||||
return getRepository(name);
|
|
||||||
|
|
||||||
// GHRepository r = new Poster(root).withCredential()
|
|
||||||
// .with("name", name).with("description", description).with("homepage", homepage)
|
|
||||||
// .with("public", isPublic ? 1 : 0).to(root.getApiURL("/organizations/"+login+"/repos/create"), JsonRepository.class).repository;
|
|
||||||
// r.root = root;
|
|
||||||
// return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Teams by their names.
|
* Teams by their names.
|
||||||
*/
|
*/
|
||||||
public Map<String,GHTeam> getTeams() throws IOException {
|
public Map<String,GHTeam> getTeams() throws IOException {
|
||||||
return root.retrieveWithAuth("/organizations/"+login+"/teams",JsonTeams.class).toMap(this);
|
GHTeam[] teams = root.retrieveWithAuth("/orgs/" + login + "/teams", GHTeam[].class);
|
||||||
|
Map<String,GHTeam> r = new TreeMap<String, GHTeam>();
|
||||||
|
for (GHTeam t : teams) {
|
||||||
|
r.put(t.getName(),t);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publicizes the membership.
|
||||||
|
*/
|
||||||
|
public void publicize(GHUser u) throws IOException {
|
||||||
|
root.retrieveWithAuth("/orgs/" + login + "/public_members/" + u.getLogin(), null, "PUT");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All the members of this organization.
|
||||||
|
*/
|
||||||
|
public List<GHUser> getMembers() throws IOException {
|
||||||
|
return new AbstractList<GHUser>() {
|
||||||
|
// these are shallow objects with only some limited values filled out
|
||||||
|
// TODO: it's better to allow objects to fill themselves in later when missing values are requested
|
||||||
|
final GHUser[] shallow = root.retrieveWithAuth("/orgs/" + login + "/members", GHUser[].class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GHUser get(int index) {
|
||||||
|
try {
|
||||||
|
return root.getUser(shallow[index].getLogin());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return shallow.length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conceals the membership.
|
||||||
|
*/
|
||||||
|
public void conceal(GHUser u) throws IOException {
|
||||||
|
root.retrieveWithAuth("/orgs/" + login + "/public_members/" + u.getLogin(), null, "DELETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Permission { ADMIN, PUSH, PULL }
|
public enum Permission { ADMIN, PUSH, PULL }
|
||||||
@@ -55,11 +95,13 @@ public class GHOrganization extends GHPerson {
|
|||||||
* Creates a new team and assigns the repositories.
|
* Creates a new team and assigns the repositories.
|
||||||
*/
|
*/
|
||||||
public GHTeam createTeam(String name, Permission p, Collection<GHRepository> repositories) throws IOException {
|
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).withCredential().with("name", name).with("permission", p.name().toLowerCase());
|
||||||
|
List<String> repo_names = new ArrayList<String>();
|
||||||
for (GHRepository r : repositories) {
|
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 {
|
public GHTeam createTeam(String name, Permission p, GHRepository... repositories) throws IOException {
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
@@ -13,36 +17,172 @@ import java.util.TreeMap;
|
|||||||
public abstract class GHPerson {
|
public abstract class GHPerson {
|
||||||
/*package almost final*/ GitHub root;
|
/*package almost final*/ GitHub root;
|
||||||
|
|
||||||
protected String gravatar_id,login;
|
// common
|
||||||
|
protected String login,location,blog,email,name,created_at,company;
|
||||||
|
protected int id;
|
||||||
|
protected String gravatar_id; // appears in V3 as well but presumably subsumed by avatar_url?
|
||||||
|
|
||||||
protected int public_gist_count,public_repo_count,following_count,id;
|
// V2
|
||||||
|
protected int public_gist_count,public_repo_count,followers_count,following_count;
|
||||||
|
|
||||||
|
// V3
|
||||||
|
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.
|
* Gets the repositories this user owns.
|
||||||
*/
|
*/
|
||||||
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)) {
|
||||||
Map<String, GHRepository> map = root.retrieve("/repos/show/" + login + "?page=" + i, JsonRepositories.class).wrap(root);
|
for (GHRepository r : batch)
|
||||||
repositories.putAll(map);
|
repositories.put(r.getName(),r);
|
||||||
if (map.isEmpty()) 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);
|
||||||
|
|
||||||
|
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
|
||||||
|
* null if the repository was not found
|
||||||
|
*/
|
||||||
public GHRepository getRepository(String name) throws IOException {
|
public GHRepository getRepository(String name) throws IOException {
|
||||||
return root.retrieve("/repos/show/" + login + '/' + name, JsonRepository.class).wrap(root);
|
try {
|
||||||
|
return root.retrieveWithAuth("/repos/" + login + '/' + name, GHRepository.class).wrap(root);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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'
|
||||||
|
*/
|
||||||
public String getLogin() {
|
public String getLogin() {
|
||||||
return login;
|
return login;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the human-readable name of the user, like "Kohsuke Kawaguchi"
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the company name of this user, like "Sun Microsystems, Inc."
|
||||||
|
*/
|
||||||
|
public String getCompany() {
|
||||||
|
return company;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the location of this user, like "Santa Clara, California"
|
||||||
|
*/
|
||||||
|
public String getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreatedAt() {
|
||||||
|
return created_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the blog URL of this user.
|
||||||
|
*/
|
||||||
|
public String getBlog() {
|
||||||
|
return blog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the e-mail address of the user.
|
||||||
|
*/
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPublicGistCount() {
|
||||||
|
return Math.max(public_gist_count,public_gists);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPublicRepoCount() {
|
||||||
|
return Math.max(public_repo_count,public_repos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFollowingCount() {
|
||||||
|
return Math.max(following_count,following);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What appears to be a GitHub internal unique number that identifies this user.
|
||||||
|
*/
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFollowersCount() {
|
||||||
|
return Math.max(followers_count,followers);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/main/java/org/kohsuke/github/GHPersonSet.java
Normal file
41
src/main/java/org/kohsuke/github/GHPersonSet.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of {@link GHPerson} with helper lookup methods.
|
||||||
|
*
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public final class GHPersonSet<T extends GHPerson> extends HashSet<T> {
|
||||||
|
public GHPersonSet() {
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHPersonSet(int initialCapacity) {
|
||||||
|
super(initialCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the item by its login.
|
||||||
|
*/
|
||||||
|
public T byLogin(String login) {
|
||||||
|
for (T t : this)
|
||||||
|
if (t.getLogin().equals(login))
|
||||||
|
return t;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ package org.kohsuke.github;
|
|||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pull request.
|
* A pull request.
|
||||||
@@ -64,7 +63,7 @@ public class GHPullRequest extends GHIssue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The change that should be pulled.
|
* The change that should be pulled. The tip of the commits to merge.
|
||||||
*/
|
*/
|
||||||
public GHCommitPointer getHead() {
|
public GHCommitPointer getHead() {
|
||||||
return head;
|
return head;
|
||||||
@@ -93,4 +92,19 @@ public class GHPullRequest extends GHIssue {
|
|||||||
public Date getClosedAt() {
|
public Date getClosedAt() {
|
||||||
return GitHub.parseDate(closed_at);
|
return GitHub.parseDate(closed_at);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GHPullRequest wrapUp(GHRepository owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
return wrapUp(owner.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
GHPullRequest wrapUp(GitHub root) {
|
||||||
|
this.root = root;
|
||||||
|
if (owner!=null) owner.wrap(root);
|
||||||
|
if (issue_user!=null) issue_user.root=root;
|
||||||
|
if (user!=null) user.root=root;
|
||||||
|
if (base!=null) base.wrapUp(root);
|
||||||
|
if (head!=null) head.wrapUp(root);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
src/main/java/org/kohsuke/github/GHRateLimit.java
Normal file
21
src/main/java/org/kohsuke/github/GHRateLimit.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rate limit.
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public class GHRateLimit {
|
||||||
|
/**
|
||||||
|
* Remaining calls that can be made.
|
||||||
|
*/
|
||||||
|
public int remaining;
|
||||||
|
/**
|
||||||
|
* Alotted API call per hour.
|
||||||
|
*/
|
||||||
|
public int limit;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return remaining+"/"+limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,32 +23,32 @@
|
|||||||
*/
|
*/
|
||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
|
|
||||||
import com.gargoylesoftware.htmlunit.WebClient;
|
import com.gargoylesoftware.htmlunit.WebClient;
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlButton;
|
import com.gargoylesoftware.htmlunit.html.HtmlButton;
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
|
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlForm;
|
import com.gargoylesoftware.htmlunit.html.HtmlForm;
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlInput;
|
import com.gargoylesoftware.htmlunit.html.HtmlInput;
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||||
|
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.AbstractSet;
|
import java.util.AbstractSet;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import static java.util.Arrays.*;
|
import static java.util.Arrays.*;
|
||||||
import static org.kohsuke.github.ApiVersion.V3;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A repository on GitHub.
|
* A repository on GitHub.
|
||||||
@@ -59,10 +59,24 @@ import static org.kohsuke.github.ApiVersion.V3;
|
|||||||
public class GHRepository {
|
public class GHRepository {
|
||||||
/*package almost final*/ GitHub root;
|
/*package almost final*/ GitHub root;
|
||||||
|
|
||||||
private String description, homepage, url, name, owner;
|
private String description, homepage, name;
|
||||||
|
private String url; // this is the API url
|
||||||
|
private String html_url; // this is the UI
|
||||||
|
private GHUser owner; // not fully populated. beware.
|
||||||
private boolean has_issues, has_wiki, fork, _private, has_downloads;
|
private 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 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;
|
||||||
@@ -73,26 +87,64 @@ public class GHRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL of this repository, like 'http://github.com/kohsuke/hudson'
|
* URL of this repository, like 'http://github.com/kohsuke/jenkins'
|
||||||
*/
|
*/
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return url;
|
return html_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the git:// URL to this repository, such as "git://github.com/kohsuke/jenkins.git"
|
||||||
|
* This URL is read-only.
|
||||||
|
*/
|
||||||
|
public String getGitTransportUrl() {
|
||||||
|
return "git://github.com/"+getOwnerName()+"/"+name+".git";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the HTTPS URL to this repository, such as "https://github.com/kohsuke/jenkins.git"
|
||||||
|
* This URL is read-only.
|
||||||
|
*/
|
||||||
|
public String gitHttpTransportUrl() {
|
||||||
|
return "https://github.com/"+getOwnerName()+"/"+name+".git";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins
|
||||||
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
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);
|
return root.getUser(owner.login); // because 'owner' isn't fully populated
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<GHIssue> getIssues(GHIssueState state) throws IOException {
|
public List<GHIssue> getIssues(GHIssueState state) throws IOException {
|
||||||
return root.retrieve("/issues/list/" + owner + "/" + name + "/" + state.toString().toLowerCase(), JsonIssues.class).wrap(this);
|
return Arrays.asList(GHIssue.wrap(root.retrieve("/repos/" + owner.login + "/" + name + "/issues?state=" + state.toString().toLowerCase(), GHIssue[].class), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getOwnerName() {
|
protected String getOwnerName() {
|
||||||
return owner;
|
return owner.login;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasIssues() {
|
public boolean hasIssues() {
|
||||||
@@ -127,6 +179,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);
|
||||||
}
|
}
|
||||||
@@ -135,16 +192,27 @@ 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.
|
||||||
* This set always appear to include the owner.
|
* This set always appear to include the owner.
|
||||||
*/
|
*/
|
||||||
public Set<GHUser> getCollaborators() throws IOException {
|
@WithBridgeMethods(Set.class)
|
||||||
Set<GHUser> r = new HashSet<GHUser>();
|
public GHPersonSet<GHUser> getCollaborators() throws IOException {
|
||||||
for (String u : root.retrieve("/repos/show/"+owner+"/"+name+"/collaborators",JsonCollaborators.class).collaborators)
|
return new GHPersonSet<GHUser>(GHUser.wrap(root.retrieve("/repos/" + owner.login + "/" + name + "/collaborators", GHUser[].class),root));
|
||||||
r.add(root.getUser(u));
|
|
||||||
return Collections.unmodifiableSet(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -152,16 +220,17 @@ public class GHRepository {
|
|||||||
* This method deviates from the principle of this library but it works a lot faster than {@link #getCollaborators()}.
|
* This method deviates from the principle of this library but it works a lot faster than {@link #getCollaborators()}.
|
||||||
*/
|
*/
|
||||||
public Set<String> getCollaboratorNames() throws IOException {
|
public Set<String> getCollaboratorNames() throws IOException {
|
||||||
Set<String> r = new HashSet<String>(root.retrieve("/repos/show/"+owner+"/"+name+"/collaborators",JsonCollaborators.class).collaborators);
|
Set<String> r = new HashSet<String>();
|
||||||
return Collections.unmodifiableSet(r);
|
for (GHUser u : GHUser.wrap(root.retrieve("/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.
|
* If this repository belongs to an organization, return a set of teams.
|
||||||
*/
|
*/
|
||||||
public Set<GHTeam> getTeams() throws IOException {
|
public Set<GHTeam> getTeams() throws IOException {
|
||||||
return Collections.unmodifiableSet(root.retrieveWithAuth("/repos/show/"+owner+"/"+name+"/teams",JsonTeams.class).toSet(
|
return Collections.unmodifiableSet(new HashSet<GHTeam>(Arrays.asList(GHTeam.wrapUp(root.retrieveWithAuth("/repos/" + owner.login + "/" + name + "/teams", GHTeam[].class), root.getOrganization(owner.login)))));
|
||||||
root.getOrganization(owner)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCollaborators(GHUser... users) throws IOException {
|
public void addCollaborators(GHUser... users) throws IOException {
|
||||||
@@ -169,7 +238,7 @@ public class GHRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addCollaborators(Collection<GHUser> users) throws IOException {
|
public void addCollaborators(Collection<GHUser> users) throws IOException {
|
||||||
modifyCollaborators(users, "/add/");
|
modifyCollaborators(users, "PUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeCollaborators(GHUser... users) throws IOException {
|
public void removeCollaborators(GHUser... users) throws IOException {
|
||||||
@@ -177,13 +246,13 @@ public class GHRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeCollaborators(Collection<GHUser> users) throws IOException {
|
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();
|
verifyMine();
|
||||||
for (GHUser user : users) {
|
for (GHUser user : users) {
|
||||||
new Poster(root).withCredential().to("/repos/collaborators/"+name+ op +user.getLogin());
|
new Poster(root).withCredential().to("/repos/"+owner.login+"/"+name+"/collaborators/"+user.getLogin(),null,method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,31 +268,54 @@ public class GHRepository {
|
|||||||
f.submit((HtmlButton) f.getElementsByTagName("button").get(0));
|
f.submit((HtmlButton) f.getElementsByTagName("button").get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void edit(String key, String value) throws IOException {
|
||||||
|
new Poster(root).withCredential().with(key,value)
|
||||||
|
.to("/repos/" + owner.login + "/" + name,null,"PATCH");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables or disables the issue tracker for this repository.
|
* Enables or disables the issue tracker for this repository.
|
||||||
*/
|
*/
|
||||||
public void enableIssueTracker(boolean v) throws IOException {
|
public void enableIssueTracker(boolean v) throws IOException {
|
||||||
new Poster(root).withCredential().with("values[has_issues]",String.valueOf(v))
|
edit("has_issues", String.valueOf(v));
|
||||||
.to("/repos/show/" + owner + "/" + name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables or disables Wiki for this repository.
|
* Enables or disables Wiki for this repository.
|
||||||
*/
|
*/
|
||||||
public void enableWiki(boolean v) throws IOException {
|
public void enableWiki(boolean v) throws IOException {
|
||||||
new Poster(root).withCredential().with("values[has_wiki]",String.valueOf(v))
|
edit("has_wiki", String.valueOf(v));
|
||||||
.to("/repos/show/" + owner + "/" + name);
|
}
|
||||||
|
|
||||||
|
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.
|
* Deletes this repository.
|
||||||
*/
|
*/
|
||||||
public void delete() throws IOException {
|
public void delete() throws IOException {
|
||||||
Poster poster = new Poster(root).withCredential();
|
throw new UnsupportedOperationException(); // doesn't appear to be available in V3
|
||||||
String url = "/repos/delete/" + owner +"/"+name;
|
// 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);
|
// DeleteToken token = poster.to(url, DeleteToken.class);
|
||||||
|
// poster.with("delete_token", token.delete_token).to(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -233,7 +325,7 @@ public class GHRepository {
|
|||||||
* Newly forked repository that belong to you.
|
* Newly forked repository that belong to you.
|
||||||
*/
|
*/
|
||||||
public GHRepository fork() throws IOException {
|
public GHRepository fork() throws IOException {
|
||||||
return new Poster(root).withCredential().to("/repos/fork/" + owner + "/" + name, JsonRepository.class).wrap(root);
|
return new Poster(root).withCredential().to("/repos/" + owner.login + "/" + name + "/forks", GHRepository.class, "POST").wrap(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,55 +335,122 @@ public class GHRepository {
|
|||||||
* Newly forked repository that belong to you.
|
* Newly forked repository that belong to you.
|
||||||
*/
|
*/
|
||||||
public GHRepository forkTo(GHOrganization org) throws IOException {
|
public GHRepository forkTo(GHOrganization org) throws IOException {
|
||||||
new Poster(root, V3).withCredential().to(String.format("/repos/%s/%s/forks?org=%s",owner,name,org.getLogin()));
|
new Poster(root).withCredential().to(String.format("/repos/%s/%s/forks?org=%s",owner.login,name,org.getLogin()));
|
||||||
return org.getRepository(name);
|
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+'/'+name+" or there's a bug in HTML scraping");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a specified pull request.
|
* Retrieves a specified pull request.
|
||||||
*/
|
*/
|
||||||
public GHPullRequest getPullRequest(int i) throws IOException {
|
public GHPullRequest getPullRequest(int i) throws IOException {
|
||||||
return root.retrieveWithAuth("/pulls/" + owner + '/' + name + "/" + i, JsonPullRequest.class).wrap(this);
|
return root.retrieveWithAuth("/repos/" + owner.login + '/' + name + "/pulls/" + i, GHPullRequest.class).wrapUp(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all the pull requests of a particular state.
|
* Retrieves all the pull requests of a particular state.
|
||||||
*/
|
*/
|
||||||
public List<GHPullRequest> getPullRequests(GHIssueState state) throws IOException {
|
public List<GHPullRequest> getPullRequests(GHIssueState state) throws IOException {
|
||||||
return root.retrieveWithAuth("/pulls/"+owner+'/'+name+"/"+state.name().toLowerCase(Locale.ENGLISH),JsonPullRequests.class).wrap(this);
|
GHPullRequest[] r = root.retrieveWithAuth("/repos/" + owner.login + '/' + name + "/pulls?state=" + state.name().toLowerCase(Locale.ENGLISH), GHPullRequest[].class);
|
||||||
|
for (GHPullRequest p : r)
|
||||||
|
p.wrapUp(this);
|
||||||
|
return new ArrayList<GHPullRequest>(Arrays.asList(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the currently configured hooks.
|
||||||
|
*/
|
||||||
|
public List<GHHook> getHooks() throws IOException {
|
||||||
|
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList(
|
||||||
|
root.retrieveWithAuth(String.format("/repos/%s/%s/hooks", owner.login, name), GHHook[].class)));
|
||||||
|
for (GHHook h : list)
|
||||||
|
h.wrap(this);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHHook getHook(int id) throws IOException {
|
||||||
|
return root.retrieveWithAuth(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.retrieve(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)) {
|
||||||
|
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)) {
|
||||||
|
@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.
|
||||||
|
* TODO: produce type-safe binding
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* Type of the hook to be created. See https://api.github.com/hooks for possible names.
|
||||||
|
* @param config
|
||||||
|
* The configuration hash.
|
||||||
|
* @param events
|
||||||
|
* Can be null. Types of events to hook into.
|
||||||
|
*/
|
||||||
|
public GHHook createHook(String name, Map<String,String> config, Collection<GHEvent> events, boolean active) throws IOException {
|
||||||
|
List<String> ea = null;
|
||||||
|
if (events!=null) {
|
||||||
|
ea = new ArrayList<String>();
|
||||||
|
for (GHEvent e : events)
|
||||||
|
ea.add(e.name().toLowerCase(Locale.ENGLISH));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Poster(root)
|
||||||
|
.withCredential()
|
||||||
|
.with("name",name)
|
||||||
|
.with("active", active)
|
||||||
|
._with("config", config)
|
||||||
|
._with("events",ea)
|
||||||
|
.to(String.format("/repos/%s/%s/hooks",owner.login,this.name),GHHook.class).wrap(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHHook createWebHook(URL url, Collection<GHEvent> events) throws IOException {
|
||||||
|
return createHook("web",Collections.singletonMap("url",url.toExternalForm()),events,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHHook createWebHook(URL url) throws IOException {
|
||||||
|
return createWebHook(url,null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is no different from getPullRequests(OPEN)
|
// this is no different from getPullRequests(OPEN)
|
||||||
@@ -303,13 +462,16 @@ public class GHRepository {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
private void verifyMine() throws IOException {
|
private void verifyMine() throws IOException {
|
||||||
if (!root.login.equals(owner))
|
if (!root.login.equals(owner.login))
|
||||||
throw new IOException("Operation not applicable to a repository owned by someone else: "+owner);
|
throw new IOException("Operation not applicable to a repository owned by someone else: "+owner.login);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a set that represents the post-commit hook URLs.
|
* Returns a set that represents the post-commit hook URLs.
|
||||||
* The returned set is live, and changes made to them are reflected to GitHub.
|
* The returned set is live, and changes made to them are reflected to GitHub.
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
* Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)}
|
||||||
*/
|
*/
|
||||||
public Set<URL> getPostCommitHooks() {
|
public Set<URL> getPostCommitHooks() {
|
||||||
return postCommitHooks;
|
return postCommitHooks;
|
||||||
@@ -321,15 +483,11 @@ public class GHRepository {
|
|||||||
private final Set<URL> postCommitHooks = new AbstractSet<URL>() {
|
private final Set<URL> postCommitHooks = new AbstractSet<URL>() {
|
||||||
private List<URL> getPostCommitHooks() {
|
private List<URL> getPostCommitHooks() {
|
||||||
try {
|
try {
|
||||||
verifyMine();
|
|
||||||
|
|
||||||
HtmlForm f = getForm();
|
|
||||||
|
|
||||||
List<URL> r = new ArrayList<URL>();
|
List<URL> r = new ArrayList<URL>();
|
||||||
for (HtmlInput i : f.getInputsByName("urls[]")) {
|
for (GHHook h : getHooks()) {
|
||||||
String v = i.getValueAttribute();
|
if (h.getName().equals("web")) {
|
||||||
if (v.length()==0) continue;
|
r.add(new URL(h.getConfig().get("url")));
|
||||||
r.add(new URL(v));
|
}
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -350,22 +508,7 @@ public class GHRepository {
|
|||||||
@Override
|
@Override
|
||||||
public boolean add(URL url) {
|
public boolean add(URL url) {
|
||||||
try {
|
try {
|
||||||
String u = url.toExternalForm();
|
createWebHook(url);
|
||||||
|
|
||||||
verifyMine();
|
|
||||||
|
|
||||||
HtmlForm f = getForm();
|
|
||||||
|
|
||||||
List<HtmlInput> controls = f.getInputsByName("urls[]");
|
|
||||||
for (HtmlInput i : controls) {
|
|
||||||
String v = i.getValueAttribute();
|
|
||||||
if (v.length()==0) continue;
|
|
||||||
if (v.equals(u))
|
|
||||||
return false; // already there
|
|
||||||
}
|
|
||||||
|
|
||||||
controls.get(controls.size()-1).setValueAttribute(u);
|
|
||||||
f.submit(null);
|
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new GHException("Failed to update post-commit hooks",e);
|
throw new GHException("Failed to update post-commit hooks",e);
|
||||||
@@ -373,43 +516,70 @@ public class GHRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean remove(Object o) {
|
public boolean remove(Object url) {
|
||||||
try {
|
try {
|
||||||
String u = ((URL)o).toExternalForm();
|
String _url = ((URL)url).toExternalForm();
|
||||||
|
for (GHHook h : getHooks()) {
|
||||||
verifyMine();
|
if (h.getName().equals("web") && h.getConfig().get("url").equals(_url)) {
|
||||||
|
h.delete();
|
||||||
HtmlForm f = getForm();
|
|
||||||
|
|
||||||
List<HtmlInput> controls = f.getInputsByName("urls[]");
|
|
||||||
for (HtmlInput i : controls) {
|
|
||||||
String v = i.getValueAttribute();
|
|
||||||
if (v.length()==0) continue;
|
|
||||||
if (v.equals(u)) {
|
|
||||||
i.setValueAttribute("");
|
|
||||||
f.submit(null);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new GHException("Failed to update post-commit hooks",e);
|
throw new GHException("Failed to update post-commit hooks",e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private HtmlForm getForm() throws IOException {
|
|
||||||
WebClient wc = root.createWebClient();
|
|
||||||
HtmlPage pg = (HtmlPage)wc.getPage(getUrl()+"/admin");
|
|
||||||
HtmlForm f = (HtmlForm) pg.getElementById("new_service");
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*package*/ GHRepository wrap(GitHub root) {
|
||||||
|
this.root = root;
|
||||||
|
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.retrieve("/repos/" + owner.login + "/" + name + "/branches", GHBranch[].class)) {
|
||||||
|
p.wrap(this);
|
||||||
|
r.put(p.getName(),p);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, GHMilestone> getMilestones() throws IOException {
|
||||||
|
Map<Integer,GHMilestone> milestones = new TreeMap<Integer, GHMilestone>();
|
||||||
|
GHMilestone[] ms = root.retrieve("/repos/" + owner.login + "/" + name + "/milestones", GHMilestone[].class);
|
||||||
|
for (GHMilestone m : ms) {
|
||||||
|
m.owner = this;
|
||||||
|
m.root = root;
|
||||||
|
milestones.put(m.getNumber(), m);
|
||||||
|
}
|
||||||
|
return milestones;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHMilestone getMilestone(int number) throws IOException {
|
||||||
|
GHMilestone m = milestones.get(number);
|
||||||
|
if (m == null) {
|
||||||
|
m = root.retrieve("/repos/" + owner.login + "/" + name + "/milestones/" + number, GHMilestone.class);
|
||||||
|
m.owner = this;
|
||||||
|
m.root = root;
|
||||||
|
milestones.put(m.getNumber(), m);
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHMilestone createMilestone(String title, String description) throws IOException {
|
||||||
|
return new Poster(root).withCredential()
|
||||||
|
.with("title", title).with("description", description)
|
||||||
|
.to("/repos/"+owner.login+"/"+name+"/milestones", GHMilestone.class,"POST").wrap(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Repository:"+owner+":"+name;
|
return "Repository:"+owner.login+":"+name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -421,7 +591,7 @@ public class GHRepository {
|
|||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj instanceof GHRepository) {
|
if (obj instanceof GHRepository) {
|
||||||
GHRepository that = (GHRepository) obj;
|
GHRepository that = (GHRepository) obj;
|
||||||
return this.owner.equals(that.owner)
|
return this.owner.login.equals(that.owner.login)
|
||||||
&& this.name.equals(that.name);
|
&& this.name.equals(that.name);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A team in GitHub organization.
|
* A team in GitHub organization.
|
||||||
@@ -15,6 +18,18 @@ public class GHTeam {
|
|||||||
|
|
||||||
protected /*final*/ GHOrganization org;
|
protected /*final*/ GHOrganization org;
|
||||||
|
|
||||||
|
/*package*/ GHTeam wrapUp(GHOrganization owner) {
|
||||||
|
this.org = owner;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ static GHTeam[] wrapUp(GHTeam[] teams, GHOrganization owner) {
|
||||||
|
for (GHTeam t : teams) {
|
||||||
|
t.wrapUp(owner);
|
||||||
|
}
|
||||||
|
return teams;
|
||||||
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -31,33 +46,38 @@ public class GHTeam {
|
|||||||
* Retrieves the current members.
|
* Retrieves the current members.
|
||||||
*/
|
*/
|
||||||
public Set<GHUser> getMembers() throws IOException {
|
public Set<GHUser> getMembers() throws IOException {
|
||||||
return org.root.retrieveWithAuth(api("/members"),JsonUsersWithDetails.class).toSet(org.root);
|
return new HashSet<GHUser>(Arrays.asList(GHUser.wrap(org.root.retrieveWithAuth(api("/members"), GHUser[].class), org.root)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String,GHRepository> getRepositories() throws IOException {
|
public Map<String,GHRepository> getRepositories() throws IOException {
|
||||||
return org.root.retrieveWithAuth(api("/repositories"),JsonRepositories.class).wrap(org.root);
|
GHRepository[] repos = org.root.retrieveWithAuth(api("/repos"), GHRepository[].class);
|
||||||
|
Map<String,GHRepository> m = new TreeMap<String, GHRepository>();
|
||||||
|
for (GHRepository r : repos) {
|
||||||
|
m.put(r.getName(),r.wrap(org.root));
|
||||||
|
}
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a member to the team.
|
* Adds a member to the team.
|
||||||
*/
|
*/
|
||||||
public void add(GHUser u) throws IOException {
|
public void add(GHUser u) throws IOException {
|
||||||
org.root.retrieveWithAuth(api("/members?name="+u.getLogin()),null, "POST");
|
org.root.retrieveWithAuth(api("/members/" + u.getLogin()), null, "PUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a member to the team.
|
* Removes a member to the team.
|
||||||
*/
|
*/
|
||||||
public void remove(GHUser u) throws IOException {
|
public void remove(GHUser u) throws IOException {
|
||||||
org.root.retrieveWithAuth(api("/members?name="+u.getLogin()),null, "DELETE");
|
org.root.retrieveWithAuth(api("/members/" + u.getLogin()), null, "DELETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(GHRepository r) throws IOException {
|
public void add(GHRepository r) throws IOException {
|
||||||
org.root.retrieveWithAuth(api("/repositories?name="+r.getOwnerName()+'/'+r.getName()),null, "POST");
|
org.root.retrieveWithAuth(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null, "PUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(GHRepository r) throws IOException {
|
public void remove(GHRepository r) throws IOException {
|
||||||
org.root.retrieveWithAuth(api("/repositories?name="+r.getOwnerName()+'/'+r.getName()),null, "DELETE");
|
org.root.retrieveWithAuth(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null, "DELETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String api(String tail) {
|
private String api(String tail) {
|
||||||
|
|||||||
@@ -23,7 +23,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,104 +36,57 @@ import java.util.Set;
|
|||||||
* @author Kohsuke Kawaguchi
|
* @author Kohsuke Kawaguchi
|
||||||
*/
|
*/
|
||||||
public class GHUser extends GHPerson {
|
public class GHUser extends GHPerson {
|
||||||
private String name,company,location,created_at,blog,email;
|
|
||||||
private int followers_count;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the human-readable name of the user, like "Kohsuke Kawaguchi"
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the company name of this user, like "Sun Microsystems, Inc."
|
|
||||||
*/
|
|
||||||
public String getCompany() {
|
|
||||||
return company;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the location of this user, like "Santa Clara, California"
|
|
||||||
*/
|
|
||||||
public String getLocation() {
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCreatedAt() {
|
|
||||||
return created_at;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the blog URL of this user.
|
|
||||||
*/
|
|
||||||
public String getBlog() {
|
|
||||||
return blog;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the login ID of this user, like 'kohsuke'
|
|
||||||
*/
|
|
||||||
public String getLogin() {
|
|
||||||
return login;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the e-mail address of the user.
|
|
||||||
*/
|
|
||||||
public String getEmail() {
|
|
||||||
return email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPublicGistCount() {
|
|
||||||
return public_gist_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPublicRepoCount() {
|
|
||||||
return public_repo_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getFollowingCount() {
|
|
||||||
return following_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* What appears to be a GitHub internal unique number that identifies this user.
|
|
||||||
*/
|
|
||||||
public int getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getFollowersCount() {
|
|
||||||
return followers_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Follow this user.
|
* Follow this user.
|
||||||
*/
|
*/
|
||||||
public void follow() throws IOException {
|
public void follow() throws IOException {
|
||||||
new Poster(root).withCredential().to("/user/follow/"+login);
|
new Poster(root).withCredential().to("/user/following/"+login,null,"PUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unfollow this user.
|
* Unfollow this user.
|
||||||
*/
|
*/
|
||||||
public void unfollow() throws IOException {
|
public void unfollow() throws IOException {
|
||||||
new Poster(root).withCredential().to("/user/unfollow/"+login);
|
new Poster(root).withCredential().to("/user/following/"+login,null,"DELETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists the users that this user is following
|
* Lists the users that this user is following
|
||||||
*/
|
*/
|
||||||
public Set<GHUser> getFollows() throws IOException {
|
@WithBridgeMethods(Set.class)
|
||||||
return root.retrieve("/user/show/"+login+"/following",JsonUsers.class).toSet(root);
|
public GHPersonSet<GHUser> getFollows() throws IOException {
|
||||||
|
GHUser[] followers = root.retrieve("/users/" + login + "/following", GHUser[].class);
|
||||||
|
return new GHPersonSet<GHUser>(Arrays.asList(wrap(followers,root)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists the users who are following this user.
|
* Lists the users who are following this user.
|
||||||
*/
|
*/
|
||||||
public Set<GHUser> getFollowers() throws IOException {
|
@WithBridgeMethods(Set.class)
|
||||||
return root.retrieve("/user/show/"+login+"/followers",JsonUsers.class).toSet(root);
|
public GHPersonSet<GHUser> getFollowers() throws IOException {
|
||||||
|
GHUser[] followers = root.retrieve("/users/" + login + "/followers", GHUser[].class);
|
||||||
|
return new GHPersonSet<GHUser>(Arrays.asList(wrap(followers,root)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ static GHUser[] wrap(GHUser[] users, GitHub root) {
|
||||||
|
for (GHUser f : users)
|
||||||
|
f.root = root;
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the organization that this user belongs to publicly.
|
||||||
|
*/
|
||||||
|
@WithBridgeMethods(Set.class)
|
||||||
|
public GHPersonSet<GHOrganization> getOrganizations() throws IOException {
|
||||||
|
GHPersonSet<GHOrganization> orgs = new GHPersonSet<GHOrganization>();
|
||||||
|
Set<String> names = new HashSet<String>();
|
||||||
|
for (GHOrganization o : root.retrieve("/users/" + login + "/orgs", GHOrganization[].class)) {
|
||||||
|
if (names.add(o.getLogin())) // I've seen some duplicates in the data
|
||||||
|
orgs.add(root.getOrganization(o.getLogin()));
|
||||||
|
}
|
||||||
|
return orgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -23,34 +23,44 @@
|
|||||||
*/
|
*/
|
||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import com.gargoylesoftware.htmlunit.WebClient;
|
import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.ANY;
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlForm;
|
import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE;
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.codehaus.jackson.map.DeserializationConfig.Feature;
|
|
||||||
import org.codehaus.jackson.map.ObjectMapper;
|
|
||||||
import org.codehaus.jackson.map.introspect.VisibilityChecker.Std;
|
|
||||||
import sun.misc.BASE64Encoder;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.InterruptedIOException;
|
import java.io.InterruptedIOException;
|
||||||
|
import java.io.Reader;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Collections;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.Iterator;
|
||||||
|
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.Set;
|
import java.util.TimeZone;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.*;
|
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.codehaus.jackson.map.DeserializationConfig.Feature;
|
||||||
|
import org.codehaus.jackson.map.ObjectMapper;
|
||||||
|
import org.codehaus.jackson.map.introspect.VisibilityChecker.Std;
|
||||||
|
|
||||||
|
import sun.misc.BASE64Encoder;
|
||||||
|
|
||||||
|
import com.gargoylesoftware.htmlunit.WebClient;
|
||||||
|
import com.gargoylesoftware.htmlunit.html.HtmlForm;
|
||||||
|
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Root of the GitHub API.
|
* Root of the GitHub API.
|
||||||
@@ -65,10 +75,22 @@ public class GitHub {
|
|||||||
|
|
||||||
private final Map<String,GHUser> users = new HashMap<String, GHUser>();
|
private final Map<String,GHUser> users = new HashMap<String, GHUser>();
|
||||||
private final Map<String,GHOrganization> orgs = new HashMap<String, GHOrganization>();
|
private final Map<String,GHOrganization> orgs = new HashMap<String, GHOrganization>();
|
||||||
private String oauthAccessToken;
|
/*package*/ String oauthAccessToken;
|
||||||
|
|
||||||
|
private final String githubServer;
|
||||||
|
|
||||||
private GitHub(String login, String apiToken, String password) {
|
private GitHub(String login, String apiToken, String password) {
|
||||||
this.login = login;
|
this ("github.com", login, apiToken, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param githubServer
|
||||||
|
* The host name of the GitHub (or GitHub enterprise) server, such as "github.com".
|
||||||
|
*/
|
||||||
|
private GitHub(String githubServer, String login, String apiToken, String password) {
|
||||||
|
this.githubServer = githubServer;
|
||||||
|
this.login = login;
|
||||||
this.apiToken = apiToken;
|
this.apiToken = apiToken;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
|
|
||||||
@@ -80,8 +102,9 @@ public class GitHub {
|
|||||||
encodedAuthorization = null;
|
encodedAuthorization = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GitHub (String oauthAccessToken) throws IOException {
|
private GitHub (String githubServer, String oauthAccessToken) throws IOException {
|
||||||
|
|
||||||
|
this.githubServer = githubServer;
|
||||||
this.password = null;
|
this.password = null;
|
||||||
this.encodedAuthorization = null;
|
this.encodedAuthorization = null;
|
||||||
|
|
||||||
@@ -115,7 +138,11 @@ public class GitHub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static GitHub connectUsingOAuth (String accessToken) throws IOException {
|
public static GitHub connectUsingOAuth (String accessToken) throws IOException {
|
||||||
return new GitHub(accessToken);
|
return connectUsingOAuth("github.com", accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GitHub connectUsingOAuth (String githubServer, String accessToken) throws IOException {
|
||||||
|
return new GitHub(githubServer, accessToken);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Connects to GitHub anonymously.
|
* Connects to GitHub anonymously.
|
||||||
@@ -131,13 +158,13 @@ public class GitHub {
|
|||||||
throw new IllegalStateException("This operation requires a credential but none is given to the GitHub constructor");
|
throw new IllegalStateException("This operation requires a credential but none is given to the GitHub constructor");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ URL getApiURL(ApiVersion v, String tailApiUrl) throws IOException {
|
/*package*/ URL getApiURL(String tailApiUrl) throws IOException {
|
||||||
if (oauthAccessToken != null) {
|
if (oauthAccessToken != null) {
|
||||||
// append the access token
|
// append the access token
|
||||||
tailApiUrl = tailApiUrl + "?access_token=" + oauthAccessToken;
|
tailApiUrl = tailApiUrl + (tailApiUrl.indexOf('?')>=0 ?'&':'?') + "access_token=" + oauthAccessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new URL(v.url+tailApiUrl);
|
return new URL("https://api."+githubServer+tailApiUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ <T> T retrieve(String tailApiUrl, Class<T> type) throws IOException {
|
/*package*/ <T> T retrieve(String tailApiUrl, Class<T> type) throws IOException {
|
||||||
@@ -145,7 +172,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 _retrieve(tailApiUrl, type, "GET", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ <T> T retrieveWithAuth(String tailApiUrl, Class<T> type, String method) throws IOException {
|
/*package*/ <T> T retrieveWithAuth(String tailApiUrl, Class<T> type, String method) throws IOException {
|
||||||
@@ -154,28 +181,144 @@ public class GitHub {
|
|||||||
|
|
||||||
private <T> T _retrieve(String tailApiUrl, Class<T> type, String method, boolean withAuth) throws IOException {
|
private <T> T _retrieve(String tailApiUrl, Class<T> type, String method, boolean withAuth) 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(tailApiUrl));
|
||||||
|
|
||||||
HttpURLConnection uc = (HttpURLConnection) getApiURL(ApiVersion.V2,tailApiUrl).openConnection();
|
|
||||||
|
|
||||||
if (withAuth && this.oauthAccessToken == null)
|
|
||||||
uc.setRequestProperty("Authorization", "Basic " + encodedAuthorization);
|
|
||||||
|
|
||||||
uc.setRequestMethod(method);
|
|
||||||
|
|
||||||
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) {
|
||||||
|
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(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 the authentication is needed but no credential is given, try it anyway (so that some calls
|
||||||
|
// that do work with anonymous access in the reduced form should still work.)
|
||||||
|
// if OAuth token is present, it'll be set in the URL, so need to set the Authorization header
|
||||||
|
if (withAuth && encodedAuthorization!=null && 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.
|
||||||
@@ -191,31 +334,55 @@ public class GitHub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw (IOException)new IOException(IOUtils.toString(uc.getErrorStream(),"UTF-8")).initCause(e);
|
if (e instanceof FileNotFoundException)
|
||||||
|
throw e; // pass through 404 Not Found to allow the caller to handle it intelligently
|
||||||
|
|
||||||
|
InputStream es = 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the object that represents the named user.
|
* Gets the current rate limit.
|
||||||
*/
|
*/
|
||||||
public GHUser getUser(String login) throws IOException {
|
public GHRateLimit getRateLimit() throws IOException {
|
||||||
GHUser u = users.get(login);
|
return retrieveWithAuth("/rate_limit", JsonRateLimit.class).rate;
|
||||||
if (u==null) {
|
|
||||||
|
|
||||||
if (oauthAccessToken != null) {
|
|
||||||
u = retrieve("/user/show",JsonUser.class).user;
|
|
||||||
u.root = this;
|
|
||||||
users.put(u.getLogin(),u);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
u = retrieve("/user/show/"+login,JsonUser.class).user;
|
|
||||||
u.root = this;
|
|
||||||
users.put(login,u);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return u;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link GHUser} that represents yourself.
|
||||||
|
*/
|
||||||
|
@WithBridgeMethods(GHUser.class)
|
||||||
|
public GHMyself getMyself() throws IOException {
|
||||||
|
requireCredential();
|
||||||
|
|
||||||
|
GHMyself u = retrieveWithAuth("/user", GHMyself.class);
|
||||||
|
|
||||||
|
u.root = this;
|
||||||
|
users.put(u.getLogin(), u);
|
||||||
|
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the object that represents the named user.
|
||||||
|
*/
|
||||||
|
public GHUser getUser(String login) throws IOException {
|
||||||
|
GHUser u = users.get(login);
|
||||||
|
if (u == null) {
|
||||||
|
u = retrieve("/users/" + login, GHUser.class);
|
||||||
|
u.root = this;
|
||||||
|
users.put(u.getLogin(), u);
|
||||||
|
}
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interns the given {@link GHUser}.
|
* Interns the given {@link GHUser}.
|
||||||
*/
|
*/
|
||||||
@@ -232,25 +399,55 @@ public class GitHub {
|
|||||||
public GHOrganization getOrganization(String name) throws IOException {
|
public GHOrganization getOrganization(String name) throws IOException {
|
||||||
GHOrganization o = orgs.get(name);
|
GHOrganization o = orgs.get(name);
|
||||||
if (o==null) {
|
if (o==null) {
|
||||||
o = retrieve("/organizations/"+name,JsonOrganization.class).organization;
|
o = retrieve("/orgs/" + name, GHOrganization.class).wrapUp(this);
|
||||||
o.root = this;
|
|
||||||
orgs.put(name,o);
|
orgs.put(name,o);
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, GHOrganization> getMyOrganizations() throws IOException {
|
|
||||||
return retrieveWithAuth("/organizations",JsonOrganizations.class).wrap(this);
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link GHUser} that represents yourself.
|
* Gets the repository object from 'user/reponame' string that GitHub calls as "repository name"
|
||||||
|
*
|
||||||
|
* @see GHRepository#getName()
|
||||||
*/
|
*/
|
||||||
public GHUser getMyself() throws IOException {
|
public GHRepository getRepository(String name) throws IOException {
|
||||||
requireCredential();
|
String[] tokens = name.split("/");
|
||||||
return getUser(login);
|
return getUser(tokens[0]).getRepository(tokens[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, GHOrganization> getMyOrganizations() throws IOException {
|
||||||
|
GHOrganization[] orgs = retrieveWithAuth("/user/orgs", GHOrganization[].class);
|
||||||
|
Map<String, GHOrganization> r = new HashMap<String, GHOrganization>();
|
||||||
|
for (GHOrganization o : orgs) {
|
||||||
|
r.put(o.name,o.wrapUp(this));
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public events visible to you. Equivalent of what's displayed on https://github.com/
|
||||||
|
*/
|
||||||
|
public List<GHEventInfo> getEvents() throws IOException {
|
||||||
|
// TODO: pagenation
|
||||||
|
GHEventInfo[] events = retrieve("/events", GHEventInfo[].class);
|
||||||
|
for (GHEventInfo e : events)
|
||||||
|
e.wrapUp(this);
|
||||||
|
return Arrays.asList(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the GitHub event object.
|
||||||
|
*
|
||||||
|
* This is primarily intended for receiving a POST HTTP call from a hook.
|
||||||
|
* Unfortunately, hook script payloads aren't self-descriptive, so you need
|
||||||
|
* to know the type of the payload you are expecting.
|
||||||
|
*/
|
||||||
|
public <T extends GHEventPayload> T parseEventPayload(Reader r, Class<T> type) throws IOException {
|
||||||
|
T t = MAPPER.readValue(r, type);
|
||||||
|
t.wrapUp(this);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new repository.
|
* Creates a new repository.
|
||||||
*
|
*
|
||||||
@@ -260,7 +457,7 @@ public class GitHub {
|
|||||||
public GHRepository createRepository(String name, String description, String homepage, boolean isPublic) throws IOException {
|
public GHRepository createRepository(String name, String description, String homepage, boolean isPublic) throws IOException {
|
||||||
return new Poster(this).withCredential()
|
return new Poster(this).withCredential()
|
||||||
.with("name", name).with("description", description).with("homepage", homepage)
|
.with("name", name).with("description", description).with("homepage", homepage)
|
||||||
.with("public", isPublic ? 1 : 0).to("/repos/create", JsonRepository.class).wrap(this);
|
.with("public", isPublic ? 1 : 0).to("/user/repos", GHRepository.class,"POST").wrap(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -268,7 +465,7 @@ public class GitHub {
|
|||||||
*/
|
*/
|
||||||
public boolean isCredentialValid() throws IOException {
|
public boolean isCredentialValid() throws IOException {
|
||||||
try {
|
try {
|
||||||
retrieveWithAuth("/user/show",JsonUser.class);
|
retrieveWithAuth("/user", GHUser.class);
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return false;
|
return false;
|
||||||
@@ -296,9 +493,12 @@ 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 {
|
||||||
return new SimpleDateFormat(f).parse(timestamp);
|
SimpleDateFormat df = new SimpleDateFormat(f);
|
||||||
|
df.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
|
return df.parse(timestamp);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
// try next
|
// try next
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2010, Kohsuke Kawaguchi
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonCollaborators {
|
|
||||||
List<String> collaborators;
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Eric Maupin
|
|
||||||
*/
|
|
||||||
class JsonIssue {
|
|
||||||
GHIssue issue;
|
|
||||||
|
|
||||||
GHIssue wrap(GHRepository r) {
|
|
||||||
issue.owner = r;
|
|
||||||
issue.root = r.root;
|
|
||||||
return issue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonIssueComments {
|
|
||||||
List<GHIssueComment> comments;
|
|
||||||
|
|
||||||
List<GHIssueComment> wrap(GHIssue owner) {
|
|
||||||
for (GHIssueComment c : comments)
|
|
||||||
c.owner = owner;
|
|
||||||
return comments;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
class JsonIssues {
|
|
||||||
List<GHIssue> issues;
|
|
||||||
|
|
||||||
public List<GHIssue> wrap(GHRepository owner) {
|
|
||||||
for (GHIssue issue : issues) {
|
|
||||||
issue.owner = owner;
|
|
||||||
issue.root = owner.root;
|
|
||||||
}
|
|
||||||
return issues;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2010, Kohsuke Kawaguchi
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class JsonOrganizations {
|
|
||||||
public List<GHOrganization> organizations;
|
|
||||||
|
|
||||||
public Map<String,GHOrganization> wrap(GitHub root) {
|
|
||||||
Map<String,GHOrganization> map = new TreeMap<String, GHOrganization>();
|
|
||||||
for (GHOrganization o : organizations) {
|
|
||||||
o.root = root;
|
|
||||||
map.put(o.getLogin(),o);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2010, Kohsuke Kawaguchi
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonPullRequest {
|
|
||||||
public GHPullRequest pull;
|
|
||||||
|
|
||||||
public GHPullRequest wrap(GHRepository owner) {
|
|
||||||
pull.owner = owner;
|
|
||||||
pull.root = owner.root;
|
|
||||||
return pull;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2010, Kohsuke Kawaguchi
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonPullRequests {
|
|
||||||
public List<GHPullRequest> pulls;
|
|
||||||
|
|
||||||
public List<GHPullRequest> wrap(GHRepository owner) {
|
|
||||||
for (GHPullRequest pull : pulls) {
|
|
||||||
pull.owner = owner;
|
|
||||||
pull.root = owner.root;
|
|
||||||
}
|
|
||||||
return pulls;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,6 @@ package org.kohsuke.github;
|
|||||||
/**
|
/**
|
||||||
* @author Kohsuke Kawaguchi
|
* @author Kohsuke Kawaguchi
|
||||||
*/
|
*/
|
||||||
class JsonOrganization {
|
class JsonRateLimit {
|
||||||
public GHOrganization organization;
|
GHRateLimit rate;
|
||||||
}
|
}
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2010, Kohsuke Kawaguchi
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonRepositories {
|
|
||||||
public List<GHRepository> repositories;
|
|
||||||
|
|
||||||
public Map<String,GHRepository> wrap(GitHub root) {
|
|
||||||
Map<String,GHRepository> map = new TreeMap<String, GHRepository>();
|
|
||||||
for (GHRepository r : repositories) {
|
|
||||||
r.root = root;
|
|
||||||
map.put(r.getName(),r);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2010, Kohsuke Kawaguchi
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonRepository {
|
|
||||||
public GHRepository repository;
|
|
||||||
|
|
||||||
public GHRepository wrap(GitHub root) {
|
|
||||||
repository.root = root;
|
|
||||||
return repository;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonTeam {
|
|
||||||
public GHTeam team;
|
|
||||||
|
|
||||||
GHTeam wrap(GHOrganization org) {
|
|
||||||
team.org = org;
|
|
||||||
return team;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonTeams {
|
|
||||||
public List<GHTeam> teams;
|
|
||||||
|
|
||||||
Map<String, GHTeam> toMap(GHOrganization org) {
|
|
||||||
Map<String, GHTeam> r = new TreeMap<String, GHTeam>();
|
|
||||||
for (GHTeam t : teams) {
|
|
||||||
t.org = org;
|
|
||||||
r.put(t.getName(),t);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<GHTeam> toSet(GHOrganization org) {
|
|
||||||
Set<GHTeam> r = new HashSet<GHTeam>();
|
|
||||||
for (GHTeam t : teams) {
|
|
||||||
t.org = org;
|
|
||||||
r.add(t);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2010, Kohsuke Kawaguchi
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonUser {
|
|
||||||
public GHUser user;
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2010, Kohsuke Kawaguchi
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonUsers {
|
|
||||||
public List<String> users;
|
|
||||||
|
|
||||||
public Set<GHUser> toSet(GitHub root) throws IOException {
|
|
||||||
Set<GHUser> r = new HashSet<GHUser>();
|
|
||||||
for (String u : users)
|
|
||||||
r.add(root.getUser(u));
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonUsersWithDetails {
|
|
||||||
public List<GHUser> users;
|
|
||||||
|
|
||||||
public Set<GHUser> toSet(GitHub root) throws IOException {
|
|
||||||
Set<GHUser> r = new HashSet<GHUser>();
|
|
||||||
for (GHUser u : users)
|
|
||||||
r.add(root.getUser(u));
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,13 +27,15 @@ import org.apache.commons.io.IOUtils;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.lang.reflect.Field;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URLEncoder;
|
import java.net.ProtocolException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.kohsuke.github.GitHub.*;
|
import static org.kohsuke.github.GitHub.*;
|
||||||
|
|
||||||
@@ -43,18 +45,21 @@ import static org.kohsuke.github.GitHub.*;
|
|||||||
*/
|
*/
|
||||||
class Poster {
|
class Poster {
|
||||||
private final GitHub root;
|
private final GitHub root;
|
||||||
private final List<String> args = new ArrayList<String>();
|
private final List<Entry> args = new ArrayList<Entry>();
|
||||||
private boolean authenticate;
|
private boolean authenticate;
|
||||||
|
|
||||||
private final ApiVersion v;
|
private static class Entry {
|
||||||
|
String key;
|
||||||
|
Object value;
|
||||||
|
|
||||||
Poster(GitHub root, ApiVersion v) {
|
private Entry(String key, Object value) {
|
||||||
this.root = root;
|
this.key = key;
|
||||||
this.v = v;
|
this.value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Poster(GitHub root) {
|
Poster(GitHub root) {
|
||||||
this(root,ApiVersion.V2);
|
this.root = root;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Poster withCredential() {
|
public Poster withCredential() {
|
||||||
@@ -64,16 +69,30 @@ class Poster {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Poster with(String key, int value) {
|
public Poster with(String key, int value) {
|
||||||
return with(key,String.valueOf(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) {
|
||||||
|
return _with(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Poster with(String key, String value) {
|
public Poster with(String key, String value) {
|
||||||
|
return _with(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Poster with(String key, Collection<String> value) {
|
||||||
|
return _with(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Poster _with(String key, Object value) {
|
||||||
if (value!=null) {
|
if (value!=null) {
|
||||||
try {
|
args.add(new Entry(key,value));
|
||||||
args.add(URLEncoder.encode(key,"UTF-8")+'='+URLEncoder.encode(value,"UTF-8"));
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new Error(e); // impossible
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -96,39 +115,46 @@ class Poster {
|
|||||||
|
|
||||||
public <T> T to(String tailApiUrl, Class<T> type, String method) throws IOException {
|
public <T> T to(String tailApiUrl, Class<T> type, String method) throws IOException {
|
||||||
while (true) {// loop while API rate limit is hit
|
while (true) {// loop while API rate limit is hit
|
||||||
HttpURLConnection uc = (HttpURLConnection) root.getApiURL(v,tailApiUrl).openConnection();
|
HttpURLConnection uc = (HttpURLConnection) root.getApiURL(tailApiUrl).openConnection();
|
||||||
|
|
||||||
uc.setDoOutput(true);
|
uc.setDoOutput(true);
|
||||||
uc.setRequestProperty("Content-type","application/x-www-form-urlencoded");
|
uc.setRequestProperty("Content-type","application/x-www-form-urlencoded");
|
||||||
if (authenticate) {
|
if (authenticate) {
|
||||||
if (v==ApiVersion.V3) {
|
if (root.oauthAccessToken!=null) {
|
||||||
|
uc.setRequestProperty("Authorization", "token " + root.oauthAccessToken);
|
||||||
|
} else {
|
||||||
if (root.password==null)
|
if (root.password==null)
|
||||||
throw new IllegalArgumentException("V3 API doesn't support API token");
|
throw new IllegalArgumentException("V3 API doesn't support API token");
|
||||||
uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization);
|
uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization);
|
||||||
} else {
|
|
||||||
uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uc.setRequestMethod(method);
|
try {
|
||||||
|
uc.setRequestMethod(method);
|
||||||
|
} catch (ProtocolException e) {
|
||||||
StringBuilder body = new StringBuilder();
|
// JDK only allows one of the fixed set of verbs. Try to override that
|
||||||
for (String e : args) {
|
try {
|
||||||
if (body.length()>0) body.append('&');
|
Field $method = HttpURLConnection.class.getDeclaredField("method");
|
||||||
body.append(e);
|
$method.setAccessible(true);
|
||||||
|
$method.set(uc,method);
|
||||||
|
} catch (Exception x) {
|
||||||
|
throw (IOException)new IOException("Failed to set the custom verb").initCause(x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputStreamWriter o = new OutputStreamWriter(uc.getOutputStream(), "UTF-8");
|
|
||||||
o.write(body.toString());
|
Map json = new HashMap();
|
||||||
o.close();
|
for (Entry e : args) {
|
||||||
|
json.put(e.key, e.value);
|
||||||
|
}
|
||||||
|
MAPPER.writeValue(uc.getOutputStream(),json);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8");
|
InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8");
|
||||||
|
String data = IOUtils.toString(r);
|
||||||
if (type==null) {
|
if (type==null) {
|
||||||
String data = IOUtils.toString(r);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return MAPPER.readValue(r,type);
|
return MAPPER.readValue(data,type);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
root.handleApiError(e,uc);
|
root.handleApiError(e,uc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +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.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;
|
||||||
import org.kohsuke.github.GHOrganization.Permission;
|
import org.kohsuke.github.GHOrganization.Permission;
|
||||||
import org.kohsuke.github.GHPullRequest;
|
|
||||||
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.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.
|
||||||
@@ -22,6 +36,46 @@ public class AppTest extends TestCase {
|
|||||||
assertFalse(GitHub.connect("totally","bogus").isCredentialValid());
|
assertFalse(GitHub.connect("totally","bogus").isCredentialValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testRateLimit() throws IOException {
|
||||||
|
System.out.println(GitHub.connect().getRateLimit());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFetchPullRequest() throws Exception {
|
||||||
|
GitHub gh = GitHub.connect();
|
||||||
|
GHRepository r = gh.getOrganization("jenkinsci").getRepository("jenkins");
|
||||||
|
assertEquals("master",r.getMasterBranch());
|
||||||
|
r.getPullRequest(1);
|
||||||
|
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"));
|
||||||
@@ -38,9 +92,93 @@ public class AppTest extends TestCase {
|
|||||||
Set<String> members = gitHub.getOrganization("jenkinsci").getRepository("violations-plugin").getCollaboratorNames();
|
Set<String> members = gitHub.getOrganization("jenkinsci").getRepository("violations-plugin").getCollaboratorNames();
|
||||||
System.out.println(members.contains("kohsuke"));
|
System.out.println(members.contains("kohsuke"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testMemberOrgs() throws Exception {
|
||||||
|
GitHub gitHub = GitHub.connect();
|
||||||
|
Set<GHOrganization> o = gitHub.getUser("kohsuke").getOrganizations();
|
||||||
|
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 testCreateCommitComment() 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");
|
||||||
|
GHHook hook = r.createWebHook(new URL("http://www.google.com/"));
|
||||||
|
System.out.println(hook);
|
||||||
|
|
||||||
|
for (GHHook h : r.getHooks())
|
||||||
|
h.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEventApi() throws Exception {
|
||||||
|
GitHub gitHub = GitHub.connect();
|
||||||
|
for (GHEventInfo ev : gitHub.getEvents()) {
|
||||||
|
System.out.println(ev);
|
||||||
|
if (ev.getType()==GHEvent.PULL_REQUEST) {
|
||||||
|
GHEventPayload.PullRequest pr = ev.getPayload(GHEventPayload.PullRequest.class);
|
||||||
|
System.out.println(pr.getNumber());
|
||||||
|
System.out.println(pr.getPullRequest());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void testApp() throws IOException {
|
public void testApp() throws IOException {
|
||||||
GitHub gitHub = GitHub.connect();
|
GitHub gitHub = GitHub.connect();
|
||||||
|
System.out.println(gitHub.getMyself().getEmails());
|
||||||
|
|
||||||
|
// GHRepository r = gitHub.connect().getOrganization("jenkinsci").createRepository("kktest4", "Kohsuke's test", "http://kohsuke.org/", "Everyone", true);
|
||||||
|
// r.fork();
|
||||||
|
|
||||||
// tryDisablingIssueTrackers(gitHub);
|
// tryDisablingIssueTrackers(gitHub);
|
||||||
|
|
||||||
@@ -129,10 +267,22 @@ public class AppTest extends TestCase {
|
|||||||
System.out.println(hooks);
|
System.out.println(hooks);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testOrganization(GitHub gitHub) throws IOException {
|
public void testOrgRepositories() throws IOException {
|
||||||
GHOrganization labs = gitHub.getOrganization("HudsonLabs");
|
GitHub gitHub = GitHub.connect();
|
||||||
GHTeam t = labs.getTeams().get("Core Developers");
|
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");
|
||||||
|
GHTeam t = j.getTeams().get("Core Developers");
|
||||||
|
|
||||||
t.add(labs.getRepository("xyz"));
|
assertNotNull(j.getRepository("jenkins"));
|
||||||
|
|
||||||
|
// t.add(labs.getRepository("xyz"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
32
src/test/java/org/kohsuke/HookApp.java
Normal file
32
src/test/java/org/kohsuke/HookApp.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package org.kohsuke;
|
||||||
|
|
||||||
|
import org.kohsuke.github.GHEventPayload;
|
||||||
|
import org.kohsuke.github.GitHub;
|
||||||
|
import org.kohsuke.stapler.StaplerRequest;
|
||||||
|
import org.kohsuke.stapler.jetty.JettyRunner;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App to test the hook script. You need some internet-facing server that can forward the request to you
|
||||||
|
* (typically via SSH reverse port forwarding.)
|
||||||
|
*
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public class HookApp {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// GitHub.connect().getMyself().getRepository("sandbox").createWebHook(
|
||||||
|
// new URL("http://173.203.118.45:18080/"), EnumSet.of(GHEvent.PULL_REQUEST));
|
||||||
|
JettyRunner jr = new JettyRunner(new HookApp());
|
||||||
|
jr.addHttpListener(8080);
|
||||||
|
jr.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doIndex(StaplerRequest req) throws IOException {
|
||||||
|
String str = req.getParameter("payload");
|
||||||
|
System.out.println(str);
|
||||||
|
GHEventPayload.PullRequest o = GitHub.connect().parseEventPayload(new StringReader(str),GHEventPayload.PullRequest.class);
|
||||||
|
System.out.println(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user