mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-11 08:21:23 +00:00
Compare commits
102 Commits
github-api
...
github-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1837699d8c | ||
|
|
2ef5dec466 | ||
|
|
a46c7acbd2 | ||
|
|
769d645237 | ||
|
|
389330df2e | ||
|
|
9d75913005 | ||
|
|
887ca772e0 | ||
|
|
45286598aa | ||
|
|
2e074b5bc4 | ||
|
|
560e3c257a | ||
|
|
6e0202fa0b | ||
|
|
ef241b1a07 | ||
|
|
f80cb541d5 | ||
|
|
1fe61f72e2 | ||
|
|
bf1b0edfd2 | ||
|
|
f0ab946b88 | ||
|
|
975ef1a43d | ||
|
|
7064865157 | ||
|
|
3dd738b0db | ||
|
|
6480dde247 | ||
|
|
555dab7403 | ||
|
|
13158a28e1 | ||
|
|
cbaca87bbc | ||
|
|
5166202f67 | ||
|
|
35d45ca47d | ||
|
|
b66ede98c7 | ||
|
|
1ba8f2ccbf | ||
|
|
82133c117a | ||
|
|
f71afca828 | ||
|
|
87f5231c9a | ||
|
|
b17f506c20 | ||
|
|
7f15f12668 | ||
|
|
e53e62bfa0 | ||
|
|
2e74517a4a | ||
|
|
aed888051e | ||
|
|
bd584124bb | ||
|
|
e658a7fa6b | ||
|
|
52108707bb | ||
|
|
0e226a8f78 | ||
|
|
1bf3e025b8 | ||
|
|
a0fdcca129 | ||
|
|
3e75e96718 | ||
|
|
1dd875adac | ||
|
|
2341f789ab | ||
|
|
8a95847b0a | ||
|
|
ea9f3eacbc | ||
|
|
435363a246 | ||
|
|
b6520cb6f9 | ||
|
|
d6d73f5165 | ||
|
|
f58dbceec7 | ||
|
|
3f1bb1a214 | ||
|
|
892d2acaa2 | ||
|
|
4e27d1b5a0 | ||
|
|
fff3272e42 | ||
|
|
803198620d | ||
|
|
9017fe70d5 | ||
|
|
ce47762fbf | ||
|
|
b40677a3ca | ||
|
|
c283c4e595 | ||
|
|
6aabaea96c | ||
|
|
65adb2f2b4 | ||
|
|
dcaf926a95 | ||
|
|
587278f282 | ||
|
|
cc3793cbcd | ||
|
|
c268a5dd07 | ||
|
|
58d10df5e3 | ||
|
|
ae2d01a878 | ||
|
|
dbc5b0b742 | ||
|
|
6af12c2335 | ||
|
|
dafb50d6a9 | ||
|
|
13c59b6618 | ||
|
|
8f95c4f179 | ||
|
|
9fd34aec7f | ||
|
|
17c7a3e7c5 | ||
|
|
40a8c110bf | ||
|
|
c9cd0a4d1f | ||
|
|
45eae77f8f | ||
|
|
926202900c | ||
|
|
21aa669503 | ||
|
|
dee28e7a7a | ||
|
|
c8f46a3666 | ||
|
|
ba7fe10a08 | ||
|
|
9e9db72878 | ||
|
|
69a87e2ab7 | ||
|
|
8ec2686e72 | ||
|
|
d034ca4d1f | ||
|
|
61cf71fd67 | ||
|
|
63dd1330e9 | ||
|
|
4411650c5a | ||
|
|
1c15751949 | ||
|
|
82acf4f107 | ||
|
|
5525ae8921 | ||
|
|
b5f7208b0d | ||
|
|
3b5bc98053 | ||
|
|
3a9ade667a | ||
|
|
057c32d410 | ||
|
|
33657c9c92 | ||
|
|
4c199256a5 | ||
|
|
9e62776905 | ||
|
|
9ba74b945d | ||
|
|
66656ce612 | ||
|
|
73a20ad829 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
target
|
target
|
||||||
|
.idea/
|
||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
*.iws
|
*.iws
|
||||||
|
|||||||
31
pom.xml
31
pom.xml
@@ -3,11 +3,11 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.kohsuke</groupId>
|
<groupId>org.kohsuke</groupId>
|
||||||
<artifactId>pom</artifactId>
|
<artifactId>pom</artifactId>
|
||||||
<version>3</version>
|
<version>4</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>github-api</artifactId>
|
<artifactId>github-api</artifactId>
|
||||||
<version>1.24</version>
|
<version>1.36</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>
|
||||||
@@ -44,16 +44,14 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jvnet.hudson</groupId>
|
<groupId>commons-lang</groupId>
|
||||||
<artifactId>htmlunit</artifactId>
|
<artifactId>commons-lang</artifactId>
|
||||||
<version>2.6-hudson-2</version>
|
<version>2.6</version>
|
||||||
<exclusions>
|
</dependency>
|
||||||
<exclusion>
|
<dependency>
|
||||||
<!-- hides JDK DOM classes in Eclipse -->
|
<groupId>commons-codec</groupId>
|
||||||
<groupId>xml-apis</groupId>
|
<artifactId>commons-codec</artifactId>
|
||||||
<artifactId>xml-apis</artifactId>
|
<version>1.7</version>
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
@@ -64,7 +62,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.codehaus.jackson</groupId>
|
<groupId>org.codehaus.jackson</groupId>
|
||||||
<artifactId>jackson-mapper-asl</artifactId>
|
<artifactId>jackson-mapper-asl</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.9.9</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-io</groupId>
|
<groupId>commons-io</groupId>
|
||||||
@@ -85,6 +83,13 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>repo.jenkins-ci.org</id>
|
||||||
|
<url>http://repo.jenkins-ci.org/public/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
<reporting>
|
<reporting>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Different API versions.
|
|
||||||
*
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
enum ApiVersion {
|
|
||||||
|
|
||||||
V2("https://?/api/v2/json"),
|
|
||||||
V3("https://api.?");
|
|
||||||
|
|
||||||
final String templateUrl;
|
|
||||||
|
|
||||||
ApiVersion(String templateUrl) {
|
|
||||||
this.templateUrl = templateUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getApiVersionBaseUrl(String githubServer) {
|
|
||||||
|
|
||||||
return templateUrl.replaceFirst("\\?", githubServer);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,8 +7,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.kohsuke.github.ApiVersion.V3;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A commit in a repository.
|
* A commit in a repository.
|
||||||
*
|
*
|
||||||
@@ -205,7 +203,7 @@ public class GHCommit {
|
|||||||
public PagedIterable<GHCommitComment> listComments() {
|
public PagedIterable<GHCommitComment> listComments() {
|
||||||
return new PagedIterable<GHCommitComment>() {
|
return new PagedIterable<GHCommitComment>() {
|
||||||
public PagedIterator<GHCommitComment> iterator() {
|
public PagedIterator<GHCommitComment> iterator() {
|
||||||
return new PagedIterator<GHCommitComment>(owner.root.retrievePaged(String.format("/repos/%s/%s/commits/%s/comments",owner.getOwnerName(),owner.getName(),sha),GHCommitComment[].class,false,V3)) {
|
return new PagedIterator<GHCommitComment>(owner.root.retrieve().asIterator(String.format("/repos/%s/%s/commits/%s/comments", owner.getOwnerName(), owner.getName(), sha), GHCommitComment[].class)) {
|
||||||
@Override
|
@Override
|
||||||
protected void wrapUp(GHCommitComment[] page) {
|
protected void wrapUp(GHCommitComment[] page) {
|
||||||
for (GHCommitComment c : page)
|
for (GHCommitComment c : page)
|
||||||
@@ -222,12 +220,11 @@ public class GHCommit {
|
|||||||
* I'm not sure how path/line/position parameters interact with each other.
|
* 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 {
|
public GHCommitComment createComment(String body, String path, Integer line, Integer position) throws IOException {
|
||||||
GHCommitComment r = new Poster(owner.root,V3)
|
GHCommitComment r = new Requester(owner.root)
|
||||||
.with("body",body)
|
.with("body",body)
|
||||||
.with("path",path)
|
.with("path",path)
|
||||||
.with("line",line)
|
.with("line",line)
|
||||||
.with("position",position)
|
.with("position",position)
|
||||||
.withCredential()
|
|
||||||
.to(String.format("/repos/%s/%s/commits/%s/comments",owner.getOwnerName(),owner.getName(),sha),GHCommitComment.class);
|
.to(String.format("/repos/%s/%s/commits/%s/comments",owner.getOwnerName(),owner.getName(),sha),GHCommitComment.class);
|
||||||
return r.wrap(owner);
|
return r.wrap(owner);
|
||||||
}
|
}
|
||||||
@@ -236,6 +233,20 @@ public class GHCommit {
|
|||||||
return createComment(body,null,null,null);
|
return createComment(body,null,null,null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the status of this commit, newer ones first.
|
||||||
|
*/
|
||||||
|
public PagedIterable<GHCommitStatus> listStatuses() throws IOException {
|
||||||
|
return owner.listCommitStatuses(sha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the last status of this commit, which is what gets shown in the UI.
|
||||||
|
*/
|
||||||
|
public GHCommitStatus getLastStatus() throws IOException {
|
||||||
|
return owner.getLastCommitStatus(sha);
|
||||||
|
}
|
||||||
|
|
||||||
GHCommit wrapUp(GHRepository owner) {
|
GHCommit wrapUp(GHRepository owner) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import java.io.IOException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import static org.kohsuke.github.ApiVersion.V3;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A comment attached to a commit (or a specific line in a specific file of a commit.)
|
* A comment attached to a commit (or a specific line in a specific file of a commit.)
|
||||||
*
|
*
|
||||||
@@ -99,10 +97,9 @@ public class GHCommitComment {
|
|||||||
* Updates the body of the commit message.
|
* Updates the body of the commit message.
|
||||||
*/
|
*/
|
||||||
public void update(String body) throws IOException {
|
public void update(String body) throws IOException {
|
||||||
GHCommitComment r = new Poster(owner.root,V3)
|
GHCommitComment r = new Requester(owner.root)
|
||||||
.with("body",body)
|
.with("body", body)
|
||||||
.withCredential()
|
.method("PATCH").to(getApiTail(), GHCommitComment.class);
|
||||||
.to(getApiTail(),GHCommitComment.class,"PATCH");
|
|
||||||
this.body = body;
|
this.body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +107,7 @@ public class GHCommitComment {
|
|||||||
* Deletes this comment.
|
* Deletes this comment.
|
||||||
*/
|
*/
|
||||||
public void delete() throws IOException {
|
public void delete() throws IOException {
|
||||||
new Poster(owner.root,V3).withCredential().to(getApiTail(),null,"DELETE");
|
new Requester(owner.root).method("DELETE").to(getApiTail());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getApiTail() {
|
private String getApiTail() {
|
||||||
|
|||||||
11
src/main/java/org/kohsuke/github/GHCommitState.java
Normal file
11
src/main/java/org/kohsuke/github/GHCommitState.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the state of commit
|
||||||
|
*
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
* @see GHCommitStatus
|
||||||
|
*/
|
||||||
|
public enum GHCommitState {
|
||||||
|
PENDING, SUCCESS, ERROR, FAILURE
|
||||||
|
}
|
||||||
72
src/main/java/org/kohsuke/github/GHCommitStatus.java
Normal file
72
src/main/java/org/kohsuke/github/GHCommitStatus.java
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a status of a commit.
|
||||||
|
*
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
* @see GHRepository#getCommitStatus(String)
|
||||||
|
* @see GHCommit#getStatus()
|
||||||
|
*/
|
||||||
|
public class GHCommitStatus {
|
||||||
|
String created_at, updated_at;
|
||||||
|
String state;
|
||||||
|
String target_url,description;
|
||||||
|
int id;
|
||||||
|
String url;
|
||||||
|
GHUser creator;
|
||||||
|
|
||||||
|
private GitHub root;
|
||||||
|
|
||||||
|
/*package*/ GHCommitStatus wrapUp(GitHub root) {
|
||||||
|
if (creator!=null) creator.wrapUp(root);
|
||||||
|
this.root = root;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return GitHub.parseDate(created_at);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdatedAt() {
|
||||||
|
return GitHub.parseDate(updated_at);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHCommitState getState() {
|
||||||
|
for (GHCommitState s : GHCommitState.values()) {
|
||||||
|
if (s.name().equalsIgnoreCase(state))
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Unexpected state: "+state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL that this status is linked to.
|
||||||
|
*
|
||||||
|
* This is the URL specified when creating a commit status.
|
||||||
|
*/
|
||||||
|
public String getTargetUrl() {
|
||||||
|
return target_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API URL of this commit status.
|
||||||
|
*/
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHUser getCreator() {
|
||||||
|
return creator;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,7 +54,6 @@ public final class GHHook {
|
|||||||
* Deletes this hook.
|
* Deletes this hook.
|
||||||
*/
|
*/
|
||||||
public void delete() throws IOException {
|
public void delete() throws IOException {
|
||||||
new Poster(repository.root,ApiVersion.V3).withCredential()
|
new Requester(repository.root).method("DELETE").to(String.format("/repos/%s/%s/hooks/%d", repository.getOwnerName(), repository.getName(), id));
|
||||||
.to(String.format("/repos/%s/%s/hooks/%d",repository.getOwnerName(),repository.getName(),id),null,"DELETE");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an issue on GitHub.
|
* Represents an issue on GitHub.
|
||||||
@@ -40,11 +41,38 @@ import java.util.List;
|
|||||||
public class GHIssue {
|
public class GHIssue {
|
||||||
GitHub root;
|
GitHub root;
|
||||||
GHRepository owner;
|
GHRepository owner;
|
||||||
|
|
||||||
|
// API v3
|
||||||
|
protected GHUser assignee;
|
||||||
|
protected String state;
|
||||||
|
protected int number;
|
||||||
|
protected String closed_at;
|
||||||
|
protected int comments;
|
||||||
|
protected String body;
|
||||||
|
protected List<String> labels;
|
||||||
|
protected GHUser user;
|
||||||
|
protected String title, created_at, html_url;
|
||||||
|
protected GHIssue.PullRequest pull_request;
|
||||||
|
protected GHMilestone milestone;
|
||||||
|
protected String url, updated_at;
|
||||||
|
protected int id;
|
||||||
|
protected GHUser closed_by;
|
||||||
|
|
||||||
private String gravatar_id,body,title,state,created_at,updated_at,html_url;
|
/*package*/ GHIssue wrap(GHRepository owner) {
|
||||||
private List<String> labels;
|
this.owner = owner;
|
||||||
private int number,votes,comments;
|
this.root = owner.root;
|
||||||
private int position;
|
if(milestone != null) milestone.wrap(owner);
|
||||||
|
if(assignee != null) assignee.wrapUp(root);
|
||||||
|
if(user != null) user.wrapUp(root);
|
||||||
|
if(closed_by != null) closed_by.wrapUp(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.
|
||||||
@@ -80,10 +108,13 @@ public class GHIssue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GHIssueState getState() {
|
public GHIssueState getState() {
|
||||||
return Enum.valueOf(GHIssueState.class, state);
|
return Enum.valueOf(GHIssueState.class, state.toUpperCase(Locale.ENGLISH));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<String> getLabels() {
|
public Collection<String> getLabels() {
|
||||||
|
if(labels == null){
|
||||||
|
return Collections.EMPTY_LIST;
|
||||||
|
}
|
||||||
return Collections.unmodifiableList(labels);
|
return Collections.unmodifiableList(labels);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,35 +126,128 @@ public class GHIssue {
|
|||||||
return GitHub.parseDate(updated_at);
|
return GitHub.parseDate(updated_at);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Date getClosedAt() {
|
||||||
|
return GitHub.parseDate(closed_at);
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getApiURL(){
|
||||||
|
return GitHub.parseURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 Requester(root).with("body",message).to(getApiRoute() + "/comments");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void edit(String key, Object value) throws IOException {
|
||||||
|
new Requester(root)._with(key, value).method("PATCH").to(getApiRoute());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
*
|
||||||
|
* @see #listComments()
|
||||||
*/
|
*/
|
||||||
public List<GHIssueComment> getComments() throws IOException {
|
public List<GHIssueComment> getComments() throws IOException {
|
||||||
return root.retrieve(getApiRoute("comments"), JsonIssueComments.class).wrap(this);
|
return listComments().asList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains all the comments associated with this issue.
|
||||||
|
*/
|
||||||
|
public PagedIterable<GHIssueComment> listComments() throws IOException {
|
||||||
|
return new PagedIterable<GHIssueComment>() {
|
||||||
|
public PagedIterator<GHIssueComment> iterator() {
|
||||||
|
return new PagedIterator<GHIssueComment>(root.retrieve().asIterator(getApiRoute() + "/comments", GHIssueComment[].class)) {
|
||||||
|
protected void wrapUp(GHIssueComment[] page) {
|
||||||
|
for (GHIssueComment c : page)
|
||||||
|
c.wrapUp(GHIssue.this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getApiRoute(String verb) {
|
private String getApiRoute() {
|
||||||
return "/issues/"+verb+"/"+owner.getOwnerName()+"/"+owner.getName()+"/"+number;
|
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GHUser getAssignee() {
|
||||||
|
return assignee;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User who submitted the issue.
|
||||||
|
*/
|
||||||
|
public GHUser getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHUser getClosedBy() {
|
||||||
|
if(!"closed".equals(state)) return null;
|
||||||
|
if(closed_by != null) return closed_by;
|
||||||
|
|
||||||
|
//TODO closed_by = owner.getIssue(number).getClosed_by();
|
||||||
|
return closed_by;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCommentsCount(){
|
||||||
|
return comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PullRequest getPullRequest() {
|
||||||
|
return pull_request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHMilestone getMilestone() {
|
||||||
|
return milestone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PullRequest{
|
||||||
|
private String diff_url, patch_url, html_url;
|
||||||
|
|
||||||
|
public URL getDiffUrl() {
|
||||||
|
return GitHub.parseURL(diff_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getPatchUrl() {
|
||||||
|
return GitHub.parseURL(patch_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getUrl() {
|
||||||
|
return GitHub.parseURL(html_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
59
src/main/java/org/kohsuke/github/GHIssueBuilder.java
Normal file
59
src/main/java/org/kohsuke/github/GHIssueBuilder.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
public class GHIssueBuilder {
|
||||||
|
private final GHRepository repo;
|
||||||
|
private final Requester builder;
|
||||||
|
private List<String> labels = new ArrayList<String>();
|
||||||
|
|
||||||
|
GHIssueBuilder(GHRepository repo, String title) {
|
||||||
|
this.repo = repo;
|
||||||
|
this.builder = new Requester(repo.root);
|
||||||
|
builder.with("title",title);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the main text of an issue, which is arbitrary multi-line text.
|
||||||
|
*/
|
||||||
|
public GHIssueBuilder body(String str) {
|
||||||
|
builder.with("body",str);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHIssueBuilder assignee(GHUser user) {
|
||||||
|
if (user!=null)
|
||||||
|
builder.with("assignee",user.getLogin());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHIssueBuilder assignee(String user) {
|
||||||
|
if (user!=null)
|
||||||
|
builder.with("assignee",user);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHIssueBuilder milestone(GHMilestone milestone) {
|
||||||
|
if (milestone!=null)
|
||||||
|
builder.with("milestone",milestone.getNumber());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHIssueBuilder label(String label) {
|
||||||
|
if (label!=null)
|
||||||
|
labels.add(label);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new issue.
|
||||||
|
*/
|
||||||
|
public GHIssue create() throws IOException {
|
||||||
|
return builder.with("labels",labels).to(repo.getApiTailUrl("issues"),GHIssue.class).wrap(repo);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,8 +35,15 @@ import java.util.Date;
|
|||||||
public class GHIssueComment {
|
public class GHIssueComment {
|
||||||
GHIssue owner;
|
GHIssue owner;
|
||||||
|
|
||||||
private String body, gravatar_id, user, created_at, updated_at;
|
private String body, gravatar_id, created_at, updated_at;
|
||||||
|
private URL url;
|
||||||
private int id;
|
private int id;
|
||||||
|
private GHUser user;
|
||||||
|
|
||||||
|
/*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.
|
||||||
@@ -63,17 +71,22 @@ public class GHIssueComment {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public URL getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the ID of the user who posted this comment.
|
* Gets the ID of the user who posted this comment.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String getUserName() {
|
public String getUserName() {
|
||||||
return user;
|
return user.getLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the user who posted this comment.
|
* Gets the user who posted this comment.
|
||||||
*/
|
*/
|
||||||
public GHUser getUser() throws IOException {
|
public GHUser getUser() throws IOException {
|
||||||
return owner.root.getUser(user);
|
return owner.root.getUser(user.getLogin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.kohsuke.github;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -23,7 +22,7 @@ public class GHMyself extends GHUser {
|
|||||||
* Always non-null.
|
* Always non-null.
|
||||||
*/
|
*/
|
||||||
public List<String> getEmails() throws IOException {
|
public List<String> getEmails() throws IOException {
|
||||||
String[] addresses = root.retrieveWithAuth3("/user/emails",String[].class);
|
String[] addresses = root.retrieve().to("/user/emails", String[].class);
|
||||||
return Collections.unmodifiableList(Arrays.asList(addresses));
|
return Collections.unmodifiableList(Arrays.asList(addresses));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,11 +33,11 @@ public class GHMyself extends GHUser {
|
|||||||
* Always non-null.
|
* Always non-null.
|
||||||
*/
|
*/
|
||||||
public List<GHKey> getPublicKeys() throws IOException {
|
public List<GHKey> getPublicKeys() throws IOException {
|
||||||
return Collections.unmodifiableList(Arrays.asList(root.retrieveWithAuth3("/user/keys",GHKey[].class)));
|
return Collections.unmodifiableList(Arrays.asList(root.retrieve().to("/user/keys", GHKey[].class)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void addEmails(Collection<String> emails) throws IOException {
|
// public void addEmails(Collection<String> emails) throws IOException {
|
||||||
//// new Poster(root,ApiVersion.V3).withCredential().to("/user/emails");
|
//// new Requester(root,ApiVersion.V3).withCredential().to("/user/emails");
|
||||||
// root.retrieveWithAuth3()
|
// root.retrieveWithAuth3()
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import com.gargoylesoftware.htmlunit.WebClient;
|
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
|
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -12,13 +7,16 @@ 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;
|
||||||
import static org.kohsuke.github.ApiVersion.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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.
|
||||||
*
|
*
|
||||||
@@ -31,7 +29,7 @@ public class GHOrganization extends GHPerson {
|
|||||||
|
|
||||||
public GHRepository createRepository(String name, String description, String homepage, GHTeam team, boolean isPublic) throws IOException {
|
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
|
||||||
return new Poster(root,V3).withCredential()
|
return new Requester(root)
|
||||||
.with("name", name).with("description", description).with("homepage", homepage)
|
.with("name", name).with("description", description).with("homepage", homepage)
|
||||||
.with("public", isPublic).with("team_id",team.getId()).to("/orgs/"+login+"/repos", GHRepository.class).wrap(root);
|
.with("public", isPublic).with("team_id",team.getId()).to("/orgs/"+login+"/repos", GHRepository.class).wrap(root);
|
||||||
}
|
}
|
||||||
@@ -40,15 +38,35 @@ public class GHOrganization extends GHPerson {
|
|||||||
* 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.retrieve().to("/orgs/" + login + "/teams", GHTeam[].class);
|
||||||
|
Map<String,GHTeam> r = new TreeMap<String, GHTeam>();
|
||||||
|
for (GHTeam t : teams) {
|
||||||
|
r.put(t.getName(),t.wrapUp(this));
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public GHRepository getRepository(String name) throws IOException {
|
* Checks if this organization has the specified user as a member.
|
||||||
|
*/
|
||||||
|
public boolean hasMember(GHUser user) {
|
||||||
try {
|
try {
|
||||||
return root.retrieveWithAuth3("/repos/" + login + '/' + name, GHRepository.class).wrap(root);
|
root.retrieve().to("/orgs/" + login + "/members/" + user.getLogin());
|
||||||
} catch (FileNotFoundException e) {
|
return true;
|
||||||
return null;
|
} catch (IOException ignore) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this organization has the specified user as a public member.
|
||||||
|
*/
|
||||||
|
public boolean hasPublicMember(GHUser user) {
|
||||||
|
try {
|
||||||
|
root.retrieve().to("/orgs/" + login + "/public_members/" + user.getLogin());
|
||||||
|
return true;
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +74,7 @@ public class GHOrganization extends GHPerson {
|
|||||||
* Publicizes the membership.
|
* Publicizes the membership.
|
||||||
*/
|
*/
|
||||||
public void publicize(GHUser u) throws IOException {
|
public void publicize(GHUser u) throws IOException {
|
||||||
root.retrieveWithAuth3("/orgs/" + login + "/public_members/" + u.getLogin(), null, "PUT");
|
root.retrieve().method("PUT").to("/orgs/" + login + "/public_members/" + u.getLogin(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,7 +84,7 @@ public class GHOrganization extends GHPerson {
|
|||||||
return new AbstractList<GHUser>() {
|
return new AbstractList<GHUser>() {
|
||||||
// these are shallow objects with only some limited values filled out
|
// 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
|
// TODO: it's better to allow objects to fill themselves in later when missing values are requested
|
||||||
final GHUser[] shallow = root.retrieveWithAuth3("/orgs/" + login + "/members", GHUser[].class);
|
final GHUser[] shallow = root.retrieve().to("/orgs/" + login + "/members", GHUser[].class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GHUser get(int index) {
|
public GHUser get(int index) {
|
||||||
@@ -88,7 +106,7 @@ public class GHOrganization extends GHPerson {
|
|||||||
* Conceals the membership.
|
* Conceals the membership.
|
||||||
*/
|
*/
|
||||||
public void conceal(GHUser u) throws IOException {
|
public void conceal(GHUser u) throws IOException {
|
||||||
root.retrieveWithAuth3("/orgs/" + login + "/public_members/" + u.getLogin(), null, "DELETE");
|
root.retrieve().method("DELETE").to("/orgs/" + login + "/public_members/" + u.getLogin(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Permission { ADMIN, PUSH, PULL }
|
public enum Permission { ADMIN, PUSH, PULL }
|
||||||
@@ -97,11 +115,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());
|
Requester post = new Requester(root).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.method("POST").to("/orgs/" + login + "/teams", GHTeam.class).wrapUp(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GHTeam createTeam(String name, Permission p, GHRepository... repositories) throws IOException {
|
public GHTeam createTeam(String name, Permission p, GHRepository... repositories) throws IOException {
|
||||||
@@ -112,13 +132,12 @@ public class GHOrganization extends GHPerson {
|
|||||||
* List up repositories that has some open pull requests.
|
* List up repositories that has some open pull requests.
|
||||||
*/
|
*/
|
||||||
public List<GHRepository> getRepositoriesWithOpenPullRequests() throws IOException {
|
public List<GHRepository> getRepositoriesWithOpenPullRequests() throws IOException {
|
||||||
WebClient wc = root.createWebClient();
|
|
||||||
HtmlPage pg = (HtmlPage)wc.getPage("https://github.com/organizations/"+login+"/dashboard/pulls");
|
|
||||||
List<GHRepository> r = new ArrayList<GHRepository>();
|
List<GHRepository> r = new ArrayList<GHRepository>();
|
||||||
for (HtmlAnchor e : pg.getElementById("js-issue-list").<HtmlAnchor>selectNodes(".//UL[@class='smallnav']/LI[not(@class='zeroed')]/A")) {
|
for (GHRepository repository : root.retrieve().to("/orgs/" + login + "/repos", GHRepository[].class)) {
|
||||||
String a = e.getHrefAttribute();
|
List<GHPullRequest> pullRequests = repository.getPullRequests(GHIssueState.OPEN);
|
||||||
String name = a.substring(a.lastIndexOf('/')+1);
|
if (pullRequests.size() > 0) {
|
||||||
r.add(getRepository(name));
|
r.add(repository);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -11,8 +9,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import static org.kohsuke.github.ApiVersion.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common part of {@link GHUser} and {@link GHOrganization}.
|
* Common part of {@link GHUser} and {@link GHOrganization}.
|
||||||
*
|
*
|
||||||
@@ -21,18 +17,31 @@ import static org.kohsuke.github.ApiVersion.*;
|
|||||||
public abstract class GHPerson {
|
public abstract class GHPerson {
|
||||||
/*package almost final*/ GitHub root;
|
/*package almost final*/ GitHub root;
|
||||||
|
|
||||||
// common
|
// core data fields that exist even for "small" user data (such as the user info in pull request)
|
||||||
protected String login,location,blog,email,name,created_at,company;
|
protected String login, avatar_url, url, gravatar_id;
|
||||||
protected int id;
|
protected int id;
|
||||||
protected String gravatar_id; // appears in V3 as well but presumably subsumed by avatar_url?
|
|
||||||
|
|
||||||
// V2
|
// other fields (that only show up in full data)
|
||||||
protected int public_gist_count,public_repo_count,followers_count,following_count;
|
protected String location,blog,email,name,created_at,company;
|
||||||
|
protected String html_url;
|
||||||
// V3
|
|
||||||
protected String avatar_url,html_url;
|
|
||||||
protected int followers,following,public_repos,public_gists;
|
protected int followers,following,public_repos,public_gists;
|
||||||
|
|
||||||
|
/*package*/ GHPerson wrapUp(GitHub root) {
|
||||||
|
this.root = root;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fully populate the data by retrieving missing data.
|
||||||
|
*
|
||||||
|
* Depending on the original API call where this object is created, it may not contain everything.
|
||||||
|
*/
|
||||||
|
protected void populate() throws IOException {
|
||||||
|
if (created_at!=null) return; // already populated
|
||||||
|
|
||||||
|
root.retrieve().to(url, this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the repositories this user owns.
|
* Gets the repositories this user owns.
|
||||||
*/
|
*/
|
||||||
@@ -58,7 +67,7 @@ public abstract class GHPerson {
|
|||||||
public synchronized Iterable<List<GHRepository>> iterateRepositories(final int pageSize) {
|
public synchronized Iterable<List<GHRepository>> iterateRepositories(final int pageSize) {
|
||||||
return new Iterable<List<GHRepository>>() {
|
return new Iterable<List<GHRepository>>() {
|
||||||
public Iterator<List<GHRepository>> iterator() {
|
public Iterator<List<GHRepository>> iterator() {
|
||||||
final Iterator<GHRepository[]> pager = root.retrievePaged("/users/" + login + "/repos?per_page="+pageSize,GHRepository[].class,false, V3);
|
final Iterator<GHRepository[]> pager = root.retrieve().asIterator("/users/" + login + "/repos?per_page="+pageSize,GHRepository[].class);
|
||||||
|
|
||||||
return new Iterator<List<GHRepository>>() {
|
return new Iterator<List<GHRepository>>() {
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
@@ -87,7 +96,7 @@ public abstract class GHPerson {
|
|||||||
*/
|
*/
|
||||||
public GHRepository getRepository(String name) throws IOException {
|
public GHRepository getRepository(String name) throws IOException {
|
||||||
try {
|
try {
|
||||||
return root.retrieve3("/repos/" + login + '/' + name, GHRepository.class).wrap(root);
|
return root.retrieve().to("/repos/" + login + '/' + name, GHRepository.class).wrap(root);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -125,52 +134,61 @@ public abstract class GHPerson {
|
|||||||
/**
|
/**
|
||||||
* Gets the human-readable name of the user, like "Kohsuke Kawaguchi"
|
* Gets the human-readable name of the user, like "Kohsuke Kawaguchi"
|
||||||
*/
|
*/
|
||||||
public String getName() {
|
public String getName() throws IOException {
|
||||||
|
populate();
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the company name of this user, like "Sun Microsystems, Inc."
|
* Gets the company name of this user, like "Sun Microsystems, Inc."
|
||||||
*/
|
*/
|
||||||
public String getCompany() {
|
public String getCompany() throws IOException {
|
||||||
|
populate();
|
||||||
return company;
|
return company;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the location of this user, like "Santa Clara, California"
|
* Gets the location of this user, like "Santa Clara, California"
|
||||||
*/
|
*/
|
||||||
public String getLocation() {
|
public String getLocation() throws IOException {
|
||||||
|
populate();
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCreatedAt() {
|
public String getCreatedAt() throws IOException {
|
||||||
|
populate();
|
||||||
return created_at;
|
return created_at;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the blog URL of this user.
|
* Gets the blog URL of this user.
|
||||||
*/
|
*/
|
||||||
public String getBlog() {
|
public String getBlog() throws IOException {
|
||||||
|
populate();
|
||||||
return blog;
|
return blog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the e-mail address of the user.
|
* Gets the e-mail address of the user.
|
||||||
*/
|
*/
|
||||||
public String getEmail() {
|
public String getEmail() throws IOException {
|
||||||
|
populate();
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPublicGistCount() {
|
public int getPublicGistCount() throws IOException {
|
||||||
return Math.max(public_gist_count,public_gists);
|
populate();
|
||||||
|
return public_gists;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPublicRepoCount() {
|
public int getPublicRepoCount() throws IOException {
|
||||||
return Math.max(public_repo_count,public_repos);
|
populate();
|
||||||
|
return public_repos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFollowingCount() {
|
public int getFollowingCount() throws IOException {
|
||||||
return Math.max(following_count,following);
|
populate();
|
||||||
|
return following;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,8 +198,9 @@ public abstract class GHPerson {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFollowersCount() {
|
public int getFollowersCount() throws IOException {
|
||||||
return Math.max(followers_count,followers);
|
populate();
|
||||||
|
return followers;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
@@ -16,6 +17,10 @@ public final class GHPersonSet<T extends GHPerson> extends HashSet<T> {
|
|||||||
super(c);
|
super(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GHPersonSet(T... c) {
|
||||||
|
super(Arrays.asList(c));
|
||||||
|
}
|
||||||
|
|
||||||
public GHPersonSet(int initialCapacity, float loadFactor) {
|
public GHPersonSet(int initialCapacity, float loadFactor) {
|
||||||
super(initialCapacity, loadFactor);
|
super(initialCapacity, loadFactor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,12 +35,35 @@ import java.util.Date;
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings({"UnusedDeclaration"})
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
public class GHPullRequest extends GHIssue {
|
public class GHPullRequest extends GHIssue {
|
||||||
private String closed_at, patch_url, issue_updated_at;
|
|
||||||
private GHUser issue_user, user;
|
private String patch_url, diff_url, issue_url;
|
||||||
// labels??
|
private GHCommitPointer base;
|
||||||
private GHCommitPointer base, head;
|
private String merged_at;
|
||||||
private String mergeable, diff_url;
|
private GHCommitPointer head;
|
||||||
|
|
||||||
|
// details that are only available when obtained from ID
|
||||||
|
private GHUser merged_by;
|
||||||
|
private int review_comments, additions;
|
||||||
|
private boolean merged;
|
||||||
|
private Boolean mergeable;
|
||||||
|
private int deletions;
|
||||||
|
private String mergeable_state;
|
||||||
|
private int changed_files;
|
||||||
|
|
||||||
|
|
||||||
|
GHPullRequest wrapUp(GHRepository owner) {
|
||||||
|
this.wrap(owner);
|
||||||
|
return wrapUp(owner.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
GHPullRequest wrapUp(GitHub root) {
|
||||||
|
if (owner!=null) owner.wrap(root);
|
||||||
|
if (base!=null) base.wrapUp(root);
|
||||||
|
if (head!=null) head.wrapUp(root);
|
||||||
|
if (merged_by != null) merged_by.wrapUp(root);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The URL of the patch file.
|
* The URL of the patch file.
|
||||||
* like https://github.com/jenkinsci/jenkins/pull/100.patch
|
* like https://github.com/jenkinsci/jenkins/pull/100.patch
|
||||||
@@ -46,12 +71,13 @@ public class GHPullRequest extends GHIssue {
|
|||||||
public URL getPatchUrl() {
|
public URL getPatchUrl() {
|
||||||
return GitHub.parseURL(patch_url);
|
return GitHub.parseURL(patch_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User who submitted a pull request.
|
* The URL of the patch file.
|
||||||
|
* like https://github.com/jenkinsci/jenkins/pull/100.patch
|
||||||
*/
|
*/
|
||||||
public GHUser getUser() {
|
public URL getIssueUrl() {
|
||||||
return user;
|
return GitHub.parseURL(issue_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,16 +95,9 @@ public class GHPullRequest extends GHIssue {
|
|||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public Date getIssueUpdatedAt() {
|
public Date getIssueUpdatedAt() {
|
||||||
return GitHub.parseDate(issue_updated_at);
|
return super.getUpdatedAt();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The HTML page of this pull request,
|
|
||||||
* like https://github.com/jenkinsci/jenkins/pull/100
|
|
||||||
*/
|
|
||||||
public URL getUrl() {
|
|
||||||
return super.getUrl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,22 +108,77 @@ public class GHPullRequest extends GHIssue {
|
|||||||
return GitHub.parseURL(diff_url);
|
return GitHub.parseURL(diff_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getClosedAt() {
|
public Date getMergedAt() {
|
||||||
return GitHub.parseDate(closed_at);
|
return GitHub.parseDate(merged_at);
|
||||||
}
|
}
|
||||||
|
|
||||||
GHPullRequest wrapUp(GHRepository owner) {
|
@Override
|
||||||
this.owner = owner;
|
public Collection<String> getLabels() {
|
||||||
return wrapUp(owner.root);
|
return super.getLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
GHPullRequest wrapUp(GitHub root) {
|
@Override
|
||||||
this.root = root;
|
public GHUser getClosedBy() {
|
||||||
if (owner!=null) owner.wrap(root);
|
return null;
|
||||||
if (issue_user!=null) issue_user.root=root;
|
}
|
||||||
if (user!=null) user.root=root;
|
|
||||||
if (base!=null) base.wrapUp(root);
|
@Override
|
||||||
if (head!=null) head.wrapUp(root);
|
public PullRequest getPullRequest() {
|
||||||
return this;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// details that are only available via get with ID
|
||||||
|
//
|
||||||
|
//
|
||||||
|
public GHUser getMergedBy() throws IOException {
|
||||||
|
populate();
|
||||||
|
return merged_by;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getReviewComments() throws IOException {
|
||||||
|
populate();
|
||||||
|
return review_comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAdditions() throws IOException {
|
||||||
|
populate();
|
||||||
|
return additions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMerged() throws IOException {
|
||||||
|
populate();
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getMergeable() throws IOException {
|
||||||
|
populate();
|
||||||
|
return mergeable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDeletions() throws IOException {
|
||||||
|
populate();
|
||||||
|
return deletions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMergeableState() throws IOException {
|
||||||
|
populate();
|
||||||
|
return mergeable_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChangedFiles() throws IOException {
|
||||||
|
populate();
|
||||||
|
return changed_files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fully populate the data by retrieving missing data.
|
||||||
|
*
|
||||||
|
* Depending on the original API call where this object is created, it may not contain everything.
|
||||||
|
*/
|
||||||
|
private void populate() throws IOException {
|
||||||
|
if (merged_by!=null) return; // already populated
|
||||||
|
|
||||||
|
root.retrieve().to(url, 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,18 +23,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
|
|
||||||
import com.gargoylesoftware.htmlunit.WebClient;
|
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlButton;
|
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
|
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlForm;
|
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlInput;
|
|
||||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
|
||||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.io.InterruptedIOException;
|
||||||
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;
|
||||||
@@ -52,7 +44,6 @@ import java.util.Set;
|
|||||||
import java.util.TreeMap;
|
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.
|
||||||
@@ -72,9 +63,16 @@ public class GHRepository {
|
|||||||
private String created_at, pushed_at;
|
private String created_at, pushed_at;
|
||||||
private Map<Integer,GHMilestone> milestones = new HashMap<Integer, GHMilestone>();
|
private Map<Integer,GHMilestone> milestones = new HashMap<Integer, GHMilestone>();
|
||||||
|
|
||||||
private String master_branch;
|
private String master_branch,language;
|
||||||
private Map<String,GHCommit> commits = new HashMap<String, GHCommit>();
|
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;
|
||||||
}
|
}
|
||||||
@@ -113,12 +111,39 @@ public class GHRepository {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasPullAccess() {
|
||||||
|
return permissions!=null && permissions.pull;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPushAccess() {
|
||||||
|
return permissions!=null && permissions.push;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAdminAccess() {
|
||||||
|
return permissions!=null && permissions.admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary programming language.
|
||||||
|
*/
|
||||||
|
public String getLanguage() {
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
public GHUser getOwner() throws IOException {
|
public GHUser getOwner() throws IOException {
|
||||||
return root.getUser(owner.login); // because 'owner' isn't fully populated
|
return root.getUser(owner.login); // because 'owner' isn't fully populated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GHIssue getIssue(int id) throws IOException {
|
||||||
|
return root.retrieve().to("/repos/" + owner.login + "/" + name + "/issues/" + id, GHIssue.class).wrap(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GHIssueBuilder createIssue(String title) {
|
||||||
|
return new GHIssueBuilder(this,title);
|
||||||
|
}
|
||||||
|
|
||||||
public List<GHIssue> getIssues(GHIssueState state) throws IOException {
|
public List<GHIssue> getIssues(GHIssueState state) throws IOException {
|
||||||
return root.retrieve("/issues/list/" + owner.login + "/" + name + "/" + state.toString().toLowerCase(), JsonIssues.class).wrap(this);
|
return Arrays.asList(GHIssue.wrap(root.retrieve().to("/repos/" + owner.login + "/" + name + "/issues?state=" + state.toString().toLowerCase(), GHIssue[].class), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getOwnerName() {
|
protected String getOwnerName() {
|
||||||
@@ -190,10 +215,7 @@ public class GHRepository {
|
|||||||
*/
|
*/
|
||||||
@WithBridgeMethods(Set.class)
|
@WithBridgeMethods(Set.class)
|
||||||
public GHPersonSet<GHUser> getCollaborators() throws IOException {
|
public GHPersonSet<GHUser> getCollaborators() throws IOException {
|
||||||
GHPersonSet<GHUser> r = new GHPersonSet<GHUser>();
|
return new GHPersonSet<GHUser>(GHUser.wrap(root.retrieve().to("/repos/" + owner.login + "/" + name + "/collaborators", GHUser[].class),root));
|
||||||
for (String u : root.retrieve("/repos/show/"+owner.login+"/"+name+"/collaborators",JsonCollaborators.class).collaborators)
|
|
||||||
r.add(root.getUser(u));
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,16 +223,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.login+"/"+name+"/collaborators",JsonCollaborators.class).collaborators);
|
Set<String> r = new HashSet<String>();
|
||||||
return Collections.unmodifiableSet(r);
|
for (GHUser u : GHUser.wrap(root.retrieve().to("/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.login+"/"+name+"/teams",JsonTeams.class).toSet(
|
return Collections.unmodifiableSet(new HashSet<GHTeam>(Arrays.asList(GHTeam.wrapUp(root.retrieve().to("/repos/" + owner.login + "/" + name + "/teams", GHTeam[].class), root.getOrganization(owner.login)))));
|
||||||
root.getOrganization(owner.login)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCollaborators(GHUser... users) throws IOException {
|
public void addCollaborators(GHUser... users) throws IOException {
|
||||||
@@ -218,7 +241,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 {
|
||||||
@@ -226,53 +249,68 @@ 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 Requester(root).method(method).to("/repos/" + owner.login + "/" + name + "/collaborators/" + user.getLogin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEmailServiceHook(String address) throws IOException {
|
public void setEmailServiceHook(String address) throws IOException {
|
||||||
WebClient wc = root.createWebClient();
|
Map<String, String> config = new HashMap<String, String>();
|
||||||
HtmlPage pg = (HtmlPage)wc.getPage(getUrl()+"/admin");
|
config.put("address", address);
|
||||||
HtmlInput email = (HtmlInput)pg.getElementById("email_address");
|
new Requester(root).method("POST").with("name", "email").with("config", config).with("active", "true")
|
||||||
email.setValueAttribute(address);
|
.to(String.format("/repos/%s/%s/hooks", owner.login, name));
|
||||||
HtmlCheckBoxInput active = (HtmlCheckBoxInput)pg.getElementById("email[active]");
|
}
|
||||||
active.setChecked(true);
|
|
||||||
|
|
||||||
final HtmlForm f = email.getEnclosingFormOrDie();
|
private void edit(String key, String value) throws IOException {
|
||||||
f.submit((HtmlButton) f.getElementsByTagName("button").get(0));
|
Requester requester = new Requester(root);
|
||||||
|
if (!key.equals("name"))
|
||||||
|
requester.with("name", name); // even when we don't change the name, we need to send it in
|
||||||
|
requester.with(key, value).method("PATCH").to("/repos/" + owner.login + "/" + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.login + "/" + 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.login + "/" + 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();
|
new Requester(root).method("DELETE").to("/repos/" + owner.login + "/" + name);
|
||||||
String url = "/repos/delete/" + owner.login +"/"+name;
|
|
||||||
|
|
||||||
DeleteToken token = poster.to(url, DeleteToken.class);
|
|
||||||
poster.with("delete_token", token.delete_token).to(url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -282,7 +320,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,V3).withCredential().to("/repos/" + owner.login + "/" + name + "/forks", GHRepository.class, "POST").wrap(root);
|
return new Requester(root).method("POST").to("/repos/" + owner.login + "/" + name + "/forks", GHRepository.class).wrap(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -292,58 +330,52 @@ 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.login,name,org.getLogin()));
|
new Requester(root).to(String.format("/repos/%s/%s/forks?org=%s", owner.login, name, org.getLogin()));
|
||||||
return org.getRepository(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// this API is asynchronous. we need to wait for a bit
|
||||||
* Rename this repository.
|
for (int i=0; i<10; i++) {
|
||||||
*/
|
GHRepository r = org.getRepository(name);
|
||||||
public void renameTo(String newName) throws IOException {
|
if (r!=null) return r;
|
||||||
WebClient wc = root.createWebClient();
|
|
||||||
HtmlPage pg = (HtmlPage)wc.getPage(getUrl()+"/admin");
|
|
||||||
for (HtmlForm f : pg.getForms()) {
|
|
||||||
if (!f.getActionAttribute().endsWith("/rename")) continue;
|
|
||||||
try {
|
try {
|
||||||
f.getInputByName("name").setValueAttribute(newName);
|
Thread.sleep(3000);
|
||||||
f.submit((HtmlButton)f.getElementsByTagName("button").get(0));
|
} catch (InterruptedException e) {
|
||||||
|
throw (IOException)new InterruptedIOException().initCause(e);
|
||||||
// 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 IOException(this+" was forked into "+org.getLogin()+" but can't find the new repository");
|
||||||
throw new IllegalArgumentException("Either you don't have the privilege to rename "+owner.login+'/'+name+" or there's a bug in HTML scraping");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a specified pull request.
|
* Retrieves a specified pull request.
|
||||||
*/
|
*/
|
||||||
public GHPullRequest getPullRequest(int i) throws IOException {
|
public GHPullRequest getPullRequest(int i) throws IOException {
|
||||||
return root.retrieveWithAuth3("/repos/" + owner.login + '/' + name + "/pulls/" + i, GHPullRequest.class).wrapUp(this);
|
return root.retrieve().to("/repos/" + owner.login + '/' + name + "/pulls/" + i, GHPullRequest.class).wrapUp(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all the pull requests of a particular state.
|
||||||
|
*
|
||||||
|
* @see #listPullRequests(GHIssueState)
|
||||||
|
*/
|
||||||
|
public List<GHPullRequest> getPullRequests(GHIssueState state) throws IOException {
|
||||||
|
return listPullRequests(state).asList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 PagedIterable<GHPullRequest> listPullRequests(final GHIssueState state) {
|
||||||
GHPullRequest[] r = root.retrieveWithAuth3("/repos/" + owner.login + '/' + name + "/pulls?state=" + state.name().toLowerCase(Locale.ENGLISH), GHPullRequest[].class);
|
return new PagedIterable<GHPullRequest>() {
|
||||||
for (GHPullRequest p : r)
|
public PagedIterator<GHPullRequest> iterator() {
|
||||||
p.wrapUp(this);
|
return new PagedIterator<GHPullRequest>(root.retrieve().asIterator(String.format("/repos/%s/%s/pulls?state=%s", owner.login, name, state.name().toLowerCase(Locale.ENGLISH)), GHPullRequest[].class)) {
|
||||||
return new ArrayList<GHPullRequest>(Arrays.asList(r));
|
@Override
|
||||||
|
protected void wrapUp(GHPullRequest[] page) {
|
||||||
|
for (GHPullRequest pr : page)
|
||||||
|
pr.wrap(GHRepository.this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -351,14 +383,14 @@ public class GHRepository {
|
|||||||
*/
|
*/
|
||||||
public List<GHHook> getHooks() throws IOException {
|
public List<GHHook> getHooks() throws IOException {
|
||||||
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList(
|
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList(
|
||||||
root.retrieveWithAuth3(String.format("/repos/%s/%s/hooks",owner.login,name),GHHook[].class)));
|
root.retrieve().to(String.format("/repos/%s/%s/hooks", owner.login, name), GHHook[].class)));
|
||||||
for (GHHook h : list)
|
for (GHHook h : list)
|
||||||
h.wrap(this);
|
h.wrap(this);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GHHook getHook(int id) throws IOException {
|
public GHHook getHook(int id) throws IOException {
|
||||||
return root.retrieveWithAuth3(String.format("/repos/%s/%s/hooks/%d",owner.login,name,id),GHHook.class).wrap(this);
|
return root.retrieve().to(String.format("/repos/%s/%s/hooks/%d", owner.login, name, id), GHHook.class).wrap(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -367,7 +399,7 @@ public class GHRepository {
|
|||||||
public GHCommit getCommit(String sha1) throws IOException {
|
public GHCommit getCommit(String sha1) throws IOException {
|
||||||
GHCommit c = commits.get(sha1);
|
GHCommit c = commits.get(sha1);
|
||||||
if (c==null) {
|
if (c==null) {
|
||||||
c = root.retrieve3(String.format("/repos/%s/%s/commits/%s",owner.login,name,sha1),GHCommit.class).wrapUp(this);
|
c = root.retrieve().to(String.format("/repos/%s/%s/commits/%s", owner.login, name, sha1), GHCommit.class).wrapUp(this);
|
||||||
commits.put(sha1,c);
|
commits.put(sha1,c);
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
@@ -379,7 +411,7 @@ public class GHRepository {
|
|||||||
public PagedIterable<GHCommit> listCommits() {
|
public PagedIterable<GHCommit> listCommits() {
|
||||||
return new PagedIterable<GHCommit>() {
|
return new PagedIterable<GHCommit>() {
|
||||||
public PagedIterator<GHCommit> iterator() {
|
public PagedIterator<GHCommit> iterator() {
|
||||||
return new PagedIterator<GHCommit>(root.retrievePaged(String.format("/repos/%s/%s/commits",owner.login,name),GHCommit[].class,false,V3)) {
|
return new PagedIterator<GHCommit>(root.retrieve().asIterator(String.format("/repos/%s/%s/commits", owner.login, name), GHCommit[].class)) {
|
||||||
protected void wrapUp(GHCommit[] page) {
|
protected void wrapUp(GHCommit[] page) {
|
||||||
for (GHCommit c : page)
|
for (GHCommit c : page)
|
||||||
c.wrapUp(GHRepository.this);
|
c.wrapUp(GHRepository.this);
|
||||||
@@ -395,7 +427,7 @@ public class GHRepository {
|
|||||||
public PagedIterable<GHCommitComment> listCommitComments() {
|
public PagedIterable<GHCommitComment> listCommitComments() {
|
||||||
return new PagedIterable<GHCommitComment>() {
|
return new PagedIterable<GHCommitComment>() {
|
||||||
public PagedIterator<GHCommitComment> iterator() {
|
public PagedIterator<GHCommitComment> iterator() {
|
||||||
return new PagedIterator<GHCommitComment>(root.retrievePaged(String.format("/repos/%s/%s/comments",owner.login,name),GHCommitComment[].class,false,V3)) {
|
return new PagedIterator<GHCommitComment>(root.retrieve().asIterator(String.format("/repos/%s/%s/comments", owner.login, name), GHCommitComment[].class)) {
|
||||||
@Override
|
@Override
|
||||||
protected void wrapUp(GHCommitComment[] page) {
|
protected void wrapUp(GHCommitComment[] page) {
|
||||||
for (GHCommitComment c : page)
|
for (GHCommitComment c : page)
|
||||||
@@ -406,6 +438,48 @@ public class GHRepository {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all the commit statues attached to the given commit, newer ones first.
|
||||||
|
*/
|
||||||
|
public PagedIterable<GHCommitStatus> listCommitStatuses(final String sha1) throws IOException {
|
||||||
|
return new PagedIterable<GHCommitStatus>() {
|
||||||
|
public PagedIterator<GHCommitStatus> iterator() {
|
||||||
|
return new PagedIterator<GHCommitStatus>(root.retrieve().asIterator(String.format("/repos/%s/%s/statuses/%s", owner.login, name, sha1), GHCommitStatus[].class)) {
|
||||||
|
@Override
|
||||||
|
protected void wrapUp(GHCommitStatus[] page) {
|
||||||
|
for (GHCommitStatus c : page)
|
||||||
|
c.wrapUp(root);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the last status of this commit, which is what gets shown in the UI.
|
||||||
|
*/
|
||||||
|
public GHCommitStatus getLastCommitStatus(String sha1) throws IOException {
|
||||||
|
List<GHCommitStatus> v = listCommitStatuses(sha1).asList();
|
||||||
|
return v.isEmpty() ? null : v.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a commit status
|
||||||
|
*
|
||||||
|
* @param targetUrl
|
||||||
|
* Optional parameter that points to the URL that has more details.
|
||||||
|
* @param description
|
||||||
|
* Optional short description.
|
||||||
|
*/
|
||||||
|
public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) throws IOException {
|
||||||
|
return new Requester(root)
|
||||||
|
.with("state", state.name().toLowerCase(Locale.ENGLISH))
|
||||||
|
.with("target_url", targetUrl)
|
||||||
|
.with("description", description)
|
||||||
|
.to(String.format("/repos/%s/%s/statuses/%s",owner.login,this.name,sha1),GHCommitStatus.class).wrapUp(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* See https://api.github.com/hooks for possible names and their configuration scheme.
|
* See https://api.github.com/hooks for possible names and their configuration scheme.
|
||||||
@@ -426,9 +500,8 @@ public class GHRepository {
|
|||||||
ea.add(e.name().toLowerCase(Locale.ENGLISH));
|
ea.add(e.name().toLowerCase(Locale.ENGLISH));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Poster(root,ApiVersion.V3)
|
return new Requester(root)
|
||||||
.withCredential()
|
.with("name", name)
|
||||||
.with("name",name)
|
|
||||||
.with("active", active)
|
.with("active", active)
|
||||||
._with("config", config)
|
._with("config", config)
|
||||||
._with("events",ea)
|
._with("events",ea)
|
||||||
@@ -532,28 +605,46 @@ public class GHRepository {
|
|||||||
*/
|
*/
|
||||||
public Map<String,GHBranch> getBranches() throws IOException {
|
public Map<String,GHBranch> getBranches() throws IOException {
|
||||||
Map<String,GHBranch> r = new TreeMap<String,GHBranch>();
|
Map<String,GHBranch> r = new TreeMap<String,GHBranch>();
|
||||||
for (GHBranch p : root.retrieve3("/repos/"+owner.login+"/"+name+"/branches", GHBranch[].class)) {
|
for (GHBranch p : root.retrieve().to(getApiTailUrl("branches"), GHBranch[].class)) {
|
||||||
p.wrap(this);
|
p.wrap(this);
|
||||||
r.put(p.getName(),p);
|
r.put(p.getName(),p);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* Use {@link #listMilestones(GHIssueState)}
|
||||||
|
*/
|
||||||
public Map<Integer, GHMilestone> getMilestones() throws IOException {
|
public Map<Integer, GHMilestone> getMilestones() throws IOException {
|
||||||
Map<Integer,GHMilestone> milestones = new TreeMap<Integer, GHMilestone>();
|
Map<Integer,GHMilestone> milestones = new TreeMap<Integer, GHMilestone>();
|
||||||
GHMilestone[] ms = root.retrieve3("/repos/"+owner.login+"/"+name+"/milestones", GHMilestone[].class);
|
for (GHMilestone m : listMilestones(GHIssueState.OPEN)) {
|
||||||
for (GHMilestone m : ms) {
|
|
||||||
m.owner = this;
|
|
||||||
m.root = root;
|
|
||||||
milestones.put(m.getNumber(), m);
|
milestones.put(m.getNumber(), m);
|
||||||
}
|
}
|
||||||
return milestones;
|
return milestones;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists up all the milestones in this repository.
|
||||||
|
*/
|
||||||
|
public PagedIterable<GHMilestone> listMilestones(final GHIssueState state) {
|
||||||
|
return new PagedIterable<GHMilestone>() {
|
||||||
|
public PagedIterator<GHMilestone> iterator() {
|
||||||
|
return new PagedIterator<GHMilestone>(root.retrieve().asIterator(getApiTailUrl("milestones?state="+state.toString().toLowerCase(Locale.ENGLISH)), GHMilestone[].class)) {
|
||||||
|
@Override
|
||||||
|
protected void wrapUp(GHMilestone[] page) {
|
||||||
|
for (GHMilestone c : page)
|
||||||
|
c.wrap(GHRepository.this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public GHMilestone getMilestone(int number) throws IOException {
|
public GHMilestone getMilestone(int number) throws IOException {
|
||||||
GHMilestone m = milestones.get(number);
|
GHMilestone m = milestones.get(number);
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
m = root.retrieve3("/repos/"+owner.login+"/"+name+"/milestones/"+number, GHMilestone.class);
|
m = root.retrieve().to(getApiTailUrl("milestones/" + number), GHMilestone.class);
|
||||||
m.owner = this;
|
m.owner = this;
|
||||||
m.root = root;
|
m.root = root;
|
||||||
milestones.put(m.getNumber(), m);
|
milestones.put(m.getNumber(), m);
|
||||||
@@ -562,9 +653,8 @@ public class GHRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GHMilestone createMilestone(String title, String description) throws IOException {
|
public GHMilestone createMilestone(String title, String description) throws IOException {
|
||||||
return new Poster(root,V3).withCredential()
|
return new Requester(root)
|
||||||
.with("title", title).with("description", description)
|
.with("title", title).with("description", description).method("POST").to(getApiTailUrl("milestones"), GHMilestone.class).wrap(this);
|
||||||
.to("/repos/"+owner.login+"/"+name+"/milestones", GHMilestone.class,"POST").wrap(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -586,4 +676,8 @@ public class GHRepository {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getApiTailUrl(String tail) {
|
||||||
|
return "/repos/" + owner.login + "/" + name +'/'+tail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.retrieve().to(api("/members"), GHUser[].class), org.root)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String,GHRepository> getRepositories() throws IOException {
|
public Map<String,GHRepository> getRepositories() throws IOException {
|
||||||
return org.root.retrieveWithAuth3(api("/repos"),JsonRepositories.class).wrap(org.root);
|
GHRepository[] repos = org.root.retrieve().to(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.retrieve().method("PUT").to(api("/members/" + u.getLogin()), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.retrieve().method("DELETE").to(api("/members/" + u.getLogin()), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
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.retrieve().method("PUT").to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
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.retrieve().method("DELETE").to(api("/repos/" + r.getOwnerName() + '/' + r.getName()), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String api(String tail) {
|
private String api(String tail) {
|
||||||
|
|||||||
@@ -23,12 +23,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import com.infradna.tool.bridge_method_injector.BridgeMethodsAdded;
|
|
||||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
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.HashSet;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,14 +41,14 @@ public class GHUser extends GHPerson {
|
|||||||
* 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 Requester(root).method("PUT").to("/user/following/" + login);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 Requester(root).method("DELETE").to("/user/following/" + login);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,7 +56,8 @@ public class GHUser extends GHPerson {
|
|||||||
*/
|
*/
|
||||||
@WithBridgeMethods(Set.class)
|
@WithBridgeMethods(Set.class)
|
||||||
public GHPersonSet<GHUser> getFollows() throws IOException {
|
public GHPersonSet<GHUser> getFollows() throws IOException {
|
||||||
return root.retrieve("/user/show/"+login+"/following",JsonUsers.class).toSet(root);
|
GHUser[] followers = root.retrieve().to("/users/" + login + "/following", GHUser[].class);
|
||||||
|
return new GHPersonSet<GHUser>(Arrays.asList(wrap(followers,root)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,7 +65,28 @@ public class GHUser extends GHPerson {
|
|||||||
*/
|
*/
|
||||||
@WithBridgeMethods(Set.class)
|
@WithBridgeMethods(Set.class)
|
||||||
public GHPersonSet<GHUser> getFollowers() throws IOException {
|
public GHPersonSet<GHUser> getFollowers() throws IOException {
|
||||||
return root.retrieve("/user/show/"+login+"/followers",JsonUsers.class).toSet(root);
|
GHUser[] followers = root.retrieve().to("/users/" + login + "/followers", GHUser[].class);
|
||||||
|
return new GHPersonSet<GHUser>(Arrays.asList(wrap(followers,root)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this user belongs to the specified organization.
|
||||||
|
*/
|
||||||
|
public boolean isMemberOf(GHOrganization org) {
|
||||||
|
return org.hasMember(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this user belongs to the specified organization as a public member.
|
||||||
|
*/
|
||||||
|
public boolean isPublicMemberOf(GHOrganization org) {
|
||||||
|
return org.hasPublicMember(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ static GHUser[] wrap(GHUser[] users, GitHub root) {
|
||||||
|
for (GHUser f : users)
|
||||||
|
f.root = root;
|
||||||
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,7 +96,7 @@ public class GHUser extends GHPerson {
|
|||||||
public GHPersonSet<GHOrganization> getOrganizations() throws IOException {
|
public GHPersonSet<GHOrganization> getOrganizations() throws IOException {
|
||||||
GHPersonSet<GHOrganization> orgs = new GHPersonSet<GHOrganization>();
|
GHPersonSet<GHOrganization> orgs = new GHPersonSet<GHOrganization>();
|
||||||
Set<String> names = new HashSet<String>();
|
Set<String> names = new HashSet<String>();
|
||||||
for (GHOrganization o : root.retrieve3("/users/"+login+"/orgs",GHOrganization[].class)) {
|
for (GHOrganization o : root.retrieve().to("/users/" + login + "/orgs", GHOrganization[].class)) {
|
||||||
if (names.add(o.getLogin())) // I've seen some duplicates in the data
|
if (names.add(o.getLogin())) // I've seen some duplicates in the data
|
||||||
orgs.add(root.getOrganization(o.getLogin()));
|
orgs.add(root.getOrganization(o.getLogin()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,20 +23,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.ANY;
|
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||||
import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import static org.kohsuke.github.ApiVersion.V2;
|
import org.apache.commons.io.IOUtils;
|
||||||
import static org.kohsuke.github.ApiVersion.V3;
|
import org.codehaus.jackson.map.DeserializationConfig.Feature;
|
||||||
|
import org.codehaus.jackson.map.ObjectMapper;
|
||||||
|
import org.codehaus.jackson.map.introspect.VisibilityChecker.Std;
|
||||||
|
|
||||||
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.InterruptedIOException;
|
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
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;
|
||||||
@@ -44,26 +41,12 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.zip.GZIPInputStream;
|
|
||||||
|
|
||||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.*;
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.codehaus.jackson.JsonParseException;
|
|
||||||
import org.codehaus.jackson.map.DeserializationConfig.Feature;
|
|
||||||
import org.codehaus.jackson.map.ObjectMapper;
|
|
||||||
import org.codehaus.jackson.map.introspect.VisibilityChecker.Std;
|
|
||||||
|
|
||||||
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.
|
||||||
@@ -72,38 +55,45 @@ import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
|||||||
*/
|
*/
|
||||||
public class GitHub {
|
public class GitHub {
|
||||||
/*package*/ final String login;
|
/*package*/ final String login;
|
||||||
|
|
||||||
|
|
||||||
/*package*/ final String encodedAuthorization;
|
/*package*/ final String encodedAuthorization;
|
||||||
/*package*/ final String password;
|
|
||||||
/*package*/ final String apiToken;
|
/*package*/ final String apiToken;
|
||||||
|
|
||||||
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>();
|
||||||
/*package*/ String oauthAccessToken;
|
/*package*/ String oauthAccessToken;
|
||||||
|
|
||||||
private final String githubServer;
|
private final String apiUrl;
|
||||||
|
|
||||||
private GitHub(String login, String apiToken, String password) {
|
private GitHub(String login, String apiToken, String password) {
|
||||||
this ("github.com", login, apiToken, password);
|
this (GITHUB_URL, login, apiToken, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GitHub(String githubServer, String login, String apiToken, String password) {
|
/**
|
||||||
this.githubServer = githubServer;
|
*
|
||||||
|
* @param apiUrl
|
||||||
|
* The URL of GitHub (or GitHub enterprise) API endpoint, such as "https://api.github.com" or
|
||||||
|
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <tt>/api/v3</tt> in the URL.
|
||||||
|
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
|
||||||
|
* Password is also considered deprecated as it is no longer required for api usage.
|
||||||
|
*/
|
||||||
|
private GitHub(String apiUrl, String login, String apiToken, String password) {
|
||||||
|
if (apiUrl.endsWith("/")) apiUrl = apiUrl.substring(0, apiUrl.length()-1); // normalize
|
||||||
|
this.apiUrl = apiUrl;
|
||||||
this.login = login;
|
this.login = login;
|
||||||
this.apiToken = apiToken;
|
this.apiToken = apiToken;
|
||||||
this.password = password;
|
|
||||||
|
|
||||||
BASE64Encoder enc = new sun.misc.BASE64Encoder();
|
|
||||||
if (apiToken!=null || password!=null) {
|
if (apiToken!=null || password!=null) {
|
||||||
String userpassword = password==null ? (login + "/token" + ":" + apiToken) : (login + ':'+password);
|
String authorization = password==null ? (login + "/token" + ":" + apiToken) : (login + ':'+password);
|
||||||
encodedAuthorization = enc.encode(userpassword.getBytes());
|
encodedAuthorization = new String(Base64.encodeBase64(authorization.getBytes()));
|
||||||
} else
|
} else
|
||||||
encodedAuthorization = null;
|
encodedAuthorization = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GitHub (String githubServer, String oauthAccessToken) throws IOException {
|
private GitHub (String apiUrl, String oauthAccessToken) throws IOException {
|
||||||
|
if (apiUrl.endsWith("/")) apiUrl = apiUrl.substring(0, apiUrl.length()-1); // normalize
|
||||||
this.githubServer = githubServer;
|
this.apiUrl = apiUrl;
|
||||||
this.password = null;
|
|
||||||
this.encodedAuthorization = null;
|
this.encodedAuthorization = null;
|
||||||
|
|
||||||
this.oauthAccessToken = oauthAccessToken;
|
this.oauthAccessToken = oauthAccessToken;
|
||||||
@@ -124,14 +114,30 @@ public class GitHub {
|
|||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(in);
|
IOUtils.closeQuietly(in);
|
||||||
}
|
}
|
||||||
return new GitHub(props.getProperty("login"),props.getProperty("token"),props.getProperty("password"));
|
String oauth = props.getProperty("oauth");
|
||||||
|
if (oauth!=null)
|
||||||
|
return new GitHub(GITHUB_URL,oauth);
|
||||||
|
else
|
||||||
|
return new GitHub(props.getProperty("login"),props.getProperty("token"),props.getProperty("password"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GitHub connect(String login, String apiToken) throws IOException {
|
/**
|
||||||
|
* Version that connects to GitHub Enterprise.
|
||||||
|
*
|
||||||
|
* @param apiUrl
|
||||||
|
* The URL of GitHub (or GitHub enterprise) API endpoint, such as "https://api.github.com" or
|
||||||
|
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <tt>/api/v3</tt> in the URL.
|
||||||
|
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
|
||||||
|
*/
|
||||||
|
public static GitHub connectToEnterprise(String apiUrl, String login, String apiToken) {
|
||||||
|
return new GitHub(apiUrl,login,apiToken,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GitHub connect(String login, String apiToken){
|
||||||
return new GitHub(login,apiToken,null);
|
return new GitHub(login,apiToken,null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GitHub connect(String login, String apiToken, String password) throws IOException {
|
public static GitHub connect(String login, String apiToken, String password){
|
||||||
return new GitHub(login,apiToken,password);
|
return new GitHub(login,apiToken,password);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,203 +162,32 @@ 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 + (tailApiUrl.indexOf('?')>=0 ?'&':'?') + "access_token=" + oauthAccessToken;
|
tailApiUrl = tailApiUrl + (tailApiUrl.indexOf('?')>=0 ?'&':'?') + "access_token=" + oauthAccessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new URL(v.getApiVersionBaseUrl(githubServer)+tailApiUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*package*/ <T> T retrieve(String tailApiUrl, Class<T> type) throws IOException {
|
if (tailApiUrl.startsWith("/")) {
|
||||||
return _retrieve(tailApiUrl, type, "GET", false, V2);
|
if ("github.com".equals(apiUrl)) {// backward compatibility
|
||||||
}
|
return new URL(GITHUB_URL + tailApiUrl);
|
||||||
|
} else {
|
||||||
/*package*/ <T> T retrieve3(String tailApiUrl, Class<T> type) throws IOException {
|
return new URL(apiUrl + tailApiUrl);
|
||||||
return _retrieve(tailApiUrl, type, "GET", false, V3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*package*/ <T> T retrieveWithAuth(String tailApiUrl, Class<T> type) throws IOException {
|
|
||||||
return retrieveWithAuth(tailApiUrl, type, "GET");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*package*/ <T> T retrieveWithAuth3(String tailApiUrl, Class<T> type) throws IOException {
|
|
||||||
return _retrieve(tailApiUrl, type, "GET", true, V3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*package*/ <T> T retrieveWithAuth(String tailApiUrl, Class<T> type, String method) throws IOException {
|
|
||||||
return _retrieve(tailApiUrl, type, method, true, V2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*package*/ <T> T retrieveWithAuth3(String tailApiUrl, Class<T> type, String method) throws IOException {
|
|
||||||
return _retrieve(tailApiUrl, type, method, true, V3);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> T _retrieve(String tailApiUrl, Class<T> type, String method, boolean withAuth, ApiVersion v) throws IOException {
|
|
||||||
while (true) {// loop while API rate limit is hit
|
|
||||||
HttpURLConnection uc = setupConnection(method, withAuth, getApiURL(v, tailApiUrl));
|
|
||||||
try {
|
|
||||||
return parse(uc,type);
|
|
||||||
} catch (IOException e) {
|
|
||||||
handleApiError(e,uc);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return new URL(tailApiUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ Requester retrieve() {
|
||||||
|
return new Requester(this).method("GET");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads pagenated resources.
|
* Gets the current rate limit.
|
||||||
*
|
|
||||||
* Every iterator call reports a new batch.
|
|
||||||
*/
|
*/
|
||||||
/*package*/ <T> Iterator<T> retrievePaged(final String tailApiUrl, final Class<T> type, final boolean withAuth, final ApiVersion v) {
|
public GHRateLimit getRateLimit() throws IOException {
|
||||||
return new Iterator<T>() {
|
return retrieve().to("/rate_limit", JsonRateLimit.class).rate;
|
||||||
/**
|
|
||||||
* The next batch to be returned from {@link #next()}.
|
|
||||||
*/
|
|
||||||
T next;
|
|
||||||
/**
|
|
||||||
* URL of the next resource to be retrieved, or null if no more data is available.
|
|
||||||
*/
|
|
||||||
URL url;
|
|
||||||
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
url = getApiURL(v, tailApiUrl);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new Error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
fetch();
|
|
||||||
return next!=null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T next() {
|
|
||||||
fetch();
|
|
||||||
T r = next;
|
|
||||||
if (r==null) throw new NoSuchElementException();
|
|
||||||
next = null;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fetch() {
|
|
||||||
if (next!=null) return; // already fetched
|
|
||||||
if (url==null) return; // no more data to fetch
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (true) {// loop while API rate limit is hit
|
|
||||||
HttpURLConnection uc = setupConnection("GET", withAuth, url);
|
|
||||||
try {
|
|
||||||
next = parse(uc,type);
|
|
||||||
assert next!=null;
|
|
||||||
findNextURL(uc);
|
|
||||||
return;
|
|
||||||
} catch (IOException e) {
|
|
||||||
handleApiError(e,uc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new Error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locate the next page from the pagination "Link" tag.
|
|
||||||
*/
|
|
||||||
private void findNextURL(HttpURLConnection uc) throws MalformedURLException {
|
|
||||||
url = null; // start defensively
|
|
||||||
String link = uc.getHeaderField("Link");
|
|
||||||
if (link==null) return;
|
|
||||||
|
|
||||||
for (String token : link.split(", ")) {
|
|
||||||
if (token.endsWith("rel=\"next\"")) {
|
|
||||||
// found the next page. This should look something like
|
|
||||||
// <https://api.github.com/repos?page=3&per_page=100>; rel="next"
|
|
||||||
int idx = token.indexOf('>');
|
|
||||||
url = new URL(token.substring(1,idx));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no more "next" link. we are done.
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpURLConnection setupConnection(String method, boolean withAuth, URL url) throws IOException {
|
|
||||||
HttpURLConnection uc = (HttpURLConnection) url.openConnection();
|
|
||||||
|
|
||||||
if (withAuth && this.oauthAccessToken == null)
|
|
||||||
uc.setRequestProperty("Authorization", "Basic " + encodedAuthorization);
|
|
||||||
|
|
||||||
uc.setRequestMethod(method);
|
|
||||||
if (method.equals("PUT")) {
|
|
||||||
uc.setDoOutput(true);
|
|
||||||
uc.setRequestProperty("Content-Length","0");
|
|
||||||
uc.getOutputStream().close();
|
|
||||||
}
|
|
||||||
uc.setRequestProperty("Accept-Encoding", "gzip");
|
|
||||||
return uc;
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> T parse(HttpURLConnection uc, Class<T> type) throws IOException {
|
|
||||||
InputStreamReader r = null;
|
|
||||||
try {
|
|
||||||
r = new InputStreamReader(wrapStream(uc, uc.getInputStream()), "UTF-8");
|
|
||||||
if (type==null) {
|
|
||||||
String data = IOUtils.toString(r);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return MAPPER.readValue(r,type);
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the "Content-Encoding" header.
|
|
||||||
*/
|
|
||||||
private InputStream wrapStream(HttpURLConnection uc, InputStream in) throws IOException {
|
|
||||||
String encoding = uc.getContentEncoding();
|
|
||||||
if (encoding==null || in==null) return in;
|
|
||||||
if (encoding.equals("gzip")) return new GZIPInputStream(in);
|
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Unexpected Content-Encoding: "+encoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the error is because of the API limit, wait 10 sec and return normally.
|
|
||||||
* Otherwise throw an exception reporting an error.
|
|
||||||
*/
|
|
||||||
/*package*/ void handleApiError(IOException e, HttpURLConnection uc) throws IOException {
|
|
||||||
if ("0".equals(uc.getHeaderField("X-RateLimit-Remaining"))) {
|
|
||||||
// API limit reached. wait 10 secs and return normally
|
|
||||||
try {
|
|
||||||
Thread.sleep(10000);
|
|
||||||
return;
|
|
||||||
} catch (InterruptedException _) {
|
|
||||||
throw (InterruptedIOException)new InterruptedIOException().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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -362,7 +197,7 @@ public class GitHub {
|
|||||||
public GHMyself getMyself() throws IOException {
|
public GHMyself getMyself() throws IOException {
|
||||||
requireCredential();
|
requireCredential();
|
||||||
|
|
||||||
GHMyself u = retrieveWithAuth3("/user", GHMyself.class);
|
GHMyself u = retrieve().to("/user", GHMyself.class);
|
||||||
|
|
||||||
u.root = this;
|
u.root = this;
|
||||||
users.put(u.getLogin(), u);
|
users.put(u.getLogin(), u);
|
||||||
@@ -376,7 +211,7 @@ public class GitHub {
|
|||||||
public GHUser getUser(String login) throws IOException {
|
public GHUser getUser(String login) throws IOException {
|
||||||
GHUser u = users.get(login);
|
GHUser u = users.get(login);
|
||||||
if (u == null) {
|
if (u == null) {
|
||||||
u = retrieve3("/users/" + login, GHUser.class);
|
u = retrieve().to("/users/" + login, GHUser.class);
|
||||||
u.root = this;
|
u.root = this;
|
||||||
users.put(u.getLogin(), u);
|
users.put(u.getLogin(), u);
|
||||||
}
|
}
|
||||||
@@ -399,8 +234,7 @@ 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().to("/orgs/" + name, GHOrganization.class).wrapUp(this);
|
||||||
o.root = this;
|
|
||||||
orgs.put(name,o);
|
orgs.put(name,o);
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
@@ -413,19 +247,31 @@ public class GitHub {
|
|||||||
*/
|
*/
|
||||||
public GHRepository getRepository(String name) throws IOException {
|
public GHRepository getRepository(String name) throws IOException {
|
||||||
String[] tokens = name.split("/");
|
String[] tokens = name.split("/");
|
||||||
return getUser(tokens[0]).getRepository(tokens[1]);
|
return retrieve().to("/repos/" + tokens[0] + '/' + tokens[1], GHRepository.class).wrap(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a shallowly populated organizations.
|
||||||
|
*
|
||||||
|
* To retrieve full organization details, you need to call {@link #getOrganization(String)}
|
||||||
|
* TODO: make this automatic.
|
||||||
|
*/
|
||||||
public Map<String, GHOrganization> getMyOrganizations() throws IOException {
|
public Map<String, GHOrganization> getMyOrganizations() throws IOException {
|
||||||
return retrieveWithAuth("/organizations",JsonOrganizations.class).wrap(this);
|
GHOrganization[] orgs = retrieve().to("/user/orgs", GHOrganization[].class);
|
||||||
|
Map<String, GHOrganization> r = new HashMap<String, GHOrganization>();
|
||||||
|
for (GHOrganization o : orgs) {
|
||||||
|
// don't put 'o' into orgs because they are shallow
|
||||||
|
r.put(o.getLogin(),o.wrapUp(this));
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public events visible to you. Equivalent of what's displayed on https://github.com/
|
* Public events visible to you. Equivalent of what's displayed on https://github.com/
|
||||||
*/
|
*/
|
||||||
public List<GHEventInfo> getEvents() throws IOException {
|
public List<GHEventInfo> getEvents() throws IOException {
|
||||||
// TODO: pagenation
|
// TODO: pagination
|
||||||
GHEventInfo[] events = retrieve3("/events", GHEventInfo[].class);
|
GHEventInfo[] events = retrieve().to("/events", GHEventInfo[].class);
|
||||||
for (GHEventInfo e : events)
|
for (GHEventInfo e : events)
|
||||||
e.wrapUp(this);
|
e.wrapUp(this);
|
||||||
return Arrays.asList(events);
|
return Arrays.asList(events);
|
||||||
@@ -451,9 +297,10 @@ public class GitHub {
|
|||||||
* Newly created repository.
|
* Newly created repository.
|
||||||
*/
|
*/
|
||||||
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,V3).withCredential()
|
Requester requester = new Requester(this)
|
||||||
.with("name", name).with("description", description).with("homepage", homepage)
|
.with("name", name).with("description", description).with("homepage", homepage)
|
||||||
.with("public", isPublic ? 1 : 0).to("/user/repos", GHRepository.class,"POST").wrap(this);
|
.with("public", isPublic ? 1 : 0);
|
||||||
|
return requester.method("POST").to("/user/repos", GHRepository.class).wrap(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -461,25 +308,13 @@ public class GitHub {
|
|||||||
*/
|
*/
|
||||||
public boolean isCredentialValid() throws IOException {
|
public boolean isCredentialValid() throws IOException {
|
||||||
try {
|
try {
|
||||||
retrieveWithAuth3("/user",GHUser.class);
|
retrieve().to("/user", GHUser.class);
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WebClient createWebClient() throws IOException {
|
|
||||||
WebClient wc = new WebClient();
|
|
||||||
wc.setJavaScriptEnabled(false);
|
|
||||||
wc.setCssEnabled(false);
|
|
||||||
HtmlPage pg = (HtmlPage)wc.getPage("https://github.com/login");
|
|
||||||
HtmlForm f = pg.getForms().get(0);
|
|
||||||
f.getInputByName("login").setValueAttribute(login);
|
|
||||||
f.getInputByName("password").setValueAttribute(password);
|
|
||||||
f.submit();
|
|
||||||
return wc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*package*/ static URL parseURL(String s) {
|
/*package*/ static URL parseURL(String s) {
|
||||||
try {
|
try {
|
||||||
return s==null ? null : new URL(s);
|
return s==null ? null : new URL(s);
|
||||||
@@ -510,4 +345,6 @@ public class GitHub {
|
|||||||
MAPPER.setVisibilityChecker(new Std(NONE, NONE, NONE, NONE, ANY));
|
MAPPER.setVisibilityChecker(new Std(NONE, NONE, NONE, NONE, ANY));
|
||||||
MAPPER.getDeserializationConfig().set(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
MAPPER.getDeserializationConfig().set(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String GITHUB_URL = "https://api.github.com";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +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 JsonBranch {
|
|
||||||
GHBranch branch;
|
|
||||||
|
|
||||||
GHBranch wrap(GHRepository r) {
|
|
||||||
return branch.wrap(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Eric Maupin
|
|
||||||
*/
|
|
||||||
class JsonBranches {
|
|
||||||
List<GHBranch> branches;
|
|
||||||
|
|
||||||
public List<GHBranch> wrap(GHRepository owner) {
|
|
||||||
for (GHBranch branch : branches)
|
|
||||||
branch.wrap(owner);
|
|
||||||
return branches;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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,8 +0,0 @@
|
|||||||
package org.kohsuke.github;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class JsonOrganization {
|
|
||||||
public GHOrganization organization;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,6 @@ package org.kohsuke.github;
|
|||||||
/**
|
/**
|
||||||
* @author Kohsuke Kawaguchi
|
* @author Kohsuke Kawaguchi
|
||||||
*/
|
*/
|
||||||
class JsonMyself {
|
class JsonRateLimit {
|
||||||
GHMyself user;
|
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,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,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 GHPersonSet<GHUser> toSet(GitHub root) throws IOException {
|
|
||||||
GHPersonSet<GHUser> r = new GHPersonSet<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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,24 @@
|
|||||||
package org.kohsuke.github;
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* {@link Iterable} that returns {@link PagedIterator}
|
||||||
|
*
|
||||||
* @author Kohsuke Kawaguchi
|
* @author Kohsuke Kawaguchi
|
||||||
*/
|
*/
|
||||||
public interface PagedIterable<T> extends Iterable<T> {
|
public abstract class PagedIterable<T> implements Iterable<T> {
|
||||||
PagedIterator<T> iterator();
|
public abstract PagedIterator<T> iterator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eagerly walk {@link Iterable} and return the result in a list.
|
||||||
|
*/
|
||||||
|
public List<T> asList() {
|
||||||
|
List<T> r = new ArrayList<T>();
|
||||||
|
for(PagedIterator<T> i = iterator(); i.hasNext();) {
|
||||||
|
r.addAll(i.nextPage());
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.kohsuke.github;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterator over a pagenated data source.
|
* Iterator over a pagenated data source.
|
||||||
@@ -28,17 +29,24 @@ public abstract class PagedIterator<T> implements Iterator<T> {
|
|||||||
protected abstract void wrapUp(T[] page);
|
protected abstract void wrapUp(T[] page);
|
||||||
|
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return (current!=null && pos<current.length) || base.hasNext();
|
fetch();
|
||||||
|
return current!=null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T next() {
|
public T next() {
|
||||||
fetch();
|
fetch();
|
||||||
|
if (current==null) throw new NoSuchElementException();
|
||||||
return current[pos++];
|
return current[pos++];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetch() {
|
private void fetch() {
|
||||||
while (current==null || current.length<=pos) {
|
while (current==null || current.length<=pos) {
|
||||||
|
if (!base.hasNext()) {// no more to retrieve
|
||||||
|
current = null;
|
||||||
|
pos = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
current = base.next();
|
current = base.next();
|
||||||
wrapUp(current);
|
wrapUp(current);
|
||||||
pos = 0;
|
pos = 0;
|
||||||
|
|||||||
@@ -1,191 +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 org.apache.commons.io.IOUtils;
|
|
||||||
import org.codehaus.jackson.JsonNode;
|
|
||||||
import org.codehaus.jackson.impl.WriterBasedGenerator;
|
|
||||||
import org.codehaus.jackson.node.ObjectNode;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.ProtocolException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.kohsuke.github.GitHub.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles HTTP POST.
|
|
||||||
* @author Kohsuke Kawaguchi
|
|
||||||
*/
|
|
||||||
class Poster {
|
|
||||||
private final GitHub root;
|
|
||||||
private final List<Entry> args = new ArrayList<Entry>();
|
|
||||||
private boolean authenticate;
|
|
||||||
|
|
||||||
private final ApiVersion v;
|
|
||||||
|
|
||||||
private static class Entry {
|
|
||||||
String key;
|
|
||||||
Object value;
|
|
||||||
|
|
||||||
private Entry(String key, Object value) {
|
|
||||||
this.key = key;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toFormArg() throws UnsupportedEncodingException {
|
|
||||||
return URLEncoder.encode(key,"UTF-8")+'='+URLEncoder.encode(value.toString(),"UTF-8");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Poster(GitHub root, ApiVersion v) {
|
|
||||||
this.root = root;
|
|
||||||
this.v = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
Poster(GitHub root) {
|
|
||||||
this(root,ApiVersion.V2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Poster withCredential() {
|
|
||||||
root.requireCredential();
|
|
||||||
authenticate = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Poster with(String key, int 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) {
|
|
||||||
return _with(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Poster _with(String key, Object value) {
|
|
||||||
if (value!=null) {
|
|
||||||
args.add(new Entry(key,value));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void to(String tailApiUrl) throws IOException {
|
|
||||||
to(tailApiUrl,null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POSTs the form to the specified URL.
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* if the server returns 4xx/5xx responses.
|
|
||||||
* @return
|
|
||||||
* {@link Reader} that reads the response.
|
|
||||||
*/
|
|
||||||
public <T> T to(String tailApiUrl, Class<T> type) throws IOException {
|
|
||||||
return to(tailApiUrl,type,"POST");
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T to(String tailApiUrl, Class<T> type, String method) throws IOException {
|
|
||||||
while (true) {// loop while API rate limit is hit
|
|
||||||
HttpURLConnection uc = (HttpURLConnection) root.getApiURL(v,tailApiUrl).openConnection();
|
|
||||||
|
|
||||||
uc.setDoOutput(true);
|
|
||||||
uc.setRequestProperty("Content-type","application/x-www-form-urlencoded");
|
|
||||||
if (authenticate) {
|
|
||||||
if (v==ApiVersion.V3) {
|
|
||||||
if (root.oauthAccessToken!=null) {
|
|
||||||
uc.setRequestProperty("Authorization", "token " + root.oauthAccessToken);
|
|
||||||
} else {
|
|
||||||
if (root.password==null)
|
|
||||||
throw new IllegalArgumentException("V3 API doesn't support API token");
|
|
||||||
uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
uc.setRequestMethod(method);
|
|
||||||
} catch (ProtocolException e) {
|
|
||||||
// JDK only allows one of the fixed set of verbs. Try to override that
|
|
||||||
try {
|
|
||||||
Field $method = HttpURLConnection.class.getDeclaredField("method");
|
|
||||||
$method.setAccessible(true);
|
|
||||||
$method.set(uc,method);
|
|
||||||
} catch (Exception x) {
|
|
||||||
throw (IOException)new IOException("Failed to set the custom verb").initCause(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (v==ApiVersion.V2) {
|
|
||||||
StringBuilder body = new StringBuilder();
|
|
||||||
for (Entry e : args) {
|
|
||||||
if (body.length()>0) body.append('&');
|
|
||||||
body.append(e.toFormArg());
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputStreamWriter o = new OutputStreamWriter(uc.getOutputStream(), "UTF-8");
|
|
||||||
o.write(body.toString());
|
|
||||||
o.close();
|
|
||||||
} else {
|
|
||||||
Map json = new HashMap();
|
|
||||||
for (Entry e : args) {
|
|
||||||
json.put(e.key, e.value);
|
|
||||||
}
|
|
||||||
MAPPER.writeValue(uc.getOutputStream(),json);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
InputStreamReader r = new InputStreamReader(uc.getInputStream(), "UTF-8");
|
|
||||||
String data = IOUtils.toString(r);
|
|
||||||
if (type==null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return MAPPER.readValue(data,type);
|
|
||||||
} catch (IOException e) {
|
|
||||||
root.handleApiError(e,uc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
348
src/main/java/org/kohsuke/github/Requester.java
Normal file
348
src/main/java/org/kohsuke/github/Requester.java
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.ProtocolException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
import static org.kohsuke.github.GitHub.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A builder pattern for making HTTP call and parsing its output.
|
||||||
|
*
|
||||||
|
* @author Kohsuke Kawaguchi
|
||||||
|
*/
|
||||||
|
class Requester {
|
||||||
|
private final GitHub root;
|
||||||
|
private final List<Entry> args = new ArrayList<Entry>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request method.
|
||||||
|
*/
|
||||||
|
private String method = "POST";
|
||||||
|
|
||||||
|
private static class Entry {
|
||||||
|
String key;
|
||||||
|
Object value;
|
||||||
|
|
||||||
|
private Entry(String key, Object value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Requester(GitHub root) {
|
||||||
|
this.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a request with authentication credential.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public Requester withCredential() {
|
||||||
|
// keeping it inline with retrieveWithAuth not to enforce the check
|
||||||
|
// root.requireCredential();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Requester with(String key, int value) {
|
||||||
|
return _with(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Requester with(String key, Integer value) {
|
||||||
|
if (value!=null)
|
||||||
|
_with(key, value.intValue());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Requester with(String key, boolean value) {
|
||||||
|
return _with(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Requester with(String key, String value) {
|
||||||
|
return _with(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Requester with(String key, Collection<String> value) {
|
||||||
|
return _with(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Requester with(String key, Map<String, String> value) {
|
||||||
|
return _with(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Requester _with(String key, Object value) {
|
||||||
|
if (value!=null) {
|
||||||
|
args.add(new Entry(key,value));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Requester method(String method) {
|
||||||
|
this.method = method;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void to(String tailApiUrl) throws IOException {
|
||||||
|
to(tailApiUrl,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a request to the specified URL, and parses the response into the given type via databinding.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* if the server returns 4xx/5xx responses.
|
||||||
|
* @return
|
||||||
|
* {@link Reader} that reads the response.
|
||||||
|
*/
|
||||||
|
public <T> T to(String tailApiUrl, Class<T> type) throws IOException {
|
||||||
|
return _to(tailApiUrl, type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like {@link #to(String, Class)} but updates an existing object instead of creating a new instance.
|
||||||
|
*/
|
||||||
|
public <T> T to(String tailApiUrl, T existingInstance) throws IOException {
|
||||||
|
return _to(tailApiUrl, null, existingInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Short for {@code method(method).to(tailApiUrl,type)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public <T> T to(String tailApiUrl, Class<T> type, String method) throws IOException {
|
||||||
|
return method(method).to(tailApiUrl,type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T _to(String tailApiUrl, Class<T> type, T instance) throws IOException {
|
||||||
|
while (true) {// loop while API rate limit is hit
|
||||||
|
HttpURLConnection uc = setupConnection(root.getApiURL(tailApiUrl));
|
||||||
|
|
||||||
|
if (!method.equals("GET")) {
|
||||||
|
uc.setDoOutput(true);
|
||||||
|
uc.setRequestProperty("Content-type","application/x-www-form-urlencoded");
|
||||||
|
|
||||||
|
Map json = new HashMap();
|
||||||
|
for (Entry e : args) {
|
||||||
|
json.put(e.key, e.value);
|
||||||
|
}
|
||||||
|
MAPPER.writeValue(uc.getOutputStream(),json);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return parse(uc,type,instance);
|
||||||
|
} catch (IOException e) {
|
||||||
|
handleApiError(e,uc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads pagenated resources.
|
||||||
|
*
|
||||||
|
* Every iterator call reports a new batch.
|
||||||
|
*/
|
||||||
|
/*package*/ <T> Iterator<T> asIterator(final String tailApiUrl, final Class<T> type) {
|
||||||
|
method("GET");
|
||||||
|
if (!args.isEmpty()) throw new IllegalStateException();
|
||||||
|
|
||||||
|
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 = root.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(url);
|
||||||
|
try {
|
||||||
|
next = parse(uc,type,null);
|
||||||
|
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(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 (root.encodedAuthorization!=null && root.oauthAccessToken == null)
|
||||||
|
uc.setRequestProperty("Authorization", "Basic " + root.encodedAuthorization);
|
||||||
|
|
||||||
|
try {
|
||||||
|
uc.setRequestMethod(method);
|
||||||
|
} catch (ProtocolException e) {
|
||||||
|
// JDK only allows one of the fixed set of verbs. Try to override that
|
||||||
|
try {
|
||||||
|
Field $method = HttpURLConnection.class.getDeclaredField("method");
|
||||||
|
$method.setAccessible(true);
|
||||||
|
$method.set(uc,method);
|
||||||
|
} catch (Exception x) {
|
||||||
|
throw (IOException)new IOException("Failed to set the custom verb").initCause(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uc.setRequestProperty("Accept-Encoding", "gzip");
|
||||||
|
return uc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T parse(HttpURLConnection uc, Class<T> type, T instance) throws IOException {
|
||||||
|
InputStreamReader r = null;
|
||||||
|
try {
|
||||||
|
r = new InputStreamReader(wrapStream(uc, uc.getInputStream()), "UTF-8");
|
||||||
|
String data = IOUtils.toString(r);
|
||||||
|
if (type!=null)
|
||||||
|
return MAPPER.readValue(data,type);
|
||||||
|
if (instance!=null)
|
||||||
|
return MAPPER.readerForUpdating(instance).<T>readValue(data);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the "Content-Encoding" header.
|
||||||
|
*/
|
||||||
|
private InputStream wrapStream(HttpURLConnection uc, InputStream in) throws IOException {
|
||||||
|
String encoding = uc.getContentEncoding();
|
||||||
|
if (encoding==null || in==null) return in;
|
||||||
|
if (encoding.equals("gzip")) return new GZIPInputStream(in);
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Unexpected Content-Encoding: "+encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the error is because of the API limit, wait 10 sec and return normally.
|
||||||
|
* Otherwise throw an exception reporting an error.
|
||||||
|
*/
|
||||||
|
/*package*/ void handleApiError(IOException e, HttpURLConnection uc) throws IOException {
|
||||||
|
if ("0".equals(uc.getHeaderField("X-RateLimit-Remaining"))) {
|
||||||
|
// API limit reached. wait 10 secs and return normally
|
||||||
|
try {
|
||||||
|
Thread.sleep(10000);
|
||||||
|
return;
|
||||||
|
} catch (InterruptedException _) {
|
||||||
|
throw (InterruptedIOException)new InterruptedIOException().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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
What is this?
|
|
||||||
|
|
||||||
This library defines an object oriented representation of the GitHub API. The library doesn't yet cover the entirety of the GitHub API, but it's implemented with the right abstractions and libraries to make it very easy to improve the coverage.
|
|
||||||
|
|
||||||
Sample Usage
|
|
||||||
|
|
||||||
------------------
|
|
||||||
GitHub github = GitHub.connect();
|
|
||||||
GHRepository repo = github.createRepository(
|
|
||||||
"new-repository","this is my new repository",
|
|
||||||
"http://www.kohsuke.org/",true/*public*/);
|
|
||||||
repo.addCollaborators(github.getUser("abayer"),github.getUser("rtyler"));
|
|
||||||
repo.delete();
|
|
||||||
------------------
|
|
||||||
|
|
||||||
Credential
|
|
||||||
|
|
||||||
This library allows the caller to supply the credential as parameters, but it also defines a common convention
|
|
||||||
so that applications using this library will look at the consistent location. In this convention, the library
|
|
||||||
looks at "~/.github" property file, which should have the following two values:
|
|
||||||
|
|
||||||
------------------
|
|
||||||
login=kohsuke
|
|
||||||
token=012345678
|
|
||||||
------------------
|
|
||||||
36
src/site/markdown/index.md
Normal file
36
src/site/markdown/index.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
What is this?
|
||||||
|
=====
|
||||||
|
|
||||||
|
This library defines an object oriented representation of the GitHub API. By "object oriented" we mean
|
||||||
|
there are classes that correspond to the domain model of GitHub (such as `GHUser` and `GHRepository`),
|
||||||
|
operations that act on them as defined as methods (such as `GHUser.follow()`), and those object references
|
||||||
|
are used in favor of using string handle (such as `GHUser.isMemberOf(GHOrganization)` instead of
|
||||||
|
`GHUser.isMemberOf(String)`)
|
||||||
|
|
||||||
|
There are some corners of the GitHub API that's not yet implemented, but
|
||||||
|
the library is implemented with the right abstractions and libraries to make it very easy to improve the coverage.
|
||||||
|
|
||||||
|
Sample Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
GitHub github = GitHub.connect();
|
||||||
|
GHRepository repo = github.createRepository(
|
||||||
|
"new-repository","this is my new repository",
|
||||||
|
"http://www.kohsuke.org/",true/*public*/);
|
||||||
|
repo.addCollaborators(github.getUser("abayer"),github.getUser("rtyler"));
|
||||||
|
repo.delete();
|
||||||
|
|
||||||
|
Credential
|
||||||
|
----
|
||||||
|
|
||||||
|
This library allows the caller to supply the credential as parameters, but it also defines a common convention
|
||||||
|
so that applications using this library will look at the consistent location. In this convention, the library
|
||||||
|
looks at `~/.github` property file, which should have the following two values:
|
||||||
|
|
||||||
|
login=kohsuke
|
||||||
|
password=012345678
|
||||||
|
|
||||||
|
Alternatively, you can have just the OAuth token in this file:
|
||||||
|
|
||||||
|
oauth=4d98173f7c075527cb64878561d1fe70
|
||||||
|
|
||||||
@@ -4,16 +4,21 @@ import junit.framework.TestCase;
|
|||||||
import org.kohsuke.github.GHCommit;
|
import org.kohsuke.github.GHCommit;
|
||||||
import org.kohsuke.github.GHCommit.File;
|
import org.kohsuke.github.GHCommit.File;
|
||||||
import org.kohsuke.github.GHCommitComment;
|
import org.kohsuke.github.GHCommitComment;
|
||||||
|
import org.kohsuke.github.GHCommitStatus;
|
||||||
import org.kohsuke.github.GHEvent;
|
import org.kohsuke.github.GHEvent;
|
||||||
import org.kohsuke.github.GHEventInfo;
|
import org.kohsuke.github.GHEventInfo;
|
||||||
import org.kohsuke.github.GHEventPayload;
|
import org.kohsuke.github.GHEventPayload;
|
||||||
import org.kohsuke.github.GHHook;
|
import org.kohsuke.github.GHHook;
|
||||||
import org.kohsuke.github.GHBranch;
|
import org.kohsuke.github.GHBranch;
|
||||||
|
import org.kohsuke.github.GHIssue;
|
||||||
|
import org.kohsuke.github.GHIssueComment;
|
||||||
import org.kohsuke.github.GHIssueState;
|
import org.kohsuke.github.GHIssueState;
|
||||||
import org.kohsuke.github.GHKey;
|
import org.kohsuke.github.GHKey;
|
||||||
|
import org.kohsuke.github.GHMilestone;
|
||||||
import org.kohsuke.github.GHMyself;
|
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;
|
||||||
@@ -31,24 +36,87 @@ import java.util.List;
|
|||||||
* Unit test for simple App.
|
* Unit test for simple App.
|
||||||
*/
|
*/
|
||||||
public class AppTest extends TestCase {
|
public class AppTest extends TestCase {
|
||||||
|
|
||||||
|
private GitHub gitHub;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
gitHub = GitHub.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRepoCRUD() throws Exception {
|
||||||
|
GHRepository r = gitHub.createRepository("github-api-test", "a test repository", "http://github-api.kohsuke.org/", true);
|
||||||
|
r.enableIssueTracker(false);
|
||||||
|
r.enableDownloads(false);
|
||||||
|
r.enableWiki(false);
|
||||||
|
r.renameTo("github-api-test2");
|
||||||
|
gitHub.getMyself().getRepository("github-api-test2").delete();
|
||||||
|
}
|
||||||
|
|
||||||
public void testCredentialValid() throws IOException {
|
public void testCredentialValid() throws IOException {
|
||||||
assertTrue(GitHub.connect().isCredentialValid());
|
assertTrue(gitHub.isCredentialValid());
|
||||||
assertFalse(GitHub.connect("totally","bogus").isCredentialValid());
|
assertFalse(GitHub.connect("totally", "bogus").isCredentialValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIssueWithNoComment() throws IOException {
|
||||||
|
GHRepository repository = gitHub.getRepository("kohsuke/test");
|
||||||
|
List<GHIssueComment> v = repository.getIssue(4).getComments();
|
||||||
|
System.out.println(v);
|
||||||
|
assertTrue(v.isEmpty());
|
||||||
|
|
||||||
|
v = repository.getIssue(3).getComments();
|
||||||
|
System.out.println(v);
|
||||||
|
assertTrue(v.size() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateIssue() throws IOException {
|
||||||
|
GHUser u = gitHub.getUser("kohsuke");
|
||||||
|
GHRepository r = u.getRepository("test");
|
||||||
|
GHMilestone someMilestone = r.listMilestones(GHIssueState.CLOSED).iterator().next();
|
||||||
|
GHIssue o = r.createIssue("testing").body("this is body").assignee(u).label("bug").label("question").milestone(someMilestone).create();
|
||||||
|
System.out.println(o.getUrl());
|
||||||
|
o.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRateLimit() throws IOException {
|
||||||
|
System.out.println(gitHub.getRateLimit());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMyOrganizations() throws IOException {
|
||||||
|
Map<String, GHOrganization> org = gitHub.getMyOrganizations();
|
||||||
|
assertFalse(org.keySet().contains(null));
|
||||||
|
System.out.println(org);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFetchPullRequest() throws Exception {
|
public void testFetchPullRequest() throws Exception {
|
||||||
GitHub gh = GitHub.connect();
|
GHRepository r = gitHub.getOrganization("jenkinsci").getRepository("jenkins");
|
||||||
GHRepository r = gh.getOrganization("jenkinsci").getRepository("jenkins");
|
|
||||||
assertEquals("master",r.getMasterBranch());
|
assertEquals("master",r.getMasterBranch());
|
||||||
r.getPullRequest(1);
|
r.getPullRequest(1);
|
||||||
r.getPullRequests(GHIssueState.OPEN);
|
r.getPullRequests(GHIssueState.OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testFetchPullRequestAsList() throws Exception {
|
||||||
|
GHRepository r = gitHub.getOrganization("symfony").getRepository("symfony-docs");
|
||||||
|
assertEquals("master", r.getMasterBranch());
|
||||||
|
PagedIterable<GHPullRequest> i = r.listPullRequests(GHIssueState.CLOSED);
|
||||||
|
List<GHPullRequest> prs = i.asList();
|
||||||
|
assertNotNull(prs);
|
||||||
|
assertTrue(prs.size() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRepoPermissions() throws Exception {
|
||||||
|
GHRepository r = gitHub.getOrganization("jenkinsci").getRepository("jenkins");
|
||||||
|
assertTrue(r.hasPullAccess());
|
||||||
|
|
||||||
|
r = gitHub.getOrganization("github").getRepository("tire");
|
||||||
|
assertFalse(r.hasAdminAccess());
|
||||||
|
}
|
||||||
|
|
||||||
public void tryGetMyself() throws Exception {
|
public void testGetMyself() throws Exception {
|
||||||
GitHub hub = GitHub.connect();
|
GHMyself me = gitHub.getMyself();
|
||||||
GHMyself me = hub.getMyself();
|
|
||||||
System.out.println(me);
|
System.out.println(me);
|
||||||
GHUser u = hub.getUser("kohsuke2");
|
GHUser u = gitHub.getUser("kohsuke2");
|
||||||
System.out.println(u);
|
System.out.println(u);
|
||||||
for (List<GHRepository> lst : me.iterateRepositories(100)) {
|
for (List<GHRepository> lst : me.iterateRepositories(100)) {
|
||||||
for (GHRepository r : lst) {
|
for (GHRepository r : lst) {
|
||||||
@@ -58,36 +126,30 @@ public class AppTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testPublicKeys() throws Exception {
|
public void testPublicKeys() throws Exception {
|
||||||
GitHub gh = GitHub.connect();
|
List<GHKey> keys = gitHub.getMyself().getPublicKeys();
|
||||||
List<GHKey> keys = gh.getMyself().getPublicKeys();
|
|
||||||
System.out.println(keys);
|
System.out.println(keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tryOrgFork() throws Exception {
|
public void tryOrgFork() throws Exception {
|
||||||
GitHub gh = GitHub.connect();
|
gitHub.getUser("kohsuke").getRepository("rubywm").forkTo(gitHub.getOrganization("jenkinsci"));
|
||||||
gh.getUser("kohsuke").getRepository("rubywm").forkTo(gh.getOrganization("jenkinsci"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tryGetTeamsForRepo() throws Exception {
|
public void tryGetTeamsForRepo() throws Exception {
|
||||||
GitHub gh = GitHub.connect();
|
Set<GHTeam> o = gitHub.getOrganization("jenkinsci").getRepository("rubywm").getTeams();
|
||||||
Set<GHTeam> o = gh.getOrganization("jenkinsci").getRepository("rubywm").getTeams();
|
|
||||||
System.out.println(o);
|
System.out.println(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMembership() throws Exception {
|
public void testMembership() throws Exception {
|
||||||
GitHub gitHub = GitHub.connect();
|
|
||||||
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 {
|
public void testMemberOrgs() throws Exception {
|
||||||
GitHub gitHub = GitHub.connect();
|
|
||||||
Set<GHOrganization> o = gitHub.getUser("kohsuke").getOrganizations();
|
Set<GHOrganization> o = gitHub.getUser("kohsuke").getOrganizations();
|
||||||
System.out.println(o);
|
System.out.println(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCommit() throws Exception {
|
public void testCommit() throws Exception {
|
||||||
GitHub gitHub = GitHub.connect();
|
|
||||||
GHCommit commit = gitHub.getUser("jenkinsci").getRepository("jenkins").getCommit("08c1c9970af4d609ae754fbe803e06186e3206f7");
|
GHCommit commit = gitHub.getUser("jenkinsci").getRepository("jenkins").getCommit("08c1c9970af4d609ae754fbe803e06186e3206f7");
|
||||||
System.out.println(commit);
|
System.out.println(commit);
|
||||||
assertEquals(1, commit.getParents().size());
|
assertEquals(1, commit.getParents().size());
|
||||||
@@ -96,11 +158,10 @@ public class AppTest extends TestCase {
|
|||||||
File f = commit.getFiles().get(0);
|
File f = commit.getFiles().get(0);
|
||||||
assertEquals(48,f.getLinesChanged());
|
assertEquals(48,f.getLinesChanged());
|
||||||
assertEquals("modified",f.getStatus());
|
assertEquals("modified",f.getStatus());
|
||||||
assertEquals("changelog.html",f.getFileName());
|
assertEquals("changelog.html", f.getFileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testListCommits() throws Exception {
|
public void testListCommits() throws Exception {
|
||||||
GitHub gitHub = GitHub.connect();
|
|
||||||
List<String> sha1 = new ArrayList<String>();
|
List<String> sha1 = new ArrayList<String>();
|
||||||
for (GHCommit c : gitHub.getUser("kohsuke").getRepository("empty-commit").listCommits()) {
|
for (GHCommit c : gitHub.getUser("kohsuke").getRepository("empty-commit").listCommits()) {
|
||||||
System.out.println(c.getSHA1());
|
System.out.println(c.getSHA1());
|
||||||
@@ -111,14 +172,12 @@ public class AppTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testBranches() throws Exception {
|
public void testBranches() throws Exception {
|
||||||
GitHub gitHub = GitHub.connect();
|
|
||||||
Map<String,GHBranch> b =
|
Map<String,GHBranch> b =
|
||||||
gitHub.getUser("jenkinsci").getRepository("jenkins").getBranches();
|
gitHub.getUser("jenkinsci").getRepository("jenkins").getBranches();
|
||||||
System.out.println(b);
|
System.out.println(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCommitComment() throws Exception {
|
public void testCommitComment() throws Exception {
|
||||||
GitHub gitHub = GitHub.connect();
|
|
||||||
GHRepository r = gitHub.getUser("jenkinsci").getRepository("jenkins");
|
GHRepository r = gitHub.getUser("jenkinsci").getRepository("jenkins");
|
||||||
PagedIterable<GHCommitComment> comments = r.listCommitComments();
|
PagedIterable<GHCommitComment> comments = r.listCommitComments();
|
||||||
List<GHCommitComment> batch = comments.iterator().nextPage();
|
List<GHCommitComment> batch = comments.iterator().nextPage();
|
||||||
@@ -128,9 +187,8 @@ public class AppTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tryCreateCommitComment() throws Exception {
|
public void testCreateCommitComment() throws Exception {
|
||||||
GitHub gitHub = GitHub.connect();
|
GHCommit commit = gitHub.getUser("johnou").getRepository("sandbox-ant").getCommit("8ae38db0ea5837313ab5f39d43a6f73de3bd9000");
|
||||||
GHCommit commit = gitHub.getUser("kohsuke").getRepository("sandbox-ant").getCommit("8ae38db0ea5837313ab5f39d43a6f73de3bd9000");
|
|
||||||
GHCommitComment c = commit.createComment("[testing](http://kohsuse.org/)");
|
GHCommitComment c = commit.createComment("[testing](http://kohsuse.org/)");
|
||||||
System.out.println(c);
|
System.out.println(c);
|
||||||
c.update("updated text");
|
c.update("updated text");
|
||||||
@@ -139,7 +197,6 @@ public class AppTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void tryHook() throws Exception {
|
public void tryHook() throws Exception {
|
||||||
GitHub gitHub = GitHub.connect();
|
|
||||||
GHRepository r = gitHub.getMyself().getRepository("test2");
|
GHRepository r = gitHub.getMyself().getRepository("test2");
|
||||||
GHHook hook = r.createWebHook(new URL("http://www.google.com/"));
|
GHHook hook = r.createWebHook(new URL("http://www.google.com/"));
|
||||||
System.out.println(hook);
|
System.out.println(hook);
|
||||||
@@ -149,7 +206,6 @@ public class AppTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testEventApi() throws Exception {
|
public void testEventApi() throws Exception {
|
||||||
GitHub gitHub = GitHub.connect();
|
|
||||||
for (GHEventInfo ev : gitHub.getEvents()) {
|
for (GHEventInfo ev : gitHub.getEvents()) {
|
||||||
System.out.println(ev);
|
System.out.println(ev);
|
||||||
if (ev.getType()==GHEvent.PULL_REQUEST) {
|
if (ev.getType()==GHEvent.PULL_REQUEST) {
|
||||||
@@ -161,10 +217,9 @@ public class AppTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testApp() throws IOException {
|
public void testApp() throws IOException {
|
||||||
GitHub gitHub = GitHub.connect();
|
|
||||||
System.out.println(gitHub.getMyself().getEmails());
|
System.out.println(gitHub.getMyself().getEmails());
|
||||||
|
|
||||||
// GHRepository r = gitHub.connect().getOrganization("jenkinsci").createRepository("kktest4", "Kohsuke's test", "http://kohsuke.org/", "Everyone", true);
|
// GHRepository r = gitHub.getOrganization("jenkinsci").createRepository("kktest4", "Kohsuke's test", "http://kohsuke.org/", "Everyone", true);
|
||||||
// r.fork();
|
// r.fork();
|
||||||
|
|
||||||
// tryDisablingIssueTrackers(gitHub);
|
// tryDisablingIssueTrackers(gitHub);
|
||||||
@@ -191,7 +246,7 @@ public class AppTest extends TestCase {
|
|||||||
// t.remove(gitHub.getMyself());
|
// t.remove(gitHub.getMyself());
|
||||||
// System.out.println(t.getMembers());
|
// System.out.println(t.getMembers());
|
||||||
|
|
||||||
// GHRepository r = GitHub.connect().getOrganization("HudsonLabs").createRepository("auto-test", "some description", "http://kohsuke.org/", "Plugin Developers", true);
|
// GHRepository r = gitHub.getOrganization("HudsonLabs").createRepository("auto-test", "some description", "http://kohsuke.org/", "Plugin Developers", true);
|
||||||
|
|
||||||
// r.
|
// r.
|
||||||
// GitHub hub = GitHub.connectAnonymously();
|
// GitHub hub = GitHub.connectAnonymously();
|
||||||
@@ -234,11 +289,6 @@ public class AppTest extends TestCase {
|
|||||||
gitHub.getUser("kohsuke").getRepository("test").renameTo("test2");
|
gitHub.getUser("kohsuke").getRepository("test").renameTo("test2");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryOrgFork(GitHub gitHub) throws IOException {
|
|
||||||
GHOrganization o = gitHub.getOrganization("HudsonLabs");
|
|
||||||
System.out.println(gitHub.getUser("rtyler").getRepository("memcache-ada").forkTo(o).getUrl());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tryTeamCreation(GitHub gitHub) throws IOException {
|
private void tryTeamCreation(GitHub gitHub) throws IOException {
|
||||||
GHOrganization o = gitHub.getOrganization("HudsonLabs");
|
GHOrganization o = gitHub.getOrganization("HudsonLabs");
|
||||||
GHTeam t = o.createTeam("auto team", Permission.PUSH);
|
GHTeam t = o.createTeam("auto team", Permission.PUSH);
|
||||||
@@ -255,7 +305,6 @@ public class AppTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testOrgRepositories() throws IOException {
|
public void testOrgRepositories() throws IOException {
|
||||||
GitHub gitHub = GitHub.connect();
|
|
||||||
GHOrganization j = gitHub.getOrganization("jenkinsci");
|
GHOrganization j = gitHub.getOrganization("jenkinsci");
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
Map<String, GHRepository> repos = j.getRepositories();
|
Map<String, GHRepository> repos = j.getRepositories();
|
||||||
@@ -264,7 +313,6 @@ public class AppTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testOrganization() throws IOException {
|
public void testOrganization() throws IOException {
|
||||||
GitHub gitHub = GitHub.connect();
|
|
||||||
GHOrganization j = gitHub.getOrganization("jenkinsci");
|
GHOrganization j = gitHub.getOrganization("jenkinsci");
|
||||||
GHTeam t = j.getTeams().get("Core Developers");
|
GHTeam t = j.getTeams().get("Core Developers");
|
||||||
|
|
||||||
@@ -272,4 +320,35 @@ public class AppTest extends TestCase {
|
|||||||
|
|
||||||
// t.add(labs.getRepository("xyz"));
|
// t.add(labs.getRepository("xyz"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testCommitStatus() throws Exception {
|
||||||
|
GHRepository r = gitHub.getUser("kohsuke").getRepository("test");
|
||||||
|
GHCommitStatus state;
|
||||||
|
// state = r.createCommitStatus("edacdd76b06c5f3f0697a22ca75803169f25f296", GHCommitState.FAILURE, "http://jenkins-ci.org/", "oops!");
|
||||||
|
|
||||||
|
List<GHCommitStatus> lst = r.listCommitStatuses("edacdd76b06c5f3f0697a22ca75803169f25f296").asList();
|
||||||
|
state = lst.get(0);
|
||||||
|
System.out.println(state);
|
||||||
|
assertEquals("oops!",state.getDescription());
|
||||||
|
assertEquals("http://jenkins-ci.org/",state.getTargetUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPullRequestPopulate() throws Exception {
|
||||||
|
GHRepository r = gitHub.getUser("kohsuke").getRepository("github-api");
|
||||||
|
GHPullRequest p = r.getPullRequest(17);
|
||||||
|
GHUser u = p.getUser();
|
||||||
|
assertNotNull(u.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCheckMembership() throws Exception {
|
||||||
|
GHOrganization j = gitHub.getOrganization("jenkinsci");
|
||||||
|
GHUser kohsuke = gitHub.getUser("kohsuke");
|
||||||
|
GHUser a = gitHub.getUser("a");
|
||||||
|
|
||||||
|
assertTrue(j.hasMember(kohsuke));
|
||||||
|
assertFalse(j.hasMember(a));
|
||||||
|
|
||||||
|
assertTrue(j.hasPublicMember(kohsuke));
|
||||||
|
assertFalse(j.hasPublicMember(a));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/test/java/org/kohsuke/github/GitHubTest.java
Normal file
24
src/test/java/org/kohsuke/github/GitHubTest.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package org.kohsuke.github;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test for {@link GitHub}.
|
||||||
|
*/
|
||||||
|
public class GitHubTest extends TestCase {
|
||||||
|
|
||||||
|
public void testGitHubServerWithHttp() throws Exception {
|
||||||
|
GitHub hub = GitHub.connectToEnterprise("http://enterprise.kohsuke.org/api/v3", "kohsuke", "token");
|
||||||
|
assertEquals("http://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGitHubServerWithHttps() throws Exception {
|
||||||
|
GitHub hub = GitHub.connectToEnterprise("https://enterprise.kohsuke.org/api/v3", "kohsuke", "token");
|
||||||
|
assertEquals("https://enterprise.kohsuke.org/api/v3/test", hub.getApiURL("/test").toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGitHubServerWithoutServer() throws Exception {
|
||||||
|
GitHub hub = GitHub.connect("kohsuke", "token", "password");
|
||||||
|
assertEquals("https://api.github.com/test", hub.getApiURL("/test").toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user