mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-11 00:11:25 +00:00
Compare commits
181 Commits
github-api
...
github-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b4d3a869b | ||
|
|
eeebb1b59f | ||
|
|
63136f64b7 | ||
|
|
1d2fbf2d92 | ||
|
|
1e52dded14 | ||
|
|
cfc7005275 | ||
|
|
f23afcd5aa | ||
|
|
4e88a0c91b | ||
|
|
d070f9deb0 | ||
|
|
b736e20a74 | ||
|
|
aad20d0a03 | ||
|
|
7ff97348d9 | ||
|
|
68dda3a46d | ||
|
|
2cd44f8c33 | ||
|
|
9775954aff | ||
|
|
1a071b0b54 | ||
|
|
8dcea59c74 | ||
|
|
f482f77871 | ||
|
|
b058c39ee1 | ||
|
|
b926b6c67f | ||
|
|
3fb8e5f799 | ||
|
|
277ccb5188 | ||
|
|
9ebc9c0867 | ||
|
|
f1f96713a4 | ||
|
|
fc3b6d2c2e | ||
|
|
d0d0716b3b | ||
|
|
73119afeff | ||
|
|
8939179be8 | ||
|
|
adba2e68db | ||
|
|
0ef8b471a3 | ||
|
|
205950fc5f | ||
|
|
8835b2c745 | ||
|
|
74fda40764 | ||
|
|
687a36937e | ||
|
|
2c7b8bd6e8 | ||
|
|
e9417f5fa1 | ||
|
|
5e08b34c43 | ||
|
|
7b436ffb3b | ||
|
|
1ee2ec3728 | ||
|
|
ed28768146 | ||
|
|
f931835176 | ||
|
|
0cf9bc2814 | ||
|
|
8b428f2c93 | ||
|
|
10238dbcd3 | ||
|
|
6229e0928d | ||
|
|
5c7b259fe9 | ||
|
|
cc84c867c0 | ||
|
|
5bf252e12d | ||
|
|
75512ff66a | ||
|
|
6f4832476a | ||
|
|
86b0d27299 | ||
|
|
5a8845f7f6 | ||
|
|
709e47f32f | ||
|
|
77590b4eb3 | ||
|
|
72fc313135 | ||
|
|
39b32cee2e | ||
|
|
bdcee7c052 | ||
|
|
4093e53b5b | ||
|
|
a4c1c8de24 | ||
|
|
7ed234c875 | ||
|
|
0359160ac6 | ||
|
|
2478dad9b5 | ||
|
|
690292352b | ||
|
|
271d18cddc | ||
|
|
e1465639e7 | ||
|
|
ce7ca59339 | ||
|
|
76610b25d7 | ||
|
|
dfce0bda7c | ||
|
|
41c0dd9727 | ||
|
|
232c0389d3 | ||
|
|
d95c8a4ab0 | ||
|
|
374fdb37e1 | ||
|
|
f78530636e | ||
|
|
0bf81f4fb9 | ||
|
|
dcc3b7f36b | ||
|
|
d6722266f5 | ||
|
|
11566891dc | ||
|
|
9aaf69cc9a | ||
|
|
a716a59489 | ||
|
|
bad0d1bbcf | ||
|
|
aa43e265b7 | ||
|
|
67280951ff | ||
|
|
c3a9f6f9f5 | ||
|
|
e631e46dd1 | ||
|
|
15163ffde0 | ||
|
|
b898284821 | ||
|
|
3bb7eb2e03 | ||
|
|
11fcb9d456 | ||
|
|
29f826448a | ||
|
|
a8cf4a7120 | ||
|
|
60dce94a47 | ||
|
|
c965b9cc24 | ||
|
|
762a32eb6d | ||
|
|
541dac1aee | ||
|
|
e2e2329301 | ||
|
|
9afad71b0f | ||
|
|
7bbe0f7e8a | ||
|
|
d90adfa98e | ||
|
|
1dbcc4b776 | ||
|
|
18696fca2d | ||
|
|
c40100b6da | ||
|
|
6396818740 | ||
|
|
6df5a0d47b | ||
|
|
15c18c5547 | ||
|
|
4b6981c2e7 | ||
|
|
1b4025300c | ||
|
|
983c871bff | ||
|
|
609f532f8c | ||
|
|
c6fc03c73a | ||
|
|
b6e48cc4f9 | ||
|
|
50f43cc178 | ||
|
|
f421067a0d | ||
|
|
edd9a2d5b6 | ||
|
|
41e0329f55 | ||
|
|
21ea916e0d | ||
|
|
3b6ca3020e | ||
|
|
3737845b78 | ||
|
|
a30c78cd12 | ||
|
|
f8fba41a30 | ||
|
|
052902fb49 | ||
|
|
58143c26bc | ||
|
|
5d83894056 | ||
|
|
e35667525f | ||
|
|
2f318152d8 | ||
|
|
bc518a9ae8 | ||
|
|
425ae2d536 | ||
|
|
a6cacd4aba | ||
|
|
5a7083537c | ||
|
|
e15f7a59fd | ||
|
|
a2fa526aa0 | ||
|
|
7e959d6a87 | ||
|
|
5121fe1cbf | ||
|
|
3c3d4fc151 | ||
|
|
a7f75c9a6c | ||
|
|
e7262b8fbe | ||
|
|
af3099c526 | ||
|
|
2b9d47cea8 | ||
|
|
5db90d3fc4 | ||
|
|
372d5ff758 | ||
|
|
ebf39eaea1 | ||
|
|
556786f2e1 | ||
|
|
0f64994537 | ||
|
|
ac64c2022b | ||
|
|
9802132b6f | ||
|
|
4d6c5c14f1 | ||
|
|
d228a5fb93 | ||
|
|
7b46ef10c8 | ||
|
|
8eb9fba051 | ||
|
|
7b58182683 | ||
|
|
95fbf9274b | ||
|
|
09557dfa0f | ||
|
|
4029fcc1ca | ||
|
|
d6627b1e34 | ||
|
|
86d75fd767 | ||
|
|
e2220bb3b3 | ||
|
|
1a9b8bd1da | ||
|
|
9eda2d3f77 | ||
|
|
e6d59df705 | ||
|
|
db845850b2 | ||
|
|
d516597659 | ||
|
|
3af5a8145a | ||
|
|
31bebd4a7a | ||
|
|
ccb87258b0 | ||
|
|
2ab71e88bd | ||
|
|
78bd7585bb | ||
|
|
92cc81d9b8 | ||
|
|
97a1c741de | ||
|
|
077d693959 | ||
|
|
94831fc10a | ||
|
|
1f298a88b0 | ||
|
|
7e49946bed | ||
|
|
1e81ab1017 | ||
|
|
311180d12e | ||
|
|
0efb206881 | ||
|
|
0b92fa5615 | ||
|
|
a58a5b56b2 | ||
|
|
b9764c0a44 | ||
|
|
590f7ba511 | ||
|
|
449909b0e8 | ||
|
|
40780525f8 | ||
|
|
0e3707d1c3 |
19
pom.xml
19
pom.xml
@@ -3,11 +3,11 @@
|
||||
<parent>
|
||||
<groupId>org.kohsuke</groupId>
|
||||
<artifactId>pom</artifactId>
|
||||
<version>8</version>
|
||||
<version>14</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>github-api</artifactId>
|
||||
<version>1.56</version>
|
||||
<version>1.68</version>
|
||||
<name>GitHub API for Java</name>
|
||||
<url>http://github-api.kohsuke.org/</url>
|
||||
<description>GitHub API for Java</description>
|
||||
@@ -16,7 +16,7 @@
|
||||
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
|
||||
<url>http://${project.artifactId}.kohsuke.org/</url>
|
||||
<tag>github-api-1.56</tag>
|
||||
<tag>github-api-1.68</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
@@ -35,7 +35,7 @@
|
||||
<plugin>
|
||||
<groupId>com.infradna.tool</groupId>
|
||||
<artifactId>bridge-method-injector</artifactId>
|
||||
<version>1.12</version>
|
||||
<version>1.14</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
@@ -77,7 +77,7 @@
|
||||
<dependency>
|
||||
<groupId>com.infradna.tool</groupId>
|
||||
<artifactId>bridge-method-annotation</artifactId>
|
||||
<version>1.12</version>
|
||||
<version>1.14</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.kohsuke.stapler</groupId>
|
||||
@@ -107,6 +107,7 @@
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
@@ -138,4 +139,12 @@
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>User List</name>
|
||||
<post>github-api@googlegroups.com</post>
|
||||
<archive>https://groups.google.com/forum/#!forum/github-api</archive>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
</project>
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Asset in a release.
|
||||
*
|
||||
* @see GHRelease#getAssets()
|
||||
*/
|
||||
public class GHAsset {
|
||||
public class GHAsset extends GHObject {
|
||||
GitHub root;
|
||||
GHRepository owner;
|
||||
private String url;
|
||||
private String id;
|
||||
private String name;
|
||||
private String label;
|
||||
private String state;
|
||||
private String content_type;
|
||||
private long size;
|
||||
private long download_count;
|
||||
private Date created_at;
|
||||
private Date updated_at;
|
||||
private String browser_download_url;
|
||||
|
||||
public String getContentType() {
|
||||
return content_type;
|
||||
@@ -31,18 +28,10 @@ public class GHAsset {
|
||||
this.content_type = contentType;
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return created_at;
|
||||
}
|
||||
|
||||
public long getDownloadCount() {
|
||||
return download_count;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
@@ -72,12 +61,16 @@ public class GHAsset {
|
||||
return state;
|
||||
}
|
||||
|
||||
public Date getUpdatedAt() {
|
||||
return updated_at;
|
||||
/**
|
||||
* @deprecated This object has no HTML URL.
|
||||
*/
|
||||
@Override
|
||||
public URL getHtmlUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
public String getBrowserDownloadUrl() {
|
||||
return browser_download_url;
|
||||
}
|
||||
|
||||
private void edit(String key, Object value) throws IOException {
|
||||
|
||||
@@ -10,85 +10,83 @@ import java.util.List;
|
||||
*
|
||||
* @author janinko
|
||||
* @see GitHub#createToken(Collection, String, String)
|
||||
* @see http://developer.github.com/v3/oauth/#create-a-new-authorization
|
||||
* @see <a href="http://developer.github.com/v3/oauth/#create-a-new-authorization">API documentation</a>
|
||||
*/
|
||||
public class GHAuthorization {
|
||||
public static final String USER = "user";
|
||||
public static final String USER_EMAIL = "user:email";
|
||||
public static final String USER_FOLLOW = "user:follow";
|
||||
public static final String PUBLIC_REPO = "public_repo";
|
||||
public static final String REPO = "repo";
|
||||
public static final String REPO_STATUS = "repo:status";
|
||||
public static final String DELETE_REPO = "delete_repo";
|
||||
public static final String NOTIFICATIONS = "notifications";
|
||||
public static final String GIST = "gist";
|
||||
public class GHAuthorization extends GHObject {
|
||||
public static final String USER = "user";
|
||||
public static final String USER_EMAIL = "user:email";
|
||||
public static final String USER_FOLLOW = "user:follow";
|
||||
public static final String PUBLIC_REPO = "public_repo";
|
||||
public static final String REPO = "repo";
|
||||
public static final String REPO_STATUS = "repo:status";
|
||||
public static final String DELETE_REPO = "delete_repo";
|
||||
public static final String NOTIFICATIONS = "notifications";
|
||||
public static final String GIST = "gist";
|
||||
public static final String READ_HOOK = "read:repo_hook";
|
||||
public static final String WRITE_HOOK = "write:repo_hook";
|
||||
public static final String AMIN_HOOK = "admin:repo_hook";
|
||||
public static final String READ_ORG = "read:org";
|
||||
public static final String WRITE_ORG = "write:org";
|
||||
public static final String ADMIN_ORG = "admin:org";
|
||||
public static final String READ_KEY = "read:public_key";
|
||||
public static final String WRITE_KEY = "write:public_key";
|
||||
public static final String ADMIN_KEY = "admin:public_key";
|
||||
|
||||
private GitHub root;
|
||||
private int id;
|
||||
private String url;
|
||||
private List<String> scopes;
|
||||
private String token;
|
||||
private App app;
|
||||
private String note;
|
||||
private String note_url;
|
||||
private String updated_at;
|
||||
private String created_at;
|
||||
private GitHub root;
|
||||
private List<String> scopes;
|
||||
private String token;
|
||||
private App app;
|
||||
private String note;
|
||||
private String note_url;
|
||||
|
||||
public GitHub getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
public List<String> getScopes() {
|
||||
return scopes;
|
||||
}
|
||||
|
||||
public List<String> getScopes() {
|
||||
return scopes;
|
||||
}
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getToken(){
|
||||
return token;
|
||||
}
|
||||
|
||||
public URL getAppUrl(){
|
||||
public URL getAppUrl() {
|
||||
return GitHub.parseURL(app.url);
|
||||
}
|
||||
}
|
||||
|
||||
public String getAppName() {
|
||||
return app.name;
|
||||
}
|
||||
|
||||
public URL getApiURL(){
|
||||
public String getAppName() {
|
||||
return app.name;
|
||||
}
|
||||
|
||||
public URL getApiURL() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
}
|
||||
|
||||
public String getNote() {
|
||||
return note;
|
||||
}
|
||||
/**
|
||||
* @deprecated This object has no HTML URL.
|
||||
*/
|
||||
@Override
|
||||
public URL getHtmlUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public URL getNoteUrl(){
|
||||
public String getNote() {
|
||||
return note;
|
||||
}
|
||||
|
||||
public URL getNoteUrl() {
|
||||
return GitHub.parseURL(note_url);
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return GitHub.parseDate(created_at);
|
||||
}
|
||||
|
||||
public Date getUpdatedAt() {
|
||||
return GitHub.parseDate(updated_at);
|
||||
/*package*/ GHAuthorization wrap(GitHub root) {
|
||||
this.root = root;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*package*/ GHAuthorization wrap(GitHub root) {
|
||||
this.root = root;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static class App{
|
||||
private String url;
|
||||
private String name;
|
||||
}
|
||||
private static class App {
|
||||
private String url;
|
||||
private String name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,26 +32,26 @@ public class GHCommit {
|
||||
|
||||
private int comment_count;
|
||||
|
||||
@WithBridgeMethods(value=GHAuthor.class,castRequired=true)
|
||||
public GitUser getAuthor() {
|
||||
return author;
|
||||
}
|
||||
@WithBridgeMethods(value = GHAuthor.class, castRequired = true)
|
||||
public GitUser getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
@WithBridgeMethods(value=GHAuthor.class,castRequired=true)
|
||||
public GitUser getCommitter() {
|
||||
return committer;
|
||||
}
|
||||
@WithBridgeMethods(value = GHAuthor.class, castRequired = true)
|
||||
public GitUser getCommitter() {
|
||||
return committer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit message.
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public int getCommentCount() {
|
||||
return comment_count;
|
||||
}
|
||||
public int getCommentCount() {
|
||||
return comment_count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,14 +153,13 @@ public class GHCommit {
|
||||
Stats stats;
|
||||
List<Parent> parents;
|
||||
User author,committer;
|
||||
|
||||
|
||||
|
||||
|
||||
public ShortInfo getCommitShortInfo() {
|
||||
return commit;
|
||||
}
|
||||
return commit;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* The repository that contains the commit.
|
||||
*/
|
||||
public GHRepository getOwner() {
|
||||
|
||||
@@ -12,13 +12,11 @@ import java.util.Date;
|
||||
* @see GHCommit#listComments()
|
||||
* @see GHCommit#createComment(String, String, Integer, Integer)
|
||||
*/
|
||||
public class GHCommitComment {
|
||||
public class GHCommitComment extends GHObject {
|
||||
private GHRepository owner;
|
||||
|
||||
String updated_at, created_at;
|
||||
String body, url, html_url, commit_id;
|
||||
String body, html_url, commit_id;
|
||||
Integer line;
|
||||
int id;
|
||||
String path;
|
||||
User user;
|
||||
|
||||
@@ -32,14 +30,6 @@ public class GHCommitComment {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return GitHub.parseDate(created_at);
|
||||
}
|
||||
|
||||
public Date getUpdatedAt() {
|
||||
return GitHub.parseDate(updated_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL like 'https://github.com/kohsuke/sandbox-ant/commit/8ae38db0ea5837313ab5f39d43a6f73de3bd9000#commitcomment-1252827' to
|
||||
* show this commit comment in a browser.
|
||||
@@ -75,10 +65,6 @@ public class GHCommitComment {
|
||||
return line!=null ? line : -1;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user who put this comment.
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
*/
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Identifies a commit in {@link GHPullRequest}.
|
||||
*
|
||||
@@ -69,6 +71,13 @@ public class GHCommitPointer {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the commit that this pointer is referring to.
|
||||
*/
|
||||
public GHCommit getCommit() throws IOException {
|
||||
return getRepository().getCommit(getSha());
|
||||
}
|
||||
|
||||
void wrapUp(GitHub root) {
|
||||
if (user!=null) user.root = root;
|
||||
if (repo!=null) repo.wrap(root);
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Represents a status of a commit.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GHRepository#getCommitStatus(String)
|
||||
* @see GHCommit#getStatus()
|
||||
* @see GHRepository#getLastCommitStatus(String)
|
||||
* @see GHCommit#getLastStatus()
|
||||
*/
|
||||
public class GHCommitStatus {
|
||||
String created_at, updated_at;
|
||||
public class GHCommitStatus extends GHObject {
|
||||
String state;
|
||||
String target_url,description;
|
||||
int id;
|
||||
String url;
|
||||
String context;
|
||||
GHUser creator;
|
||||
|
||||
@@ -27,14 +25,6 @@ public class GHCommitStatus {
|
||||
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))
|
||||
@@ -56,22 +46,19 @@ public class GHCommitStatus {
|
||||
return description;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* API URL of this commit status.
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public GHUser getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
public String getContext() {
|
||||
return context;
|
||||
}
|
||||
public String getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This object has no HTML URL.
|
||||
*/
|
||||
@Override
|
||||
public URL getHtmlUrl() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,10 @@ public class GHCompare {
|
||||
public Commit[] getCommits() {
|
||||
return commits;
|
||||
}
|
||||
|
||||
|
||||
public GHCommit.File[] getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
public GHCompare wrap(GHRepository owner) {
|
||||
this.owner = owner;
|
||||
@@ -145,6 +148,6 @@ public class GHCompare {
|
||||
}
|
||||
|
||||
public static enum Status {
|
||||
behind, ahead, identical
|
||||
behind, ahead, identical, diverged
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
@@ -14,7 +16,13 @@ import javax.xml.bind.DatatypeConverter;
|
||||
*/
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public class GHContent {
|
||||
private GHRepository owner;
|
||||
/*
|
||||
In normal use of this class, repository field is set via wrap(),
|
||||
but in the code search API, there's a nested 'repository' field that gets populated from JSON.
|
||||
*/
|
||||
private GHRepository repository;
|
||||
|
||||
private GitHub root;
|
||||
|
||||
private String type;
|
||||
private String encoding;
|
||||
@@ -26,9 +34,10 @@ public class GHContent {
|
||||
private String url; // this is the API url
|
||||
private String git_url; // this is the Blob url
|
||||
private String html_url; // this is the UI
|
||||
private String download_url;
|
||||
|
||||
public GHRepository getOwner() {
|
||||
return owner;
|
||||
return repository;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
@@ -58,35 +67,34 @@ public class GHContent {
|
||||
/**
|
||||
* Retrieve the decoded content that is stored at this location.
|
||||
*
|
||||
* <p>
|
||||
* Due to the nature of GitHub's API, you're not guaranteed that
|
||||
* the content will already be populated, so this may trigger
|
||||
* network activity, and can throw an IOException.
|
||||
**/
|
||||
*
|
||||
* @deprecated
|
||||
* Use {@link #read()}
|
||||
*/
|
||||
public String getContent() throws IOException {
|
||||
return new String(DatatypeConverter.parseBase64Binary(getEncodedContent()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the raw content that is stored at this location.
|
||||
* Retrieve the base64-encoded content that is stored at this location.
|
||||
*
|
||||
* <p>
|
||||
* Due to the nature of GitHub's API, you're not guaranteed that
|
||||
* the content will already be populated, so this may trigger
|
||||
* network activity, and can throw an IOException.
|
||||
**/
|
||||
*
|
||||
* @deprecated
|
||||
* Use {@link #read()}
|
||||
*/
|
||||
public String getEncodedContent() throws IOException {
|
||||
if (content != null)
|
||||
if (content!=null)
|
||||
return content;
|
||||
|
||||
GHContent retrievedContent = owner.getFileContent(path);
|
||||
|
||||
this.size = retrievedContent.size;
|
||||
this.sha = retrievedContent.sha;
|
||||
this.content = retrievedContent.content;
|
||||
this.url = retrievedContent.url;
|
||||
this.git_url = retrievedContent.git_url;
|
||||
this.html_url = retrievedContent.html_url;
|
||||
|
||||
return content;
|
||||
else
|
||||
return Base64.encodeBase64String(IOUtils.toByteArray(read()));
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
@@ -101,6 +109,21 @@ public class GHContent {
|
||||
return html_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the actual content stored here.
|
||||
*/
|
||||
public InputStream read() throws IOException {
|
||||
return new Requester(root).asStream(getDownloadUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to retrieve the raw content of the file. Null if this is a directory.
|
||||
*/
|
||||
public String getDownloadUrl() throws IOException {
|
||||
populate();
|
||||
return download_url;
|
||||
}
|
||||
|
||||
public boolean isFile() {
|
||||
return "file".equals(type);
|
||||
}
|
||||
@@ -109,6 +132,16 @@ public class GHContent {
|
||||
return "dir".equals(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 synchronized void populate() throws IOException {
|
||||
if (download_url!=null) return; // already populated
|
||||
root.retrieve().to(url, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* List immediate children of this directory.
|
||||
*/
|
||||
@@ -118,10 +151,10 @@ public class GHContent {
|
||||
|
||||
return new PagedIterable<GHContent>() {
|
||||
public PagedIterator<GHContent> iterator() {
|
||||
return new PagedIterator<GHContent>(owner.root.retrieve().asIterator(url, GHContent[].class)) {
|
||||
return new PagedIterator<GHContent>(root.retrieve().asIterator(url, GHContent[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(GHContent[] page) {
|
||||
GHContent.wrap(page,owner);
|
||||
GHContent.wrap(page, repository);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -129,13 +162,21 @@ public class GHContent {
|
||||
}
|
||||
|
||||
public GHContentUpdateResponse update(String newContent, String commitMessage) throws IOException {
|
||||
return update(newContent, commitMessage, null);
|
||||
return update(newContent.getBytes(), commitMessage, null);
|
||||
}
|
||||
|
||||
public GHContentUpdateResponse update(String newContent, String commitMessage, String branch) throws IOException {
|
||||
String encodedContent = DatatypeConverter.printBase64Binary(newContent.getBytes());
|
||||
return update(newContent.getBytes(), commitMessage, branch);
|
||||
}
|
||||
|
||||
Requester requester = new Requester(owner.root)
|
||||
public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage) throws IOException {
|
||||
return update(newContentBytes, commitMessage, null);
|
||||
}
|
||||
|
||||
public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage, String branch) throws IOException {
|
||||
String encodedContent = DatatypeConverter.printBase64Binary(newContentBytes);
|
||||
|
||||
Requester requester = new Requester(root)
|
||||
.with("path", path)
|
||||
.with("message", commitMessage)
|
||||
.with("sha", sha)
|
||||
@@ -148,8 +189,8 @@ public class GHContent {
|
||||
|
||||
GHContentUpdateResponse response = requester.to(getApiRoute(), GHContentUpdateResponse.class);
|
||||
|
||||
response.getContent().wrap(owner);
|
||||
response.getCommit().wrapUp(owner);
|
||||
response.getContent().wrap(repository);
|
||||
response.getCommit().wrapUp(repository);
|
||||
|
||||
this.content = encodedContent;
|
||||
return response;
|
||||
@@ -160,7 +201,7 @@ public class GHContent {
|
||||
}
|
||||
|
||||
public GHContentUpdateResponse delete(String commitMessage, String branch) throws IOException {
|
||||
Requester requester = new Requester(owner.root)
|
||||
Requester requester = new Requester(root)
|
||||
.with("path", path)
|
||||
.with("message", commitMessage)
|
||||
.with("sha", sha)
|
||||
@@ -172,18 +213,26 @@ public class GHContent {
|
||||
|
||||
GHContentUpdateResponse response = requester.to(getApiRoute(), GHContentUpdateResponse.class);
|
||||
|
||||
response.getCommit().wrapUp(owner);
|
||||
response.getCommit().wrapUp(repository);
|
||||
return response;
|
||||
}
|
||||
|
||||
private String getApiRoute() {
|
||||
return "/repos/" + owner.getOwnerName() + "/" + owner.getName() + "/contents/" + path;
|
||||
return "/repos/" + repository.getOwnerName() + "/" + repository.getName() + "/contents/" + path;
|
||||
}
|
||||
|
||||
GHContent wrap(GHRepository owner) {
|
||||
this.owner = owner;
|
||||
this.repository = owner;
|
||||
this.root = owner.root;
|
||||
return this;
|
||||
}
|
||||
GHContent wrap(GitHub root) {
|
||||
this.root = root;
|
||||
if (repository!=null)
|
||||
repository.wrap(root);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public static GHContent[] wrap(GHContent[] contents, GHRepository repository) {
|
||||
for (GHContent unwrappedContent : contents) {
|
||||
|
||||
74
src/main/java/org/kohsuke/github/GHContentSearchBuilder.java
Normal file
74
src/main/java/org/kohsuke/github/GHContentSearchBuilder.java
Normal file
@@ -0,0 +1,74 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
/**
|
||||
* Search code for {@link GHContent}.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GitHub#searchContent()
|
||||
*/
|
||||
public class GHContentSearchBuilder extends GHSearchBuilder<GHContent> {
|
||||
/*package*/ GHContentSearchBuilder(GitHub root) {
|
||||
super(root,ContentSearchResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search terms.
|
||||
*/
|
||||
public GHContentSearchBuilder q(String term) {
|
||||
super.q(term);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHContentSearchBuilder in(String v) {
|
||||
return q("in:"+v);
|
||||
}
|
||||
|
||||
public GHContentSearchBuilder language(String v) {
|
||||
return q("language:"+v);
|
||||
}
|
||||
|
||||
public GHContentSearchBuilder fork(String v) {
|
||||
return q("fork:"+v);
|
||||
}
|
||||
|
||||
public GHContentSearchBuilder size(String v) {
|
||||
return q("size:"+v);
|
||||
}
|
||||
|
||||
public GHContentSearchBuilder path(String v) {
|
||||
return q("path:"+v);
|
||||
}
|
||||
|
||||
public GHContentSearchBuilder filename(String v) {
|
||||
return q("filename:"+v);
|
||||
}
|
||||
|
||||
public GHContentSearchBuilder extension(String v) {
|
||||
return q("extension:"+v);
|
||||
}
|
||||
|
||||
public GHContentSearchBuilder user(String v) {
|
||||
return q("user:"+v);
|
||||
}
|
||||
|
||||
|
||||
public GHContentSearchBuilder repo(String v) {
|
||||
return q("repo:"+v);
|
||||
}
|
||||
|
||||
private static class ContentSearchResult extends SearchResult<GHContent> {
|
||||
private GHContent[] items;
|
||||
|
||||
@Override
|
||||
/*package*/ GHContent[] getItems(GitHub root) {
|
||||
for (GHContent item : items)
|
||||
item.wrap(root);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getApiUrl() {
|
||||
return "/search/code";
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ public class GHDeployKey {
|
||||
protected String url, key, title;
|
||||
protected boolean verified;
|
||||
protected int id;
|
||||
private GHRepository owner;
|
||||
private GHRepository owner;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
@@ -31,10 +31,10 @@ public class GHDeployKey {
|
||||
return verified;
|
||||
}
|
||||
|
||||
public GHDeployKey wrap(GHRepository repo) {
|
||||
this.owner = repo;
|
||||
return this;
|
||||
}
|
||||
public GHDeployKey wrap(GHRepository repo) {
|
||||
this.owner = repo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this).append("title",title).append("id",id).append("key",key).toString();
|
||||
|
||||
61
src/main/java/org/kohsuke/github/GHDeployment.java
Normal file
61
src/main/java/org/kohsuke/github/GHDeployment.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
public class GHDeployment extends GHObject {
|
||||
private GHRepository owner;
|
||||
private GitHub root;
|
||||
protected String sha;
|
||||
protected String ref;
|
||||
protected String task;
|
||||
protected Object payload;
|
||||
protected String environment;
|
||||
protected String description;
|
||||
protected String statuses_url;
|
||||
protected String repository_url;
|
||||
protected GHUser creator;
|
||||
|
||||
|
||||
GHDeployment wrap(GHRepository owner) {
|
||||
this.owner = owner;
|
||||
this.root = owner.root;
|
||||
if(creator != null) creator.wrapUp(root);
|
||||
return this;
|
||||
}
|
||||
|
||||
public URL getStatusesUrl() {
|
||||
return GitHub.parseURL(statuses_url);
|
||||
}
|
||||
|
||||
public URL getRepositoryUrl() {
|
||||
return GitHub.parseURL(repository_url);
|
||||
}
|
||||
|
||||
public String getTask() {
|
||||
return task;
|
||||
}
|
||||
public String getPayload() {
|
||||
return (String) payload;
|
||||
}
|
||||
public String getEnvironment() {
|
||||
return environment;
|
||||
}
|
||||
public GHUser getCreator() {
|
||||
return creator;
|
||||
}
|
||||
public String getRef() {
|
||||
return ref;
|
||||
}
|
||||
public String getSha(){
|
||||
return sha;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This object has no HTML URL.
|
||||
*/
|
||||
@Override
|
||||
public URL getHtmlUrl() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
55
src/main/java/org/kohsuke/github/GHDeploymentBuilder.java
Normal file
55
src/main/java/org/kohsuke/github/GHDeploymentBuilder.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
//Based on https://developer.github.com/v3/repos/deployments/#create-a-deployment
|
||||
public class GHDeploymentBuilder {
|
||||
private final GHRepository repo;
|
||||
private final Requester builder;
|
||||
|
||||
public GHDeploymentBuilder(GHRepository repo) {
|
||||
this.repo = repo;
|
||||
this.builder = new Requester(repo.root);
|
||||
}
|
||||
|
||||
public GHDeploymentBuilder(GHRepository repo, String ref) {
|
||||
this(repo);
|
||||
ref(ref);
|
||||
}
|
||||
|
||||
public GHDeploymentBuilder ref(String branch) {
|
||||
builder.with("ref",branch);
|
||||
return this;
|
||||
}
|
||||
public GHDeploymentBuilder task(String task) {
|
||||
builder.with("task",task);
|
||||
return this;
|
||||
}
|
||||
public GHDeploymentBuilder autoMerge(boolean autoMerge) {
|
||||
builder.with("auto_merge",autoMerge);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHDeploymentBuilder requiredContexts(List<String> requiredContexts) {
|
||||
builder.with("required_contexts",requiredContexts);
|
||||
return this;
|
||||
}
|
||||
public GHDeploymentBuilder payload(String payload) {
|
||||
builder.with("payload",payload);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHDeploymentBuilder environment(String environment) {
|
||||
builder.with("environment",environment);
|
||||
return this;
|
||||
}
|
||||
public GHDeploymentBuilder description(String description) {
|
||||
builder.with("description",description);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHDeployment create() throws IOException {
|
||||
return builder.to(repo.getApiTailUrl("deployments"),GHDeployment.class).wrap(repo);
|
||||
}
|
||||
}
|
||||
8
src/main/java/org/kohsuke/github/GHDeploymentState.java
Normal file
8
src/main/java/org/kohsuke/github/GHDeploymentState.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
/**
|
||||
* Represents the state of deployment
|
||||
*/
|
||||
public enum GHDeploymentState {
|
||||
PENDING, SUCCESS, ERROR, FAILURE
|
||||
}
|
||||
42
src/main/java/org/kohsuke/github/GHDeploymentStatus.java
Normal file
42
src/main/java/org/kohsuke/github/GHDeploymentStatus.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
public class GHDeploymentStatus extends GHObject {
|
||||
private GHRepository owner;
|
||||
private GitHub root;
|
||||
protected GHUser creator;
|
||||
protected String state;
|
||||
protected String description;
|
||||
protected String target_url;
|
||||
protected String deployment_url;
|
||||
protected String repository_url;
|
||||
public GHDeploymentStatus wrap(GHRepository owner) {
|
||||
this.owner = owner;
|
||||
this.root = owner.root;
|
||||
if(creator != null) creator.wrapUp(root);
|
||||
return this;
|
||||
}
|
||||
public URL getTargetUrl() {
|
||||
return GitHub.parseURL(target_url);
|
||||
}
|
||||
|
||||
public URL getDeploymentUrl() {
|
||||
return GitHub.parseURL(deployment_url);
|
||||
}
|
||||
|
||||
public URL getRepositoryUrl() {
|
||||
return GitHub.parseURL(repository_url);
|
||||
}
|
||||
public GHDeploymentState getState() {
|
||||
return GHDeploymentState.valueOf(state.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This object has no HTML URL.
|
||||
*/
|
||||
@Override
|
||||
public URL getHtmlUrl() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class GHDeploymentStatusBuilder {
|
||||
private final Requester builder;
|
||||
private GHRepository repo;
|
||||
private int deploymentId;
|
||||
|
||||
public GHDeploymentStatusBuilder(GHRepository repo, int deploymentId, GHDeploymentState state) {
|
||||
this.repo = repo;
|
||||
this.deploymentId = deploymentId;
|
||||
this.builder = new Requester(repo.root);
|
||||
this.builder.with("state",state.toString().toLowerCase());
|
||||
}
|
||||
|
||||
public GHDeploymentStatusBuilder description(String description) {
|
||||
this.builder.with("description",description);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHDeploymentStatusBuilder targetUrl(String targetUrl) {
|
||||
this.builder.with("target_url",targetUrl);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHDeploymentStatus create() throws IOException {
|
||||
return builder.to(repo.getApiTailUrl("deployments")+"/"+deploymentId+"/statuses",GHDeploymentStatus.class).wrap(repo);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,8 @@ public enum GHEvent {
|
||||
COMMIT_COMMENT,
|
||||
CREATE,
|
||||
DELETE,
|
||||
DEPLOYMENT,
|
||||
DEPLOYMENT_STATUS,
|
||||
DOWNLOAD,
|
||||
FOLLOW,
|
||||
FORK,
|
||||
@@ -25,6 +27,8 @@ public enum GHEvent {
|
||||
PULL_REQUEST,
|
||||
PULL_REQUEST_REVIEW_COMMENT,
|
||||
PUSH,
|
||||
RELEASE,
|
||||
STATUS,
|
||||
TEAM_ADD,
|
||||
WATCH
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ public abstract class GHEventPayload {
|
||||
private String ref;
|
||||
private int size;
|
||||
private List<PushCommit> commits;
|
||||
private GHRepository repository;
|
||||
|
||||
/**
|
||||
* The SHA of the HEAD commit on the repository
|
||||
@@ -158,6 +159,17 @@ public abstract class GHEventPayload {
|
||||
return commits;
|
||||
}
|
||||
|
||||
public GHRepository getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
void wrapUp(GitHub root) {
|
||||
super.wrapUp(root);
|
||||
if (repository!=null)
|
||||
repository.wrap(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit in a push
|
||||
*/
|
||||
|
||||
@@ -3,8 +3,8 @@ package org.kohsuke.github;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -16,17 +16,18 @@ import java.util.Map.Entry;
|
||||
* @see GHUser#listGists()
|
||||
* @see GitHub#getGist(String)
|
||||
* @see GitHub#createGist()
|
||||
* @see <a href="https://developer.github.com/v3/gists/">documentation</a>
|
||||
*/
|
||||
public class GHGist {
|
||||
public class GHGist extends GHObject {
|
||||
/*package almost final*/ GHUser owner;
|
||||
/*package almost final*/ GitHub root;
|
||||
|
||||
private String url, forks_url, commits_url, id, git_pull_url, git_push_url, html_url;
|
||||
private String forks_url, commits_url, id, git_pull_url, git_push_url, html_url;
|
||||
|
||||
@JsonProperty("public")
|
||||
private boolean _public;
|
||||
|
||||
private String created_at, updated_at, description;
|
||||
private String description;
|
||||
|
||||
private int comments;
|
||||
|
||||
@@ -41,13 +42,6 @@ public class GHGist {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* API URL of this gist, such as 'https://api.github.com/gists/12345'
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getForksUrl() {
|
||||
return forks_url;
|
||||
}
|
||||
@@ -56,13 +50,6 @@ public class GHGist {
|
||||
return commits_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of this gist, such as '12345'
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL like https://gist.github.com/gists/12345.git
|
||||
*/
|
||||
@@ -74,22 +61,14 @@ public class GHGist {
|
||||
return git_push_url;
|
||||
}
|
||||
|
||||
public String getHtmlUrl() {
|
||||
return html_url;
|
||||
public URL getHtmlUrl() {
|
||||
return GitHub.parseURL(html_url);
|
||||
}
|
||||
|
||||
public boolean isPublic() {
|
||||
return _public;
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return GitHub.parseDate(created_at);
|
||||
}
|
||||
|
||||
public Date getUpdatedAt() {
|
||||
return GitHub.parseDate(updated_at);
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
@@ -10,18 +11,17 @@ import java.util.Map;
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class GHHook {
|
||||
public class GHHook extends GHObject {
|
||||
/**
|
||||
* Repository that the hook belongs to.
|
||||
*/
|
||||
/*package*/ transient GHRepository repository;
|
||||
|
||||
String created_at, updated_at, name;
|
||||
String name;
|
||||
List<String> events;
|
||||
boolean active;
|
||||
Map<String,String> config;
|
||||
int id;
|
||||
|
||||
|
||||
/*package*/ GHHook wrap(GHRepository owner) {
|
||||
this.repository = owner;
|
||||
return this;
|
||||
@@ -46,14 +46,18 @@ public class GHHook {
|
||||
return Collections.unmodifiableMap(config);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes this hook.
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
new Requester(repository.root).method("DELETE").to(String.format("/repos/%s/%s/hooks/%d", repository.getOwnerName(), repository.getName(), id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This object has no HTML URL.
|
||||
*/
|
||||
@Override
|
||||
public URL getHtmlUrl() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,52 +37,46 @@ import java.util.Locale;
|
||||
*
|
||||
* @author Eric Maupin
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GHRepository#getIssue(int)
|
||||
* @see GitHub#searchIssues()
|
||||
* @see GHIssueSearchBuilder
|
||||
*/
|
||||
public class GHIssue {
|
||||
public class GHIssue extends GHObject {
|
||||
GitHub root;
|
||||
GHRepository owner;
|
||||
|
||||
// API v3
|
||||
|
||||
// API v3
|
||||
protected GHUser assignee;
|
||||
protected String state;
|
||||
protected int number;
|
||||
protected String closed_at;
|
||||
protected int comments;
|
||||
protected String body;
|
||||
// for backward compatibility with < 1.63, this collection needs to hold instances of Label, not GHLabel
|
||||
protected List<Label> labels;
|
||||
protected GHUser user;
|
||||
protected String title, created_at, html_url;
|
||||
protected String title, html_url;
|
||||
protected GHIssue.PullRequest pull_request;
|
||||
protected GHMilestone milestone;
|
||||
protected String url, updated_at;
|
||||
protected int id;
|
||||
protected GHUser closed_by;
|
||||
|
||||
public static class Label {
|
||||
private String url;
|
||||
private String name;
|
||||
private String color;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
/**
|
||||
* @deprecated use {@link GHLabel}
|
||||
*/
|
||||
public static class Label extends GHLabel {
|
||||
}
|
||||
|
||||
/*package*/ GHIssue wrap(GHRepository owner) {
|
||||
this.owner = owner;
|
||||
this.root = owner.root;
|
||||
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);
|
||||
if(milestone != null) milestone.wrap(owner);
|
||||
return wrap(owner.root);
|
||||
}
|
||||
|
||||
/*package*/ GHIssue wrap(GitHub root) {
|
||||
this.root = root;
|
||||
if(assignee != null) assignee.wrapUp(root);
|
||||
if(user != null) user.wrapUp(root);
|
||||
if(closed_by != null) closed_by.wrapUp(root);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -117,7 +111,7 @@ public class GHIssue {
|
||||
* The HTML page of this issue,
|
||||
* like https://github.com/jenkinsci/jenkins/issues/100
|
||||
*/
|
||||
public URL getUrl() {
|
||||
public URL getHtmlUrl() {
|
||||
return GitHub.parseURL(html_url);
|
||||
}
|
||||
|
||||
@@ -129,28 +123,20 @@ public class GHIssue {
|
||||
return Enum.valueOf(GHIssueState.class, state.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
public Collection<Label> getLabels() {
|
||||
public Collection<GHLabel> getLabels() throws IOException {
|
||||
if(labels == null){
|
||||
return Collections.EMPTY_LIST;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.unmodifiableList(labels);
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return GitHub.parseDate(created_at);
|
||||
}
|
||||
|
||||
public Date getUpdatedAt() {
|
||||
return GitHub.parseDate(updated_at);
|
||||
return Collections.<GHLabel>unmodifiableList(labels);
|
||||
}
|
||||
|
||||
public Date getClosedAt() {
|
||||
return GitHub.parseDate(closed_at);
|
||||
}
|
||||
|
||||
public URL getApiURL(){
|
||||
public URL getApiURL(){
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the issue by adding a comment.
|
||||
@@ -163,6 +149,10 @@ public class GHIssue {
|
||||
new Requester(root)._with(key, value).method("PATCH").to(getApiRoute());
|
||||
}
|
||||
|
||||
private void editIssue(String key, Object value) throws IOException {
|
||||
new Requester(root)._with(key, value).method("PATCH").to(getIssuesApiRoute());
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this issue.
|
||||
*/
|
||||
@@ -186,25 +176,25 @@ public class GHIssue {
|
||||
}
|
||||
|
||||
public void assignTo(GHUser user) throws IOException {
|
||||
edit("assignee",user.getLogin());
|
||||
editIssue("assignee",user.getLogin());
|
||||
}
|
||||
|
||||
public void setLabels(String... labels) throws IOException {
|
||||
edit("labels",labels);
|
||||
editIssue("labels",labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains all the comments associated with this issue.
|
||||
*
|
||||
* @see #listComments()
|
||||
*
|
||||
* @see #listComments()
|
||||
*/
|
||||
public List<GHIssueComment> getComments() throws IOException {
|
||||
return listComments().asList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains all the comments associated with this issue.
|
||||
*/
|
||||
public List<GHIssueComment> getComments() throws IOException {
|
||||
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() {
|
||||
@@ -222,54 +212,69 @@ public class GHIssue {
|
||||
return getIssuesApiRoute();
|
||||
}
|
||||
|
||||
private String getIssuesApiRoute() {
|
||||
protected String getIssuesApiRoute() {
|
||||
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/issues/"+number;
|
||||
}
|
||||
|
||||
public GHUser getAssignee() {
|
||||
return assignee;
|
||||
}
|
||||
|
||||
public GHUser getAssignee() {
|
||||
return assignee;
|
||||
}
|
||||
|
||||
/**
|
||||
* User who submitted the issue.
|
||||
*/
|
||||
public GHUser getUser() {
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* Reports who has closed the issue.
|
||||
*
|
||||
* <p>
|
||||
* Note that GitHub doesn't always seem to report this information
|
||||
* even for an issue that's already closed. See
|
||||
* https://github.com/kohsuke/github-api/issues/60.
|
||||
*/
|
||||
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 GHMilestone getMilestone() {
|
||||
return milestone;
|
||||
}
|
||||
/**
|
||||
* Returns non-null if this issue is a shadow of a pull request.
|
||||
*/
|
||||
public PullRequest getPullRequest() {
|
||||
return pull_request;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
public boolean isPullRequest() {
|
||||
return pull_request!=null;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,10 @@ import java.util.Date;
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class GHIssueComment {
|
||||
public class GHIssueComment extends GHObject {
|
||||
GHIssue owner;
|
||||
|
||||
private String body, gravatar_id, created_at, updated_at;
|
||||
private URL url;
|
||||
private int id;
|
||||
private String body, gravatar_id;
|
||||
private GHUser user;
|
||||
|
||||
/*package*/ GHIssueComment wrapUp(GHIssue owner) {
|
||||
@@ -59,22 +57,6 @@ public class GHIssueComment {
|
||||
return body;
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return GitHub.parseDate(created_at);
|
||||
}
|
||||
|
||||
public Date getUpdatedAt() {
|
||||
return GitHub.parseDate(updated_at);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public URL getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of the user who posted this comment.
|
||||
*/
|
||||
@@ -89,4 +71,12 @@ public class GHIssueComment {
|
||||
public GHUser getUser() throws IOException {
|
||||
return owner.root.getUser(user.getLogin());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This object has no HTML URL.
|
||||
*/
|
||||
@Override
|
||||
public URL getHtmlUrl() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
66
src/main/java/org/kohsuke/github/GHIssueSearchBuilder.java
Normal file
66
src/main/java/org/kohsuke/github/GHIssueSearchBuilder.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Search issues.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GitHub#searchIssues()
|
||||
*/
|
||||
public class GHIssueSearchBuilder extends GHSearchBuilder<GHIssue> {
|
||||
/*package*/ GHIssueSearchBuilder(GitHub root) {
|
||||
super(root,IssueSearchResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search terms.
|
||||
*/
|
||||
public GHIssueSearchBuilder q(String term) {
|
||||
super.q(term);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHIssueSearchBuilder mentions(GHUser u) {
|
||||
return mentions(u.getLogin());
|
||||
}
|
||||
|
||||
public GHIssueSearchBuilder mentions(String login) {
|
||||
return q("mentions:"+login);
|
||||
}
|
||||
|
||||
public GHIssueSearchBuilder isOpen() {
|
||||
return q("is:open");
|
||||
}
|
||||
|
||||
public GHIssueSearchBuilder isClosed() {
|
||||
return q("is:closed");
|
||||
}
|
||||
|
||||
public GHIssueSearchBuilder isMerged() {
|
||||
return q("is:merged");
|
||||
}
|
||||
|
||||
public GHIssueSearchBuilder sort(Sort sort) {
|
||||
req.with("sort",sort.toString().toLowerCase(Locale.ENGLISH));
|
||||
return this;
|
||||
}
|
||||
|
||||
public enum Sort { COMMENTS, CREATED, UPDATED }
|
||||
|
||||
private static class IssueSearchResult extends SearchResult<GHIssue> {
|
||||
private GHIssue[] items;
|
||||
|
||||
@Override
|
||||
/*package*/ GHIssue[] getItems(GitHub root) {
|
||||
for (GHIssue i : items)
|
||||
i.wrap(root);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getApiUrl() {
|
||||
return "/search/issues";
|
||||
}
|
||||
}
|
||||
37
src/main/java/org/kohsuke/github/GHLabel.java
Normal file
37
src/main/java/org/kohsuke/github/GHLabel.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GHIssue#getLabels()
|
||||
* @see GHRepository#listLabels()
|
||||
*/
|
||||
public class GHLabel {
|
||||
private String url, name, color;
|
||||
private GHRepository repo;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Color code without leading '#', such as 'f29513'
|
||||
*/
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
/*package*/ GHLabel wrapUp(GHRepository repo) {
|
||||
this.repo = repo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void delete() throws IOException {
|
||||
repo.root.retrieve().method("DELETE").to(url);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -9,62 +10,58 @@ import java.util.Locale;
|
||||
* @author Yusuke Kokubo
|
||||
*
|
||||
*/
|
||||
public class GHMilestone {
|
||||
public class GHMilestone extends GHObject {
|
||||
GitHub root;
|
||||
GHRepository owner;
|
||||
GHRepository owner;
|
||||
|
||||
GHUser creator;
|
||||
private String state, due_on, title, url, created_at, description;
|
||||
private int closed_issues, open_issues, number;
|
||||
GHUser creator;
|
||||
private String state, due_on, title, description, html_url;
|
||||
private int closed_issues, open_issues, number;
|
||||
|
||||
public GitHub getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public GHRepository getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public GHUser getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
public Date getDueOn() {
|
||||
if (due_on == null) return null;
|
||||
return GitHub.parseDate(due_on);
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return GitHub.parseDate(created_at);
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public int getClosedIssues() {
|
||||
return closed_issues;
|
||||
}
|
||||
|
||||
public int getOpenIssues() {
|
||||
return open_issues;
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public GHMilestoneState getState() {
|
||||
return Enum.valueOf(GHMilestoneState.class, state.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
public GitHub getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public GHRepository getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public GHUser getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
public Date getDueOn() {
|
||||
if (due_on == null) return null;
|
||||
return GitHub.parseDate(due_on);
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public int getClosedIssues() {
|
||||
return closed_issues;
|
||||
}
|
||||
|
||||
public int getOpenIssues() {
|
||||
return open_issues;
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public URL getHtmlUrl() {
|
||||
return GitHub.parseURL(html_url);
|
||||
}
|
||||
|
||||
public GHMilestoneState getState() {
|
||||
return Enum.valueOf(GHMilestoneState.class, state.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this issue.
|
||||
@@ -81,9 +78,9 @@ public class GHMilestone {
|
||||
return "/repos/"+owner.getOwnerName()+"/"+owner.getName()+"/milestones/"+number;
|
||||
}
|
||||
|
||||
public GHMilestone wrap(GHRepository repo) {
|
||||
this.owner = repo;
|
||||
this.root = repo.root;
|
||||
return this;
|
||||
}
|
||||
public GHMilestone wrap(GHRepository repo) {
|
||||
this.owner = repo;
|
||||
this.root = repo.root;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,12 +101,24 @@ public class GHMyself extends GHUser {
|
||||
* Lists up all repositories this user owns (public and private).
|
||||
*
|
||||
* Unlike {@link #getAllRepositories()}, this does not wait until all the repositories are returned.
|
||||
* Repositories are returned by GitHub API with a 30 items per page.
|
||||
*/
|
||||
@Override
|
||||
public PagedIterable<GHRepository> listRepositories() {
|
||||
return listRepositories(30);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists up all the repositories this user owns (public and private) using the specified page size.
|
||||
*
|
||||
* @param pageSize size for each page of items returned by GitHub. Maximum page size is 100.
|
||||
*
|
||||
* Unlike {@link #getRepositories()}, this does not wait until all the repositories are returned.
|
||||
*/
|
||||
public PagedIterable<GHRepository> listRepositories(final int pageSize) {
|
||||
return new PagedIterable<GHRepository>() {
|
||||
public PagedIterator<GHRepository> iterator() {
|
||||
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/user/repos", GHRepository[].class)) {
|
||||
return new PagedIterator<GHRepository>(root.retrieve().asIterator("/user/repos?per_page=" + pageSize, GHRepository[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(GHRepository[] page) {
|
||||
for (GHRepository c : page)
|
||||
|
||||
207
src/main/java/org/kohsuke/github/GHNotificationStream.java
Normal file
207
src/main/java/org/kohsuke/github/GHNotificationStream.java
Normal file
@@ -0,0 +1,207 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Listens to GitHub notification stream.
|
||||
*
|
||||
* <p>
|
||||
* This class supports two modes of retrieving notifications that can
|
||||
* be controlled via {@link #nonBlocking(boolean)}.
|
||||
*
|
||||
* <p>
|
||||
* In the blocking mode, which is the default, iterator will be infinite.
|
||||
* The call to {@link Iterator#next()} will block until a new notification
|
||||
* arrives. This is useful for application that runs perpetually and reacts
|
||||
* to notifications.
|
||||
*
|
||||
* <p>
|
||||
* In the non-blocking mode, the iterator will only report the set of
|
||||
* notifications initially retrieved from GitHub, then quit. This is useful
|
||||
* for a batch application to process the current set of notifications.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GitHub#listNotifications()
|
||||
* @see GHRepository#listNotifications()
|
||||
*/
|
||||
public class GHNotificationStream implements Iterable<GHThread> {
|
||||
private final GitHub root;
|
||||
|
||||
private Boolean all, participating;
|
||||
private String since;
|
||||
private String apiUrl;
|
||||
private boolean nonBlocking = false;
|
||||
|
||||
/*package*/ GHNotificationStream(GitHub root, String apiUrl) {
|
||||
this.root = root;
|
||||
this.apiUrl = apiUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the stream include notifications that are already read?
|
||||
*/
|
||||
public GHNotificationStream read(boolean v) {
|
||||
all = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the stream be restricted to notifications in which the user
|
||||
* is directly participating or mentioned?
|
||||
*/
|
||||
public GHNotificationStream participating(boolean v) {
|
||||
participating = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHNotificationStream since(long timestamp) {
|
||||
return since(new Date(timestamp));
|
||||
}
|
||||
|
||||
public GHNotificationStream since(Date dt) {
|
||||
since = GitHub.printDate(dt);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to true, {@link #iterator()} will stop iterating instead of blocking and
|
||||
* waiting for the updates to arrive.
|
||||
*/
|
||||
public GHNotificationStream nonBlocking(boolean v) {
|
||||
this.nonBlocking = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an infinite blocking {@link Iterator} that returns
|
||||
* {@link GHThread} as notifications arrive.
|
||||
*/
|
||||
public Iterator<GHThread> iterator() {
|
||||
// capture the configuration setting here
|
||||
final Requester req = new Requester(root).method("GET")
|
||||
.with("all", all).with("participating", participating).with("since", since);
|
||||
|
||||
return new Iterator<GHThread>() {
|
||||
/**
|
||||
* Stuff we've fetched but haven't returned to the caller.
|
||||
* Newer ones first.
|
||||
*/
|
||||
private GHThread[] threads = EMPTY_ARRAY;
|
||||
|
||||
/**
|
||||
* Next element in {@link #threads} to return. This counts down.
|
||||
*/
|
||||
private int idx=-1;
|
||||
|
||||
/**
|
||||
* threads whose updated_at is older than this should be ignored.
|
||||
*/
|
||||
private long lastUpdated = -1;
|
||||
|
||||
/**
|
||||
* Next request should have "If-Modified-Since" header with this value.
|
||||
*/
|
||||
private String lastModified;
|
||||
|
||||
/**
|
||||
* When is the next polling allowed?
|
||||
*/
|
||||
private long nextCheckTime = -1;
|
||||
|
||||
private GHThread next;
|
||||
|
||||
public GHThread next() {
|
||||
if (next==null) {
|
||||
next = fetch();
|
||||
if (next==null)
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
GHThread r = next;
|
||||
next = null;
|
||||
return r;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
if (next==null)
|
||||
next = fetch();
|
||||
return next!=null;
|
||||
}
|
||||
|
||||
GHThread fetch() {
|
||||
try {
|
||||
while (true) {// loop until we get new threads to return
|
||||
|
||||
// if we have fetched un-returned threads, use them first
|
||||
while (idx>=0) {
|
||||
GHThread n = threads[idx--];
|
||||
long nt = n.getUpdatedAt().getTime();
|
||||
if (nt >= lastUpdated) {
|
||||
lastUpdated = nt;
|
||||
return n.wrap(root);
|
||||
}
|
||||
}
|
||||
|
||||
if (nonBlocking && nextCheckTime>=0)
|
||||
return null; // nothing more to report, and we aren't blocking
|
||||
|
||||
// observe the polling interval before making the call
|
||||
while (true) {
|
||||
long now = System.currentTimeMillis();
|
||||
if (nextCheckTime < now) break;
|
||||
long waitTime = Math.max(Math.min(nextCheckTime - now, 1000), 60 * 1000);
|
||||
Thread.sleep(waitTime);
|
||||
}
|
||||
|
||||
req.setHeader("If-Modified-Since", lastModified);
|
||||
|
||||
threads = req.to(apiUrl, GHThread[].class);
|
||||
if (threads==null) {
|
||||
threads = EMPTY_ARRAY; // if unmodified, we get empty array
|
||||
} else {
|
||||
// we get a new batch, but we want to ignore the ones that we've seen
|
||||
lastUpdated++;
|
||||
}
|
||||
idx = threads.length-1;
|
||||
|
||||
nextCheckTime = calcNextCheckTime();
|
||||
lastModified = req.getResponseHeader("Last-Modified");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private long calcNextCheckTime() {
|
||||
String v = req.getResponseHeader("X-Poll-Interval");
|
||||
if (v==null) v="60";
|
||||
return System.currentTimeMillis()+Integer.parseInt(v)*1000;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void markAsRead() throws IOException {
|
||||
markAsRead(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks all the notifications as read.
|
||||
*/
|
||||
public void markAsRead(long timestamp) throws IOException {
|
||||
final Requester req = new Requester(root).method("PUT");
|
||||
if (timestamp>=0)
|
||||
req.with("last_read_at", GitHub.printDate(new Date(timestamp)));
|
||||
req.asHttpStatusCode(apiUrl);
|
||||
}
|
||||
|
||||
private static final GHThread[] EMPTY_ARRAY = new GHThread[0];
|
||||
}
|
||||
69
src/main/java/org/kohsuke/github/GHObject.java
Normal file
69
src/main/java/org/kohsuke/github/GHObject.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Most (all?) domain objects in GitHub seems to have these 4 properties.
|
||||
*/
|
||||
public abstract class GHObject {
|
||||
protected String url;
|
||||
protected int id;
|
||||
protected String created_at;
|
||||
protected String updated_at;
|
||||
|
||||
/*package*/ GHObject() {
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this resource created?
|
||||
*/
|
||||
@WithBridgeMethods(value=String.class, adapterMethod="createdAtStr")
|
||||
public Date getCreatedAt() throws IOException {
|
||||
return GitHub.parseDate(created_at);
|
||||
}
|
||||
|
||||
private Object createdAtStr(Date id, Class type) {
|
||||
return created_at;
|
||||
}
|
||||
|
||||
/**
|
||||
* API URL of this object.
|
||||
*/
|
||||
@WithBridgeMethods(value=String.class, adapterMethod="urlToString")
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL of this object for humans, which renders some HTML.
|
||||
*/
|
||||
@WithBridgeMethods(value=String.class, adapterMethod="urlToString")
|
||||
public abstract URL getHtmlUrl();
|
||||
|
||||
/**
|
||||
* When was this resource last updated?
|
||||
*/
|
||||
public Date getUpdatedAt() throws IOException {
|
||||
return GitHub.parseDate(updated_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique ID number of this resource.
|
||||
*/
|
||||
@WithBridgeMethods(value=String.class, adapterMethod="intToString")
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private Object intToString(int id, Class type) {
|
||||
return String.valueOf(id);
|
||||
}
|
||||
|
||||
private Object urlToString(URL url, Class type) {
|
||||
return url==null ? null : url.toString();
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,10 @@ package org.kohsuke.github;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -14,15 +16,14 @@ import java.util.TreeMap;
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public abstract class GHPerson {
|
||||
public abstract class GHPerson extends GHObject {
|
||||
/*package almost final*/ GitHub root;
|
||||
|
||||
// core data fields that exist even for "small" user data (such as the user info in pull request)
|
||||
protected String login, avatar_url, url, gravatar_id;
|
||||
protected int id;
|
||||
protected String login, avatar_url, gravatar_id;
|
||||
|
||||
// other fields (that only show up in full data)
|
||||
protected String location,blog,email,name,created_at,company;
|
||||
protected String location,blog,email,name,company;
|
||||
protected String html_url;
|
||||
protected int followers,following,public_repos,public_gists;
|
||||
|
||||
@@ -36,7 +37,7 @@ public abstract class GHPerson {
|
||||
*
|
||||
* Depending on the original API call where this object is created, it may not contain everything.
|
||||
*/
|
||||
protected void populate() throws IOException {
|
||||
protected synchronized void populate() throws IOException {
|
||||
if (created_at!=null) return; // already populated
|
||||
|
||||
root.retrieve().to(url, this);
|
||||
@@ -196,9 +197,14 @@ public abstract class GHPerson {
|
||||
return location;
|
||||
}
|
||||
|
||||
public String getCreatedAt() throws IOException {
|
||||
public Date getCreatedAt() throws IOException {
|
||||
populate();
|
||||
return created_at;
|
||||
return super.getCreatedAt();
|
||||
}
|
||||
|
||||
public Date getUpdatedAt() throws IOException {
|
||||
populate();
|
||||
return super.getCreatedAt();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,8 +215,9 @@ public abstract class GHPerson {
|
||||
return blog;
|
||||
}
|
||||
|
||||
public String getHtmlUrl() {
|
||||
return html_url;
|
||||
@Override
|
||||
public URL getHtmlUrl() {
|
||||
return GitHub.parseURL(html_url);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,13 +243,6 @@ public abstract class GHPerson {
|
||||
return following;
|
||||
}
|
||||
|
||||
/**
|
||||
* What appears to be a GitHub internal unique number that identifies this user.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getFollowersCount() throws IOException {
|
||||
populate();
|
||||
return followers;
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A pull request.
|
||||
@@ -37,31 +36,38 @@ import java.util.Locale;
|
||||
*/
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public class GHPullRequest extends GHIssue {
|
||||
|
||||
private String patch_url, diff_url, issue_url;
|
||||
private GHCommitPointer base;
|
||||
private String merged_at;
|
||||
private GHCommitPointer head;
|
||||
|
||||
private String patch_url, diff_url, issue_url;
|
||||
private GHCommitPointer base;
|
||||
private String merged_at;
|
||||
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;
|
||||
private int review_comments, additions;
|
||||
private boolean merged;
|
||||
private Boolean mergeable;
|
||||
private int deletions;
|
||||
private String mergeable_state;
|
||||
private int changed_files;
|
||||
|
||||
/**
|
||||
* GitHub doesn't return some properties of {@link GHIssue} when requesting the GET on the 'pulls' API
|
||||
* route as opposed to 'issues' API route. This flag remembers whether we made the GET call on the 'issues' route
|
||||
* on this object to fill in those missing details
|
||||
*/
|
||||
private transient boolean fetchedIssueDetails;
|
||||
|
||||
|
||||
GHPullRequest wrapUp(GHRepository owner) {
|
||||
this.wrap(owner);
|
||||
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 (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;
|
||||
}
|
||||
@@ -78,8 +84,8 @@ public class GHPullRequest extends GHIssue {
|
||||
public URL getPatchUrl() {
|
||||
return GitHub.parseURL(patch_url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* The URL of the patch file.
|
||||
* like https://github.com/jenkinsci/jenkins/pull/100.patch
|
||||
*/
|
||||
@@ -101,9 +107,9 @@ public class GHPullRequest extends GHIssue {
|
||||
public GHCommitPointer getHead() {
|
||||
return head;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Date getIssueUpdatedAt() {
|
||||
|
||||
@Deprecated
|
||||
public Date getIssueUpdatedAt() throws IOException {
|
||||
return super.getUpdatedAt();
|
||||
}
|
||||
|
||||
@@ -119,64 +125,65 @@ public class GHPullRequest extends GHIssue {
|
||||
return GitHub.parseDate(merged_at);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Label> getLabels() {
|
||||
return super.getLabels();
|
||||
}
|
||||
@Override
|
||||
public Collection<GHLabel> getLabels() throws IOException {
|
||||
fetchIssue();
|
||||
return super.getLabels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GHUser getClosedBy() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public GHUser getClosedBy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PullRequest getPullRequest() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public PullRequest getPullRequest() {
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// details that are only available via get with ID
|
||||
//
|
||||
//
|
||||
public GHUser getMergedBy() throws IOException {
|
||||
populate();
|
||||
return merged_by;
|
||||
}
|
||||
return merged_by;
|
||||
}
|
||||
|
||||
public int getReviewComments() throws IOException {
|
||||
public int getReviewComments() throws IOException {
|
||||
populate();
|
||||
return review_comments;
|
||||
}
|
||||
return review_comments;
|
||||
}
|
||||
|
||||
public int getAdditions() throws IOException {
|
||||
public int getAdditions() throws IOException {
|
||||
populate();
|
||||
return additions;
|
||||
}
|
||||
return additions;
|
||||
}
|
||||
|
||||
public boolean isMerged() throws IOException {
|
||||
populate();
|
||||
return merged;
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
public Boolean getMergeable() throws IOException {
|
||||
public Boolean getMergeable() throws IOException {
|
||||
populate();
|
||||
return mergeable;
|
||||
}
|
||||
return mergeable;
|
||||
}
|
||||
|
||||
public int getDeletions() throws IOException {
|
||||
public int getDeletions() throws IOException {
|
||||
populate();
|
||||
return deletions;
|
||||
}
|
||||
return deletions;
|
||||
}
|
||||
|
||||
public String getMergeableState() throws IOException {
|
||||
public String getMergeableState() throws IOException {
|
||||
populate();
|
||||
return mergeable_state;
|
||||
}
|
||||
return mergeable_state;
|
||||
}
|
||||
|
||||
public int getChangedFiles() throws IOException {
|
||||
public int getChangedFiles() throws IOException {
|
||||
populate();
|
||||
return changed_files;
|
||||
}
|
||||
return changed_files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully populate the data by retrieving missing data.
|
||||
@@ -186,7 +193,40 @@ public class GHPullRequest extends GHIssue {
|
||||
private void populate() throws IOException {
|
||||
if (merged_by!=null) return; // already populated
|
||||
|
||||
root.retrieve().to(url, this);
|
||||
root.retrieve().to(url, this).wrapUp(owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all the commits associated to this pull request.
|
||||
*/
|
||||
public PagedIterable<GHPullRequestFileDetail> listFiles() {
|
||||
return new PagedIterable<GHPullRequestFileDetail>() {
|
||||
public PagedIterator<GHPullRequestFileDetail> iterator() {
|
||||
return new PagedIterator<GHPullRequestFileDetail>(root.retrieve().asIterator(String.format("%s/files", getApiURL()),
|
||||
GHPullRequestFileDetail[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(GHPullRequestFileDetail[] page) {
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains all the review comments associated with this pull request.
|
||||
*/
|
||||
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
|
||||
return new PagedIterable<GHPullRequestReviewComment>() {
|
||||
public PagedIterator<GHPullRequestReviewComment> iterator() {
|
||||
return new PagedIterator<GHPullRequestReviewComment>(root.retrieve().asIterator(getApiRoute() + "/comments",
|
||||
GHPullRequestReviewComment[].class)) {
|
||||
protected void wrapUp(GHPullRequestReviewComment[] page) {
|
||||
for (GHPullRequestReviewComment c : page)
|
||||
c.wrapUp(GHPullRequest.this);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,16 +236,27 @@ public class GHPullRequest extends GHIssue {
|
||||
return new PagedIterable<GHPullRequestCommitDetail>() {
|
||||
public PagedIterator<GHPullRequestCommitDetail> iterator() {
|
||||
return new PagedIterator<GHPullRequestCommitDetail>(root.retrieve().asIterator(
|
||||
String.format("%s/commits", getApiURL().getPath()),
|
||||
String.format("%s/commits", getApiURL()),
|
||||
GHPullRequestCommitDetail[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(GHPullRequestCommitDetail[] page) {
|
||||
for (GHPullRequestCommitDetail c : page)
|
||||
c.wrapUp(GHPullRequest.this);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position) throws IOException {
|
||||
return new Requester(root).method("POST")
|
||||
.with("body", body)
|
||||
.with("commit_id", sha)
|
||||
.with("path", path)
|
||||
.with("position", position)
|
||||
.to(getApiRoute() + "/comments", GHPullRequestReviewComment.class).wrapUp(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge this pull request.
|
||||
*
|
||||
@@ -215,7 +266,27 @@ public class GHPullRequest extends GHIssue {
|
||||
* Commit message. If null, the default one will be used.
|
||||
*/
|
||||
public void merge(String msg) throws IOException {
|
||||
new Requester(root).method("PUT").with("commit_message",msg).to(getApiRoute()+"/merge");
|
||||
merge(msg,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge this pull request.
|
||||
*
|
||||
* The equivalent of the big green "Merge pull request" button.
|
||||
*
|
||||
* @param msg
|
||||
* Commit message. If null, the default one will be used.
|
||||
* @param sha
|
||||
* SHA that pull request head must match to allow merge.
|
||||
*/
|
||||
public void merge(String msg, String sha) throws IOException {
|
||||
new Requester(root).method("PUT").with("commit_message",msg).with("sha",sha).to(getApiRoute()+"/merge");
|
||||
}
|
||||
|
||||
private void fetchIssue() throws IOException {
|
||||
if (!fetchedIssueDetails) {
|
||||
new Requester(root).to(getIssuesApiRoute(), this);
|
||||
fetchedIssueDetails = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,99 +31,111 @@ import java.net.URL;
|
||||
* Commit detail inside a {@link GHPullRequest}.
|
||||
*
|
||||
* @author Luca Milanesio
|
||||
* @see GHPullRequest#listCommits()
|
||||
*/
|
||||
public class GHPullRequestCommitDetail {
|
||||
private GHPullRequest owner;
|
||||
|
||||
/*package*/ void wrapUp(GHPullRequest owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link GitUser}
|
||||
*/
|
||||
public static class Authorship extends GitUser {}
|
||||
public static class Authorship extends GitUser {
|
||||
}
|
||||
|
||||
public static class Tree {
|
||||
String sha;
|
||||
String url;
|
||||
|
||||
public String getSha() {
|
||||
return sha;
|
||||
}
|
||||
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Commit {
|
||||
Authorship author;
|
||||
Authorship committer;
|
||||
String message;
|
||||
Tree tree;
|
||||
String url;
|
||||
int comment_count;
|
||||
|
||||
@WithBridgeMethods(value = Authorship.class, castRequired = true)
|
||||
public GitUser getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
@WithBridgeMethods(value = Authorship.class, castRequired = true)
|
||||
public GitUser getCommitter() {
|
||||
return committer;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
|
||||
public int getComment_count() {
|
||||
return comment_count;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CommitPointer {
|
||||
String sha;
|
||||
String url;
|
||||
String html_url;
|
||||
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
|
||||
public URL getHtml_url() {
|
||||
return GitHub.parseURL(html_url);
|
||||
}
|
||||
|
||||
public String getSha() {
|
||||
return sha;
|
||||
}
|
||||
}
|
||||
|
||||
String sha;
|
||||
String url;
|
||||
|
||||
public String getSha() {
|
||||
return sha;
|
||||
}
|
||||
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Commit {
|
||||
Authorship author;
|
||||
Authorship committer;
|
||||
String message;
|
||||
Tree tree;
|
||||
String url;
|
||||
int comment_count;
|
||||
|
||||
@WithBridgeMethods(value=Authorship.class,castRequired=true)
|
||||
public GitUser getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
@WithBridgeMethods(value=Authorship.class,castRequired=true)
|
||||
public GitUser getCommitter() {
|
||||
return committer;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
|
||||
public int getComment_count() {
|
||||
return comment_count;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CommitPointer {
|
||||
String sha;
|
||||
Commit commit;
|
||||
String url;
|
||||
String html_url;
|
||||
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
|
||||
public URL getHtml_url() {
|
||||
return GitHub.parseURL(html_url);
|
||||
}
|
||||
String comments_url;
|
||||
CommitPointer[] parents;
|
||||
|
||||
public String getSha() {
|
||||
return sha;
|
||||
return sha;
|
||||
}
|
||||
}
|
||||
|
||||
String sha;
|
||||
Commit commit;
|
||||
String url;
|
||||
String html_url;
|
||||
String comments_url;
|
||||
CommitPointer[] parents;
|
||||
|
||||
public String getSha() {
|
||||
return sha;
|
||||
}
|
||||
public Commit getCommit() {
|
||||
return commit;
|
||||
}
|
||||
public URL getApiUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(html_url);
|
||||
}
|
||||
public URL getCommentsUrl() {
|
||||
return GitHub.parseURL(comments_url);
|
||||
}
|
||||
public CommitPointer[] getParents() {
|
||||
return parents;
|
||||
}
|
||||
public Commit getCommit() {
|
||||
return commit;
|
||||
}
|
||||
|
||||
public URL getApiUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(html_url);
|
||||
}
|
||||
|
||||
public URL getCommentsUrl() {
|
||||
return GitHub.parseURL(comments_url);
|
||||
}
|
||||
|
||||
public CommitPointer[] getParents() {
|
||||
return parents;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2015, Julien Henry
|
||||
*
|
||||
* 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.net.URL;
|
||||
|
||||
/**
|
||||
* File detail inside a {@link GHPullRequest}.
|
||||
*
|
||||
* @author Julien Henry
|
||||
* @see GHPullRequest#listFiles()
|
||||
*/
|
||||
public class GHPullRequestFileDetail {
|
||||
|
||||
String sha;
|
||||
String filename;
|
||||
String status;
|
||||
int additions;
|
||||
int deletions;
|
||||
int changes;
|
||||
String blob_url;
|
||||
String raw_url;
|
||||
String contents_url;
|
||||
String patch;
|
||||
|
||||
public String getSha() {
|
||||
return sha;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public int getAdditions() {
|
||||
return additions;
|
||||
}
|
||||
|
||||
public int getDeletions() {
|
||||
return deletions;
|
||||
}
|
||||
|
||||
public int getChanges() {
|
||||
return changes;
|
||||
}
|
||||
|
||||
public URL getBlobUrl() {
|
||||
return GitHub.parseURL(blob_url);
|
||||
}
|
||||
|
||||
public URL getRawUrl() {
|
||||
return GitHub.parseURL(raw_url);
|
||||
}
|
||||
|
||||
public URL getContentsUrl() {
|
||||
return GitHub.parseURL(contents_url);
|
||||
}
|
||||
|
||||
public String getPatch() {
|
||||
return patch;
|
||||
}
|
||||
}
|
||||
105
src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java
Normal file
105
src/main/java/org/kohsuke/github/GHPullRequestReviewComment.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.net.URL;
|
||||
|
||||
/**
|
||||
* Review comment to the pull request
|
||||
*
|
||||
* @author Julien Henry
|
||||
* @see GHPullRequest#listReviewComments()
|
||||
* @see GHPullRequest#createReviewComment(String, String, String, int)
|
||||
*/
|
||||
public class GHPullRequestReviewComment extends GHObject {
|
||||
GHPullRequest owner;
|
||||
|
||||
private String body;
|
||||
private GHUser user;
|
||||
private String path;
|
||||
private int position;
|
||||
private int originalPosition;
|
||||
|
||||
/*package*/ GHPullRequestReviewComment wrapUp(GHPullRequest owner) {
|
||||
this.owner = owner;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pull request to which this review comment is associated.
|
||||
*/
|
||||
public GHPullRequest getParent() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* The comment itself.
|
||||
*/
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user who posted this comment.
|
||||
*/
|
||||
public GHUser getUser() throws IOException {
|
||||
return owner.root.getUser(user.getLogin());
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public int getOriginalPosition() {
|
||||
return originalPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getHtmlUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String getApiRoute() {
|
||||
return "/repos/"+owner.getRepository().getFullName()+"/comments/"+id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the comment.
|
||||
*/
|
||||
public void update(String body) throws IOException {
|
||||
new Requester(owner.root).method("PATCH").with("body", body).to(getApiRoute(),this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes this review comment.
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
new Requester(owner.root).method("DELETE").to(getApiRoute());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Rate limit.
|
||||
* @author Kohsuke Kawaguchi
|
||||
@@ -10,12 +12,28 @@ public class GHRateLimit {
|
||||
*/
|
||||
public int remaining;
|
||||
/**
|
||||
* Alotted API call per hour.
|
||||
* Allotted API call per hour.
|
||||
*/
|
||||
public int limit;
|
||||
|
||||
/**
|
||||
* The time at which the current rate limit window resets in UTC epoch seconds.
|
||||
*/
|
||||
public Date reset;
|
||||
|
||||
/**
|
||||
* Non-epoch date
|
||||
*/
|
||||
public Date getResetDate() {
|
||||
return new Date(reset.getTime() * 1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return remaining+"/"+limit;
|
||||
return "GHRateLimit{" +
|
||||
"remaining=" + remaining +
|
||||
", limit=" + limit +
|
||||
", resetDate=" + getResetDate() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
@@ -8,6 +9,7 @@ import java.net.URL;
|
||||
* @author Michael Clarke
|
||||
*/
|
||||
public class GHRef {
|
||||
/*package almost final*/ GitHub root;
|
||||
|
||||
private String ref, url;
|
||||
private GHObject object;
|
||||
@@ -33,6 +35,48 @@ public class GHRef {
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this ref to the specified commit.
|
||||
*
|
||||
* @param sha
|
||||
* The SHA1 value to set this reference to
|
||||
*/
|
||||
public void updateTo(String sha) throws IOException {
|
||||
updateTo(sha, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this ref to the specified commit.
|
||||
*
|
||||
* @param sha
|
||||
* The SHA1 value to set this reference to
|
||||
* @param force
|
||||
* Whether or not to force this ref update.
|
||||
*/
|
||||
public void updateTo(String sha, Boolean force) throws IOException {
|
||||
new Requester(root)
|
||||
.with("sha", sha).with("force", force).method("PATCH").to(url, GHRef.class).wrap(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes this ref from the repository using the GitHub API.
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
new Requester(root).method("DELETE").to(url);
|
||||
}
|
||||
|
||||
/*package*/ GHRef wrap(GitHub root) {
|
||||
this.root = root;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*package*/ static GHRef[] wrap(GHRef[] in, GitHub root) {
|
||||
for (GHRef r : in) {
|
||||
r.wrap(root);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
public static class GHObject {
|
||||
private String type, sha, url;
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.kohsuke.github;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@@ -15,22 +16,19 @@ import static java.lang.String.format;
|
||||
* @see GHRepository#getReleases()
|
||||
* @see GHRepository#createRelease(String)
|
||||
*/
|
||||
public class GHRelease {
|
||||
public class GHRelease extends GHObject {
|
||||
GitHub root;
|
||||
GHRepository owner;
|
||||
|
||||
private String url;
|
||||
private String html_url;
|
||||
private String assets_url;
|
||||
private String upload_url;
|
||||
private long id;
|
||||
private String tag_name;
|
||||
private String target_commitish;
|
||||
private String name;
|
||||
private String body;
|
||||
private boolean draft;
|
||||
private boolean prerelease;
|
||||
private Date created_at;
|
||||
private Date published_at;
|
||||
private String tarball_url;
|
||||
private String zipball_url;
|
||||
@@ -39,48 +37,16 @@ public class GHRelease {
|
||||
return assets_url;
|
||||
}
|
||||
|
||||
public void setAssetsUrl(String assets_url) {
|
||||
this.assets_url = assets_url;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(String body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return created_at;
|
||||
}
|
||||
|
||||
public void setCreatedAt(Date created_at) {
|
||||
this.created_at = created_at;
|
||||
}
|
||||
|
||||
public boolean isDraft() {
|
||||
return draft;
|
||||
}
|
||||
|
||||
public void setDraft(boolean draft) {
|
||||
this.draft = draft;
|
||||
}
|
||||
|
||||
public String getHtmlUrl() {
|
||||
return html_url;
|
||||
}
|
||||
|
||||
public void setHtmlUrl(String html_url) {
|
||||
this.html_url = html_url;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
public URL getHtmlUrl() {
|
||||
return GitHub.parseURL(html_url);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -103,74 +69,34 @@ public class GHRelease {
|
||||
return prerelease;
|
||||
}
|
||||
|
||||
public void setPrerelease(boolean prerelease) {
|
||||
this.prerelease = prerelease;
|
||||
}
|
||||
|
||||
public Date getPublished_at() {
|
||||
return published_at;
|
||||
}
|
||||
|
||||
public void setPublished_at(Date published_at) {
|
||||
this.published_at = published_at;
|
||||
}
|
||||
|
||||
public GitHub getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public void setRoot(GitHub root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public String getTagName() {
|
||||
return tag_name;
|
||||
}
|
||||
|
||||
public void setTagName(String tag_name) {
|
||||
this.tag_name = tag_name;
|
||||
}
|
||||
|
||||
public String getTargetCommitish() {
|
||||
return target_commitish;
|
||||
}
|
||||
|
||||
public void setTargetCommitish(String target_commitish) {
|
||||
this.target_commitish = target_commitish;
|
||||
}
|
||||
|
||||
public String getUploadUrl() {
|
||||
return upload_url;
|
||||
}
|
||||
|
||||
public void setUploadUrl(String upload_url) {
|
||||
this.upload_url = upload_url;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getZipballUrl() {
|
||||
return zipball_url;
|
||||
}
|
||||
|
||||
public void setZipballUrl(String zipballUrl) {
|
||||
this.zipball_url = zipballUrl;
|
||||
}
|
||||
|
||||
public String getTarballUrl() {
|
||||
return tarball_url;
|
||||
}
|
||||
|
||||
public void setTarballUrl(String tarballUrl) {
|
||||
this.tarball_url = tarballUrl;
|
||||
}
|
||||
|
||||
GHRelease wrap(GHRepository owner) {
|
||||
this.owner = owner;
|
||||
this.root = owner.root;
|
||||
@@ -195,7 +121,7 @@ public class GHRelease {
|
||||
public GHAsset uploadAsset(File file, String contentType) throws IOException {
|
||||
Requester builder = new Requester(owner.root);
|
||||
|
||||
String url = format("https://uploads.github.com%sreleases/%d/assets?name=%s",
|
||||
String url = format("https://uploads.github.com%s/releases/%d/assets?name=%s",
|
||||
owner.getApiTailUrl(""), getId(), file.getName());
|
||||
return builder.contentType(contentType)
|
||||
.with(new FileInputStream(file))
|
||||
|
||||
@@ -25,28 +25,18 @@ package org.kohsuke.github;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||
import java.io.FileNotFoundException;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* A repository on GitHub.
|
||||
@@ -54,11 +44,10 @@ import static java.util.Arrays.*;
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public class GHRepository {
|
||||
public class GHRepository extends GHObject {
|
||||
/*package almost final*/ GitHub root;
|
||||
|
||||
private String description, homepage, name;
|
||||
private String url; // this is the API url
|
||||
private String description, homepage, name, full_name;
|
||||
private String html_url; // this is the UI
|
||||
private String git_url, ssh_url, clone_url, svn_url;
|
||||
private GHUser owner; // not fully populated. beware.
|
||||
@@ -66,7 +55,7 @@ public class GHRepository {
|
||||
@JsonProperty("private")
|
||||
private boolean _private;
|
||||
private int watchers,forks,open_issues,size,network_count,subscribers_count;
|
||||
private String created_at, pushed_at;
|
||||
private String pushed_at;
|
||||
private Map<Integer,GHMilestone> milestones = new HashMap<Integer, GHMilestone>();
|
||||
|
||||
private String default_branch,language;
|
||||
@@ -74,6 +63,61 @@ public class GHRepository {
|
||||
|
||||
private GHRepoPermission permissions;
|
||||
|
||||
private GHRepository source, parent;
|
||||
|
||||
public GHDeploymentBuilder createDeployment(String ref) {
|
||||
return new GHDeploymentBuilder(this,ref);
|
||||
}
|
||||
|
||||
public PagedIterable<GHDeploymentStatus> getDeploymentStatuses(final int id) {
|
||||
return new PagedIterable<GHDeploymentStatus>() {
|
||||
public PagedIterator<GHDeploymentStatus> iterator() {
|
||||
return new PagedIterator<GHDeploymentStatus>(root.retrieve().asIterator(getApiTailUrl("deployments")+"/"+id+"/statuses", GHDeploymentStatus[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(GHDeploymentStatus[] page) {
|
||||
for (GHDeploymentStatus c : page)
|
||||
c.wrap(GHRepository.this);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public PagedIterable<GHDeployment> listDeployments(String sha,String ref,String task,String environment){
|
||||
List<String> params = Arrays.asList(getParam("sha", sha), getParam("ref", ref), getParam("task", task), getParam("environment", environment));
|
||||
final String deploymentsUrl = getApiTailUrl("deployments") + "?"+ join(params,"&");
|
||||
return new PagedIterable<GHDeployment>() {
|
||||
public PagedIterator<GHDeployment> iterator() {
|
||||
return new PagedIterator<GHDeployment>(root.retrieve().asIterator(deploymentsUrl, GHDeployment[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(GHDeployment[] page) {
|
||||
for (GHDeployment c : page)
|
||||
c.wrap(GHRepository.this);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private String join(List<String> params, String joinStr) {
|
||||
StringBuilder output = new StringBuilder();
|
||||
for(String param: params){
|
||||
if(param != null){
|
||||
output.append(param+joinStr);
|
||||
}
|
||||
}
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
private String getParam(String name, String value) {
|
||||
return StringUtils.trimToNull(value)== null? null: name+"="+value;
|
||||
}
|
||||
|
||||
public GHDeploymentStatusBuilder createDeployStatus(int deploymentId, GHDeploymentState ghDeploymentState) {
|
||||
return new GHDeploymentStatusBuilder(this,deploymentId,ghDeploymentState);
|
||||
}
|
||||
|
||||
private static class GHRepoPermission {
|
||||
boolean pull,push,admin;
|
||||
}
|
||||
@@ -87,13 +131,6 @@ public class GHRepository {
|
||||
return homepage;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL of this repository, like 'http://github.com/kohsuke/jenkins'
|
||||
*/
|
||||
public String getUrl() {
|
||||
return html_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the git:// URL to this repository, such as "git://github.com/kohsuke/jenkins.git"
|
||||
* This URL is read-only.
|
||||
@@ -124,6 +161,10 @@ public class GHRepository {
|
||||
return ssh_url;
|
||||
}
|
||||
|
||||
public URL getHtmlUrl() {
|
||||
return GitHub.parseURL(html_url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins
|
||||
*/
|
||||
@@ -131,6 +172,13 @@ public class GHRepository {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full repository name including the owner or organization. For example 'jenkinsci/jenkins' in case of http://github.com/jenkinsci/jenkins
|
||||
*/
|
||||
public String getFullName() {
|
||||
return full_name;
|
||||
}
|
||||
|
||||
public boolean hasPullAccess() {
|
||||
return permissions!=null && permissions.pull;
|
||||
}
|
||||
@@ -155,7 +203,7 @@ public class GHRepository {
|
||||
}
|
||||
|
||||
public GHIssue getIssue(int id) throws IOException {
|
||||
return root.retrieve().to("/repos/" + owner.login + "/" + name + "/issues/" + id, GHIssue.class).wrap(this);
|
||||
return root.retrieve().to(getApiTailUrl("issues/" + id), GHIssue.class).wrap(this);
|
||||
}
|
||||
|
||||
public GHIssueBuilder createIssue(String title) {
|
||||
@@ -168,8 +216,8 @@ public class GHRepository {
|
||||
|
||||
public List<GHIssue> getIssues(GHIssueState state, GHMilestone milestone) throws IOException {
|
||||
return Arrays.asList(GHIssue.wrap(root.retrieve()
|
||||
.to(String.format("/repos/%s/%s/issues?state=%s&milestone=%s", owner.login, name,
|
||||
state.toString().toLowerCase(), milestone == null ? "none" : "" + milestone.getNumber()),
|
||||
.to(getApiTailUrl(String.format("issues?state=%s&milestone=%s",
|
||||
state.toString().toLowerCase(), milestone == null ? "none" : "" + milestone.getNumber())),
|
||||
GHIssue[].class
|
||||
), this));
|
||||
}
|
||||
@@ -206,7 +254,7 @@ public class GHRepository {
|
||||
*/
|
||||
public GHRef createRef(String name, String sha) throws IOException {
|
||||
return new Requester(root)
|
||||
.with("ref", name).with("sha", sha).method("POST").to(getApiTailUrl("git/refs"), GHRef.class);
|
||||
.with("ref", name).with("sha", sha).method("POST").to(getApiTailUrl("git/refs"), GHRef.class).wrap(root);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,7 +293,19 @@ public class GHRepository {
|
||||
};
|
||||
}
|
||||
|
||||
protected String getOwnerName() {
|
||||
/**
|
||||
* List languages for the specified repository.
|
||||
* The value on the right of a language is the number of bytes of code written in that language.
|
||||
* {
|
||||
"C": 78769,
|
||||
"Python": 7769
|
||||
}
|
||||
*/
|
||||
public Map<String,Long> listLanguages() throws IOException {
|
||||
return root.retrieve().to(getApiTailUrl("languages"), HashMap.class);
|
||||
}
|
||||
|
||||
public String getOwnerName() {
|
||||
return owner.login;
|
||||
}
|
||||
|
||||
@@ -298,12 +358,8 @@ public class GHRepository {
|
||||
return GitHub.parseDate(pushed_at);
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return GitHub.parseDate(created_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the primary branch you'll configure in the "Admin > Options" config page.
|
||||
* Returns the primary branch you'll configure in the "Admin > Options" config page.
|
||||
*
|
||||
* @return
|
||||
* This field is null until the user explicitly configures the master branch.
|
||||
@@ -335,7 +391,7 @@ public class GHRepository {
|
||||
return new PagedIterable<GHUser>() {
|
||||
public PagedIterator<GHUser> iterator() {
|
||||
|
||||
return new PagedIterator<GHUser>(root.retrieve().asIterator("/repos/" + owner.login + "/" + name + "/collaborators", GHUser[].class)) {
|
||||
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl("collaborators"), GHUser[].class)) {
|
||||
|
||||
@Override
|
||||
protected void wrapUp(GHUser[] users) {
|
||||
@@ -356,7 +412,7 @@ public class GHRepository {
|
||||
*/
|
||||
public Set<String> getCollaboratorNames() throws IOException {
|
||||
Set<String> r = new HashSet<String>();
|
||||
for (GHUser u : GHUser.wrap(root.retrieve().to("/repos/" + owner.login + "/" + name + "/collaborators", GHUser[].class),root))
|
||||
for (GHUser u : GHUser.wrap(root.retrieve().to(getApiTailUrl("collaborators"), GHUser[].class),root))
|
||||
r.add(u.login);
|
||||
return r;
|
||||
}
|
||||
@@ -365,7 +421,7 @@ public class GHRepository {
|
||||
* If this repository belongs to an organization, return a set of teams.
|
||||
*/
|
||||
public Set<GHTeam> getTeams() throws IOException {
|
||||
return Collections.unmodifiableSet(new HashSet<GHTeam>(Arrays.asList(GHTeam.wrapUp(root.retrieve().to("/repos/" + owner.login + "/" + name + "/teams", GHTeam[].class), root.getOrganization(owner.login)))));
|
||||
return Collections.unmodifiableSet(new HashSet<GHTeam>(Arrays.asList(GHTeam.wrapUp(root.retrieve().to(getApiTailUrl("teams"), GHTeam[].class), root.getOrganization(owner.login)))));
|
||||
}
|
||||
|
||||
public void addCollaborators(GHUser... users) throws IOException {
|
||||
@@ -387,7 +443,7 @@ public class GHRepository {
|
||||
private void modifyCollaborators(Collection<GHUser> users, String method) throws IOException {
|
||||
verifyMine();
|
||||
for (GHUser user : users) {
|
||||
new Requester(root).method(method).to("/repos/" + owner.login + "/" + name + "/collaborators/" + user.getLogin());
|
||||
new Requester(root).method(method).to(getApiTailUrl("collaborators/" + user.getLogin()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,14 +451,14 @@ public class GHRepository {
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
config.put("address", address);
|
||||
new Requester(root).method("POST").with("name", "email").with("config", config).with("active", "true")
|
||||
.to(String.format("/repos/%s/%s/hooks", owner.login, name));
|
||||
.to(getApiTailUrl("hooks"));
|
||||
}
|
||||
|
||||
private void edit(String key, String value) throws IOException {
|
||||
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);
|
||||
requester.with(key, value).method("PATCH").to(getApiTailUrl(""));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -443,7 +499,7 @@ public class GHRepository {
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
try {
|
||||
new Requester(root).method("DELETE").to("/repos/" + owner.login + "/" + name);
|
||||
new Requester(root).method("DELETE").to(getApiTailUrl(""));
|
||||
} catch (FileNotFoundException x) {
|
||||
throw (FileNotFoundException) new FileNotFoundException("Failed to delete " + owner.login + "/" + name + "; might not exist, or you might need the delete_repo scope in your token: http://stackoverflow.com/a/19327004/12916").initCause(x);
|
||||
}
|
||||
@@ -456,7 +512,7 @@ public class GHRepository {
|
||||
* Newly forked repository that belong to you.
|
||||
*/
|
||||
public GHRepository fork() throws IOException {
|
||||
return new Requester(root).method("POST").to("/repos/" + owner.login + "/" + name + "/forks", GHRepository.class).wrap(root);
|
||||
return new Requester(root).method("POST").to(getApiTailUrl("forks"), GHRepository.class).wrap(root);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -466,7 +522,7 @@ public class GHRepository {
|
||||
* Newly forked repository that belong to you.
|
||||
*/
|
||||
public GHRepository forkTo(GHOrganization org) throws IOException {
|
||||
new Requester(root).to(String.format("/repos/%s/%s/forks?org=%s", owner.login, name, org.getLogin()));
|
||||
new Requester(root).to(getApiTailUrl("forks?org="+org.getLogin()));
|
||||
|
||||
// this API is asynchronous. we need to wait for a bit
|
||||
for (int i=0; i<10; i++) {
|
||||
@@ -485,7 +541,7 @@ public class GHRepository {
|
||||
* Retrieves a specified pull request.
|
||||
*/
|
||||
public GHPullRequest getPullRequest(int i) throws IOException {
|
||||
return root.retrieve().to("/repos/" + owner.login + '/' + name + "/pulls/" + i, GHPullRequest.class).wrapUp(this);
|
||||
return root.retrieve().to(getApiTailUrl("pulls/" + i), GHPullRequest.class).wrapUp(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -503,11 +559,11 @@ public class GHRepository {
|
||||
public PagedIterable<GHPullRequest> listPullRequests(final GHIssueState state) {
|
||||
return new PagedIterable<GHPullRequest>() {
|
||||
public PagedIterator<GHPullRequest> iterator() {
|
||||
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 PagedIterator<GHPullRequest>(root.retrieve().asIterator(getApiTailUrl("pulls?state="+state.name().toLowerCase(Locale.ENGLISH)), GHPullRequest[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(GHPullRequest[] page) {
|
||||
for (GHPullRequest pr : page)
|
||||
pr.wrap(GHRepository.this);
|
||||
pr.wrapUp(GHRepository.this);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -542,14 +598,14 @@ public class GHRepository {
|
||||
*/
|
||||
public List<GHHook> getHooks() throws IOException {
|
||||
List<GHHook> list = new ArrayList<GHHook>(Arrays.asList(
|
||||
root.retrieve().to(String.format("/repos/%s/%s/hooks", owner.login, name), GHHook[].class)));
|
||||
root.retrieve().to(getApiTailUrl("hooks"), GHHook[].class)));
|
||||
for (GHHook h : list)
|
||||
h.wrap(this);
|
||||
return list;
|
||||
}
|
||||
|
||||
public GHHook getHook(int id) throws IOException {
|
||||
return root.retrieve().to(String.format("/repos/%s/%s/hooks/%d", owner.login, name, id), GHHook.class).wrap(this);
|
||||
return root.retrieve().to(getApiTailUrl("hooks/" + id), GHHook.class).wrap(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -561,7 +617,7 @@ public class GHRepository {
|
||||
* @throws IOException on failure communicating with GitHub
|
||||
*/
|
||||
public GHCompare getCompare(String id1, String id2) throws IOException {
|
||||
GHCompare compare = root.retrieve().to(String.format("/repos/%s/%s/compare/%s...%s", owner.login, name, id1, id2), GHCompare.class);
|
||||
GHCompare compare = root.retrieve().to(getApiTailUrl(String.format("compare/%s...%s", id1, id2)), GHCompare.class);
|
||||
return compare.wrap(this);
|
||||
}
|
||||
|
||||
@@ -579,31 +635,60 @@ public class GHRepository {
|
||||
* @throws IOException on failure communicating with GitHub
|
||||
*/
|
||||
public GHRef[] getRefs() throws IOException {
|
||||
return root.retrieve().to(String.format("/repos/%s/%s/git/refs", owner.login, name), GHRef[].class);
|
||||
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs", owner.login, name), GHRef[].class),root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrienved all refs of the given type for the current GitHub repository.
|
||||
* Retrieves all refs of the given type for the current GitHub repository.
|
||||
* @param refType the type of reg to search for e.g. <tt>tags</tt> or <tt>commits</tt>
|
||||
* @return an array of all refs matching the request type
|
||||
* @throws IOException on failure communicating with GitHub, potentially due to an invalid ref type being requested
|
||||
*/
|
||||
public GHRef[] getRefs(String refType) throws IOException {
|
||||
return root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refType), GHRef[].class);
|
||||
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refType), GHRef[].class),root);
|
||||
}
|
||||
/**
|
||||
* Retrive a ref of the given type for the current GitHub repository.
|
||||
*
|
||||
* @param refName
|
||||
* eg: heads/branch
|
||||
* @return refs matching the request type
|
||||
* @throws IOException
|
||||
* on failure communicating with GitHub, potentially due to an
|
||||
* invalid ref type being requested
|
||||
*/
|
||||
public GHRef getRef(String refName) throws IOException {
|
||||
return root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refName), GHRef.class);
|
||||
}
|
||||
* Retrive a ref of the given type for the current GitHub repository.
|
||||
*
|
||||
* @param refName
|
||||
* eg: heads/branch
|
||||
* @return refs matching the request type
|
||||
* @throws IOException
|
||||
* on failure communicating with GitHub, potentially due to an
|
||||
* invalid ref type being requested
|
||||
*/
|
||||
public GHRef getRef(String refName) throws IOException {
|
||||
return root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", owner.login, name, refName), GHRef.class).wrap(root);
|
||||
}
|
||||
/**
|
||||
* Retrive a tree of the given type for the current GitHub repository.
|
||||
*
|
||||
* @param sha - sha number or branch name ex: "master"
|
||||
* @return refs matching the request type
|
||||
* @throws IOException
|
||||
* on failure communicating with GitHub, potentially due to an
|
||||
* invalid tree type being requested
|
||||
*/
|
||||
public GHTree getTree(String sha) throws IOException {
|
||||
String url = String.format("/repos/%s/%s/git/trees/%s", owner.login, name, sha);
|
||||
return root.retrieve().to(url, GHTree.class).wrap(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the tree for the current GitHub repository, recursively as described in here:
|
||||
* https://developer.github.com/v3/git/trees/#get-a-tree-recursively
|
||||
*
|
||||
* @param sha - sha number or branch name ex: "master"
|
||||
* @param recursive use 1
|
||||
* @throws IOException
|
||||
* on failure communicating with GitHub, potentially due to an
|
||||
* invalid tree type being requested
|
||||
*/
|
||||
public GHTree getTreeRecursive(String sha, int recursive) throws IOException {
|
||||
String url = String.format("/repos/%s/%s/git/trees/%s?recursive=%d", owner.login, name, sha, recursive);
|
||||
return root.retrieve().to(url, GHTree.class).wrap(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a commit object in this repository.
|
||||
*/
|
||||
@@ -701,10 +786,10 @@ public class GHRepository {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see {@link #createCommitStatus(String, GHCommitState,String,String,String) createCommitStatus}
|
||||
* @see #createCommitStatus(String, GHCommitState,String,String,String)
|
||||
*/
|
||||
public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) throws IOException {
|
||||
return createCommitStatus(sha1, state, targetUrl, description,null);
|
||||
return createCommitStatus(sha1, state, targetUrl, description,null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -724,6 +809,54 @@ public class GHRepository {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists labels in this repository.
|
||||
*
|
||||
* https://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository
|
||||
*/
|
||||
public PagedIterable<GHLabel> listLabels() throws IOException {
|
||||
return new PagedIterable<GHLabel>() {
|
||||
public PagedIterator<GHLabel> iterator() {
|
||||
return new PagedIterator<GHLabel>(root.retrieve().asIterator(getApiTailUrl("labels"), GHLabel[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(GHLabel[] page) {
|
||||
for (GHLabel c : page)
|
||||
c.wrapUp(GHRepository.this);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public GHLabel getLabel(String name) throws IOException {
|
||||
return root.retrieve().to(getApiTailUrl("labels/"+name), GHLabel.class).wrapUp(this);
|
||||
}
|
||||
|
||||
public GHLabel createLabel(String name, String color) throws IOException {
|
||||
return root.retrieve().method("POST")
|
||||
.with("name",name)
|
||||
.with("color",color)
|
||||
.to(getApiTailUrl("labels"), GHLabel.class).wrapUp(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all the subscribers (aka watchers.)
|
||||
*
|
||||
* https://developer.github.com/v3/activity/watching/
|
||||
*/
|
||||
public PagedIterable<GHUser> listSubscribers() {
|
||||
return new PagedIterable<GHUser>() {
|
||||
public PagedIterator<GHUser> iterator() {
|
||||
return new PagedIterator<GHUser>(root.retrieve().asIterator(getApiTailUrl("subscribers"), GHUser[].class)) {
|
||||
protected void wrapUp(GHUser[] page) {
|
||||
for (GHUser c : page)
|
||||
c.wrapUp(root);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* See https://api.github.com/hooks for possible names and their configuration scheme.
|
||||
@@ -862,10 +995,10 @@ public class GHRepository {
|
||||
*/
|
||||
public Map<Integer, GHMilestone> getMilestones() throws IOException {
|
||||
Map<Integer,GHMilestone> milestones = new TreeMap<Integer, GHMilestone>();
|
||||
for (GHMilestone m : listMilestones(GHIssueState.OPEN)) {
|
||||
milestones.put(m.getNumber(), m);
|
||||
}
|
||||
return milestones;
|
||||
for (GHMilestone m : listMilestones(GHIssueState.OPEN)) {
|
||||
milestones.put(m.getNumber(), m);
|
||||
}
|
||||
return milestones;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -885,16 +1018,16 @@ public class GHRepository {
|
||||
};
|
||||
}
|
||||
|
||||
public GHMilestone getMilestone(int number) throws IOException {
|
||||
GHMilestone m = milestones.get(number);
|
||||
if (m == null) {
|
||||
public GHMilestone getMilestone(int number) throws IOException {
|
||||
GHMilestone m = milestones.get(number);
|
||||
if (m == null) {
|
||||
m = root.retrieve().to(getApiTailUrl("milestones/" + number), GHMilestone.class);
|
||||
m.owner = this;
|
||||
m.root = root;
|
||||
milestones.put(m.getNumber(), m);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
m.owner = this;
|
||||
m.root = root;
|
||||
milestones.put(m.getNumber(), m);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public GHContent getFileContent(String path) throws IOException {
|
||||
return getFileContent(path, null);
|
||||
@@ -902,12 +1035,9 @@ public class GHRepository {
|
||||
|
||||
public GHContent getFileContent(String path, String ref) throws IOException {
|
||||
Requester requester = root.retrieve();
|
||||
String target = String.format("/repos/%s/%s/contents/%s", owner.login, name, path);
|
||||
String target = getApiTailUrl("contents/" + path);
|
||||
|
||||
if (ref != null)
|
||||
target = target + "?ref=" + ref;
|
||||
|
||||
return requester.to(target, GHContent.class).wrap(this);
|
||||
return requester.with("ref",ref).to(target, GHContent.class).wrap(this);
|
||||
}
|
||||
|
||||
public List<GHContent> getDirectoryContent(String path) throws IOException {
|
||||
@@ -916,31 +1046,40 @@ public class GHRepository {
|
||||
|
||||
public List<GHContent> getDirectoryContent(String path, String ref) throws IOException {
|
||||
Requester requester = root.retrieve();
|
||||
String target = String.format("/repos/%s/%s/contents/%s", owner.login, name, path);
|
||||
String target = getApiTailUrl("contents/" + path);
|
||||
|
||||
if (ref != null)
|
||||
target = target + "?ref=" + ref;
|
||||
|
||||
GHContent[] files = requester.to(target, GHContent[].class);
|
||||
GHContent[] files = requester.with("ref",ref).to(target, GHContent[].class);
|
||||
|
||||
GHContent.wrap(files, this);
|
||||
|
||||
return Arrays.asList(files);
|
||||
}
|
||||
|
||||
public GHContent getReadme() throws Exception {
|
||||
return getFileContent("readme");
|
||||
/**
|
||||
* https://developer.github.com/v3/repos/contents/#get-the-readme
|
||||
*/
|
||||
public GHContent getReadme() throws IOException {
|
||||
Requester requester = root.retrieve();
|
||||
return requester.to(getApiTailUrl("readme"), GHContent.class).wrap(this);
|
||||
}
|
||||
|
||||
public GHContentUpdateResponse createContent(String content, String commitMessage, String path) throws IOException {
|
||||
return createContent(content, commitMessage, path, null);
|
||||
return createContent(content.getBytes(), commitMessage, path, null);
|
||||
}
|
||||
|
||||
public GHContentUpdateResponse createContent(String content, String commitMessage, String path, String branch) throws IOException {
|
||||
return createContent(content.getBytes(), commitMessage, path, branch);
|
||||
}
|
||||
|
||||
public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path) throws IOException {
|
||||
return createContent(contentBytes, commitMessage, path, null);
|
||||
}
|
||||
|
||||
public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path, String branch) throws IOException {
|
||||
Requester requester = new Requester(root)
|
||||
.with("path", path)
|
||||
.with("message", commitMessage)
|
||||
.with("content", DatatypeConverter.printBase64Binary(content.getBytes()))
|
||||
.with("content", DatatypeConverter.printBase64Binary(contentBytes))
|
||||
.method("PUT");
|
||||
|
||||
if (branch != null) {
|
||||
@@ -955,26 +1094,127 @@ public class GHRepository {
|
||||
return response;
|
||||
}
|
||||
|
||||
public GHMilestone createMilestone(String title, String description) throws IOException {
|
||||
public GHMilestone createMilestone(String title, String description) throws IOException {
|
||||
return new Requester(root)
|
||||
.with("title", title).with("description", description).method("POST").to(getApiTailUrl("milestones"), GHMilestone.class).wrap(this);
|
||||
}
|
||||
|
||||
public GHDeployKey addDeployKey(String title,String key) throws IOException {
|
||||
return new Requester(root)
|
||||
}
|
||||
|
||||
public GHDeployKey addDeployKey(String title,String key) throws IOException {
|
||||
return new Requester(root)
|
||||
.with("title", title).with("key", key).method("POST").to(getApiTailUrl("keys"), GHDeployKey.class).wrap(this);
|
||||
|
||||
}
|
||||
|
||||
public List<GHDeployKey> getDeployKeys() throws IOException{
|
||||
List<GHDeployKey> list = new ArrayList<GHDeployKey>(Arrays.asList(
|
||||
root.retrieve().to(String.format("/repos/%s/%s/keys", owner.login, name), GHDeployKey[].class)));
|
||||
for (GHDeployKey h : list)
|
||||
h.wrap(this);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public List<GHDeployKey> getDeployKeys() throws IOException{
|
||||
List<GHDeployKey> list = new ArrayList<GHDeployKey>(Arrays.asList(
|
||||
root.retrieve().to(getApiTailUrl("keys"), GHDeployKey[].class)));
|
||||
for (GHDeployKey h : list)
|
||||
h.wrap(this);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forked repositories have a 'source' attribute that specifies the ultimate source of the forking chain.
|
||||
*
|
||||
* @return
|
||||
* {@link GHRepository} that points to the root repository where this repository is forked
|
||||
* (indirectly or directly) from. Otherwise null.
|
||||
* @see #getParent()
|
||||
*/
|
||||
public GHRepository getSource() throws IOException {
|
||||
if (source == null) return null;
|
||||
if (source.root == null)
|
||||
source = root.getRepository(source.getFullName());
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forked repositories have a 'parent' attribute that specifies the repository this repository
|
||||
* is directly forked from. If we keep traversing {@link #getParent()} until it returns null, that
|
||||
* is {@link #getSource()}.
|
||||
*
|
||||
* @return
|
||||
* {@link GHRepository} that points to the repository where this repository is forked
|
||||
* directly from. Otherwise null.
|
||||
* @see #getSource()
|
||||
*/
|
||||
public GHRepository getParent() throws IOException {
|
||||
if (parent == null) return null;
|
||||
if (parent.root == null)
|
||||
parent = root.getRepository(parent.getFullName());
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to this repository to get notifications.
|
||||
*/
|
||||
public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException {
|
||||
return new Requester(root)
|
||||
.with("subscribed", subscribed)
|
||||
.with("ignored", ignored)
|
||||
.method("PUT").to(getApiTailUrl("subscription"), GHSubscription.class).wrapUp(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current subscription.
|
||||
*
|
||||
* @return null if no subscription exists.
|
||||
*/
|
||||
public GHSubscription getSubscription() throws IOException {
|
||||
try {
|
||||
return new Requester(root).to(getApiTailUrl("subscription"), GHSubscription.class).wrapUp(this);
|
||||
} catch (FileNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public PagedIterable<Contributor> listContributors() throws IOException {
|
||||
return new PagedIterable<Contributor>() {
|
||||
public PagedIterator<Contributor> iterator() {
|
||||
return new PagedIterator<Contributor>(root.retrieve().asIterator(getApiTailUrl("contributors"), Contributor[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(Contributor[] page) {
|
||||
for (Contributor c : page)
|
||||
c.wrapUp(root);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class Contributor extends GHUser {
|
||||
private int contributions;
|
||||
|
||||
public int getContributions() {
|
||||
return contributions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Markdown document.
|
||||
*
|
||||
* In {@linkplain MarkdownMode#GFM GFM mode}, issue numbers and user mentions
|
||||
* are linked accordingly.
|
||||
*
|
||||
* @see GitHub#renderMarkdown(String)
|
||||
*/
|
||||
public Reader renderMarkdown(String text, MarkdownMode mode) throws IOException {
|
||||
return new InputStreamReader(
|
||||
new Requester(root)
|
||||
.with("text", text)
|
||||
.with("mode",mode==null?null:mode.toString())
|
||||
.with("context", getFullName())
|
||||
.asStream("/markdown"),
|
||||
"UTF-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* List all the notifications in a repository for the current user.
|
||||
*/
|
||||
public GHNotificationStream listNotifications() {
|
||||
return new GHNotificationStream(root,getApiTailUrl("/notifications"));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -997,6 +1237,7 @@ public class GHRepository {
|
||||
}
|
||||
|
||||
String getApiTailUrl(String tail) {
|
||||
return "/repos/" + owner.login + "/" + name +'/'+tail;
|
||||
if (tail.length()>0 && !tail.startsWith("/")) tail='/'+tail;
|
||||
return "/repos/" + owner.login + "/" + name +tail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Search repositories.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GitHub#searchRepositories()
|
||||
*/
|
||||
public class GHRepositorySearchBuilder extends GHSearchBuilder<GHRepository> {
|
||||
/*package*/ GHRepositorySearchBuilder(GitHub root) {
|
||||
super(root,RepositorySearchResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search terms.
|
||||
*/
|
||||
public GHRepositorySearchBuilder q(String term) {
|
||||
super.q(term);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder in(String v) {
|
||||
return q("in:"+v);
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder size(String v) {
|
||||
return q("size:"+v);
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder forks(String v) {
|
||||
return q("forks:"+v);
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder created(String v) {
|
||||
return q("created:"+v);
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder pushed(String v) {
|
||||
return q("pushed:"+v);
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder user(String v) {
|
||||
return q("user:"+v);
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder repo(String v) {
|
||||
return q("repo:"+v);
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder language(String v) {
|
||||
return q("language:"+v);
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder stars(String v) {
|
||||
return q("stars:"+v);
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder sort(Sort sort) {
|
||||
req.with("sort",sort.toString().toLowerCase(Locale.ENGLISH));
|
||||
return this;
|
||||
}
|
||||
|
||||
public enum Sort { STARS, FORKS, UPDATED }
|
||||
|
||||
private static class RepositorySearchResult extends SearchResult<GHRepository> {
|
||||
private GHRepository[] items;
|
||||
|
||||
@Override
|
||||
/*package*/ GHRepository[] getItems(GitHub root) {
|
||||
for (GHRepository item : items)
|
||||
item.wrap(root);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getApiUrl() {
|
||||
return "/search/repositories";
|
||||
}
|
||||
}
|
||||
54
src/main/java/org/kohsuke/github/GHSearchBuilder.java
Normal file
54
src/main/java/org/kohsuke/github/GHSearchBuilder.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Base class for various search builders.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public abstract class GHSearchBuilder<T> {
|
||||
protected final GitHub root;
|
||||
protected final Requester req;
|
||||
protected final List<String> terms = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Data transfer object that receives the result of search.
|
||||
*/
|
||||
private final Class<? extends SearchResult<T>> receiverType;
|
||||
|
||||
/*package*/ GHSearchBuilder(GitHub root, Class<? extends SearchResult<T>> receiverType) {
|
||||
this.root = root;
|
||||
this.req = root.retrieve();
|
||||
this.receiverType = receiverType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search terms.
|
||||
*/
|
||||
public GHSearchBuilder q(String term) {
|
||||
terms.add(term);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the search.
|
||||
*/
|
||||
public PagedSearchIterable<T> list() {
|
||||
return new PagedSearchIterable<T>(root) {
|
||||
public PagedIterator<T> iterator() {
|
||||
req.set("q", StringUtils.join(terms, " "));
|
||||
return new PagedIterator<T>(adapt(req.asIterator(getApiUrl(), receiverType))) {
|
||||
protected void wrapUp(T[] page) {
|
||||
// SearchResult.getItems() should do it
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract String getApiUrl();
|
||||
}
|
||||
64
src/main/java/org/kohsuke/github/GHSubscription.java
Normal file
64
src/main/java/org/kohsuke/github/GHSubscription.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Represents your subscribing to a repository / conversation thread..
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GHRepository#getSubscription()
|
||||
* @see GHThread#getSubscription()
|
||||
*/
|
||||
public class GHSubscription {
|
||||
private String created_at, url, repository_url, reason;
|
||||
private boolean subscribed, ignored;
|
||||
|
||||
private GitHub root;
|
||||
private GHRepository repo;
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return GitHub.parseDate(created_at);
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getRepositoryUrl() {
|
||||
return repository_url;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public boolean isSubscribed() {
|
||||
return subscribed;
|
||||
}
|
||||
|
||||
public boolean isIgnored() {
|
||||
return ignored;
|
||||
}
|
||||
|
||||
public GHRepository getRepository() {
|
||||
return repo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes this subscription.
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
new Requester(root).method("DELETE").to(url);
|
||||
}
|
||||
|
||||
GHSubscription wrapUp(GHRepository repo) {
|
||||
this.repo = repo;
|
||||
return wrapUp(repo.root);
|
||||
}
|
||||
|
||||
GHSubscription wrapUp(GitHub root) {
|
||||
this.root = root;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@ public class GHTag {
|
||||
/*package*/ GHTag wrap(GHRepository owner) {
|
||||
this.owner = owner;
|
||||
this.root = owner.root;
|
||||
if (commit!=null)
|
||||
commit.wrapUp(owner);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
@@ -15,6 +14,7 @@ import java.util.TreeMap;
|
||||
public class GHTeam {
|
||||
private String name,permission;
|
||||
private int id;
|
||||
private GHOrganization organization; // populated by GET /user/teams where Teams+Orgs are returned together
|
||||
|
||||
protected /*final*/ GHOrganization org;
|
||||
|
||||
@@ -23,6 +23,11 @@ public class GHTeam {
|
||||
return this;
|
||||
}
|
||||
|
||||
/*package*/ GHTeam wrapUp(GitHub root) { // auto-wrapUp when organization is known from GET /user/teams
|
||||
this.organization.wrapUp(root);
|
||||
return wrapUp(organization);
|
||||
}
|
||||
|
||||
/*package*/ static GHTeam[] wrapUp(GHTeam[] teams, GHOrganization owner) {
|
||||
for (GHTeam t : teams) {
|
||||
t.wrapUp(owner);
|
||||
@@ -45,8 +50,21 @@ public class GHTeam {
|
||||
/**
|
||||
* Retrieves the current members.
|
||||
*/
|
||||
public PagedIterable<GHUser> listMembers() throws IOException {
|
||||
return new PagedIterable<GHUser>() {
|
||||
public PagedIterator<GHUser> iterator() {
|
||||
return new PagedIterator<GHUser>(org.root.retrieve().asIterator(api("/members"), GHUser[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(GHUser[] page) {
|
||||
GHUser.wrap(page, org.root);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Set<GHUser> getMembers() throws IOException {
|
||||
return new HashSet<GHUser>(Arrays.asList(GHUser.wrap(org.root.retrieve().to(api("/members"), GHUser[].class), org.root)));
|
||||
return Collections.unmodifiableSet(listMembers().asSet());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,19 +80,36 @@ public class GHTeam {
|
||||
}
|
||||
|
||||
public Map<String,GHRepository> getRepositories() throws IOException {
|
||||
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));
|
||||
for (GHRepository r : listRepositories()) {
|
||||
m.put(r.getName(), r);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public PagedIterable<GHRepository> listRepositories() {
|
||||
return new PagedIterable<GHRepository>() {
|
||||
public PagedIterator<GHRepository> iterator() {
|
||||
return new PagedIterator<GHRepository>(org.root.retrieve().asIterator(api("/repos"), GHRepository[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(GHRepository[] page) {
|
||||
for (GHRepository r : page)
|
||||
r.wrap(org.root);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a member to the team.
|
||||
*
|
||||
* The user will be invited to the organization if required.
|
||||
*
|
||||
* @since 1.59
|
||||
*/
|
||||
public void add(GHUser u) throws IOException {
|
||||
org.root.retrieve().method("PUT").to(api("/members/" + u.getLogin()), null);
|
||||
org.root.retrieve().method("PUT").to(api("/memberships/" + u.getLogin()), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,4 +130,8 @@ public class GHTeam {
|
||||
private String api(String tail) {
|
||||
return "/teams/"+id+tail;
|
||||
}
|
||||
|
||||
public GHOrganization getOrganization() {
|
||||
return org;
|
||||
}
|
||||
}
|
||||
|
||||
142
src/main/java/org/kohsuke/github/GHThread.java
Normal file
142
src/main/java/org/kohsuke/github/GHThread.java
Normal file
@@ -0,0 +1,142 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* A conversation in the notification API.
|
||||
*
|
||||
* @see <a href="https://developer.github.com/v3/activity/notifications/">documentation</a>
|
||||
* @see GHNotificationStream
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class GHThread extends GHObject {
|
||||
private GitHub root;
|
||||
private GHRepository repository;
|
||||
private Subject subject;
|
||||
private String reason;
|
||||
private boolean unread;
|
||||
private String last_read_at;
|
||||
private String url,subscription_url;
|
||||
|
||||
static class Subject {
|
||||
String title;
|
||||
String url;
|
||||
String latest_comment_url;
|
||||
String type;
|
||||
}
|
||||
|
||||
private GHThread() {// no external construction allowed
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null if the entire thread has never been read.
|
||||
*/
|
||||
public Date getLastReadAt() {
|
||||
return GitHub.parseDate(last_read_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This object has no HTML URL.
|
||||
*/
|
||||
@Override
|
||||
public URL getHtmlUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public GHRepository getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
// TODO: how to expose the subject?
|
||||
|
||||
public boolean isRead() {
|
||||
return !unread;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return subject.title;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return subject.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this thread is about an issue, return that issue.
|
||||
*
|
||||
* @return null if this thread is not about an issue.
|
||||
*/
|
||||
public GHIssue getBoundIssue() throws IOException {
|
||||
if (!"Issue".equals(subject.type) && "PullRequest".equals(subject.type))
|
||||
return null;
|
||||
return repository.getIssue(
|
||||
Integer.parseInt(subject.url.substring(subject.url.lastIndexOf('/') + 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* If this thread is about a pull request, return that pull request.
|
||||
*
|
||||
* @return null if this thread is not about a pull request.
|
||||
*/
|
||||
public GHPullRequest getBoundPullRequest() throws IOException {
|
||||
if (!"PullRequest".equals(subject.type))
|
||||
return null;
|
||||
return repository.getPullRequest(
|
||||
Integer.parseInt(subject.url.substring(subject.url.lastIndexOf('/') + 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* If this thread is about a commit, return that commit.
|
||||
*
|
||||
* @return null if this thread is not about a commit.
|
||||
*/
|
||||
public GHCommit getBoundCommit() throws IOException {
|
||||
if (!"Commit".equals(subject.type))
|
||||
return null;
|
||||
return repository.getCommit(subject.url.substring(subject.url.lastIndexOf('/') + 1));
|
||||
}
|
||||
|
||||
/*package*/ GHThread wrap(GitHub root) {
|
||||
this.root = root;
|
||||
if (this.repository!=null)
|
||||
this.repository.wrap(root);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this thread as read.
|
||||
*/
|
||||
public void markAsRead() throws IOException {
|
||||
new Requester(root).method("PATCH").to(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to this conversation to get notifications.
|
||||
*/
|
||||
public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException {
|
||||
return new Requester(root)
|
||||
.with("subscribed", subscribed)
|
||||
.with("ignored", ignored)
|
||||
.method("PUT").to(subscription_url, GHSubscription.class).wrapUp(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current subscription for this thread.
|
||||
*
|
||||
* @return null if no subscription exists.
|
||||
*/
|
||||
public GHSubscription getSubscription() throws IOException {
|
||||
try {
|
||||
return new Requester(root).to(subscription_url, GHSubscription.class).wrapUp(root);
|
||||
} catch (FileNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
src/main/java/org/kohsuke/github/GHTree.java
Normal file
58
src/main/java/org/kohsuke/github/GHTree.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides information for Git Trees
|
||||
* https://developer.github.com/v3/git/trees/
|
||||
*
|
||||
* @author Daniel Teixeira - https://github.com/ddtxra
|
||||
* @see GHRepository#getTree(String)
|
||||
*/
|
||||
public class GHTree {
|
||||
/* package almost final */GitHub root;
|
||||
|
||||
private boolean truncated;
|
||||
private String sha, url;
|
||||
private GHTreeEntry[] tree;
|
||||
|
||||
/**
|
||||
* The SHA for this trees
|
||||
*/
|
||||
public String getSha() {
|
||||
return sha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of entries of the trees
|
||||
* @return
|
||||
*/
|
||||
public List<GHTreeEntry> getTree() {
|
||||
return Collections.unmodifiableList(Arrays.asList(tree));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the number of items in the tree array exceeded the GitHub maximum limit.
|
||||
* @return true true if the number of items in the tree array exceeded the GitHub maximum limit otherwise false.
|
||||
*/
|
||||
public boolean isTruncated() {
|
||||
return truncated;
|
||||
}
|
||||
|
||||
/**
|
||||
* The API URL of this tag, such as
|
||||
* "url": "https://api.github.com/repos/octocat/Hello-World/trees/fc6274d15fa3ae2ab983129fb037999f264ba9a7",
|
||||
*/
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
|
||||
/* package */GHTree wrap(GitHub root) {
|
||||
this.root = root;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
71
src/main/java/org/kohsuke/github/GHTreeEntry.java
Normal file
71
src/main/java/org/kohsuke/github/GHTreeEntry.java
Normal file
@@ -0,0 +1,71 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Provides information for Git Trees
|
||||
* https://developer.github.com/v3/git/trees/
|
||||
*
|
||||
* @author Daniel Teixeira - https://github.com/ddtxra
|
||||
* @see GHTree
|
||||
*/
|
||||
public class GHTreeEntry {
|
||||
private String path, mode, type, sha, url;
|
||||
private long size;
|
||||
|
||||
/**
|
||||
* Get the path such as
|
||||
* "subdir/file.txt"
|
||||
*
|
||||
* @return the path
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mode such as
|
||||
* 100644
|
||||
*
|
||||
* @return the mode
|
||||
*/
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the file, such as
|
||||
* 132
|
||||
* @return The size of the path or 0 if it is a directory
|
||||
*/
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type such as:
|
||||
* "blob"
|
||||
*
|
||||
* @return The type
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SHA1 of this object.
|
||||
*/
|
||||
public String getSha() {
|
||||
return sha;
|
||||
}
|
||||
|
||||
/**
|
||||
* API URL to this Git data, such as
|
||||
* https://api.github.com/repos/jenkinsci
|
||||
* /jenkins/git/commits/b72322675eb0114363a9a86e9ad5a170d1d07ac0
|
||||
*/
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,24 @@ public class GHUser extends GHPerson {
|
||||
return new GHPersonSet<GHUser>(Arrays.asList(wrap(followers,root)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all the subscribed (aka watched) repositories.
|
||||
*
|
||||
* https://developer.github.com/v3/activity/watching/
|
||||
*/
|
||||
public PagedIterable<GHRepository> listSubscriptions() {
|
||||
return new PagedIterable<GHRepository>() {
|
||||
public PagedIterator<GHRepository> iterator() {
|
||||
return new PagedIterator<GHRepository>(root.retrieve().asIterator(getApiTailUrl("subscriptions"), GHRepository[].class)) {
|
||||
protected void wrapUp(GHRepository[] page) {
|
||||
for (GHRepository c : page)
|
||||
c.wrap(root);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this user belongs to the specified organization.
|
||||
*/
|
||||
@@ -162,4 +180,9 @@ public class GHUser extends GHPerson {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String getApiTailUrl(String tail) {
|
||||
if (tail.length()>0 && !tail.startsWith("/")) tail='/'+tail;
|
||||
return "/users/" + login + tail;
|
||||
}
|
||||
}
|
||||
|
||||
72
src/main/java/org/kohsuke/github/GHUserSearchBuilder.java
Normal file
72
src/main/java/org/kohsuke/github/GHUserSearchBuilder.java
Normal file
@@ -0,0 +1,72 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Search users.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GitHub#searchUsers()
|
||||
*/
|
||||
public class GHUserSearchBuilder extends GHSearchBuilder<GHUser> {
|
||||
/*package*/ GHUserSearchBuilder(GitHub root) {
|
||||
super(root,UserSearchResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search terms.
|
||||
*/
|
||||
public GHUserSearchBuilder q(String term) {
|
||||
super.q(term);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHUserSearchBuilder type(String v) {
|
||||
return q("type:"+v);
|
||||
}
|
||||
|
||||
public GHUserSearchBuilder in(String v) {
|
||||
return q("in:"+v);
|
||||
}
|
||||
|
||||
public GHUserSearchBuilder repos(String v) {
|
||||
return q("repos:"+v);
|
||||
}
|
||||
|
||||
public GHUserSearchBuilder location(String v) {
|
||||
return q("location:"+v);
|
||||
}
|
||||
|
||||
public GHUserSearchBuilder language(String v) {
|
||||
return q("language:"+v);
|
||||
}
|
||||
|
||||
public GHUserSearchBuilder created(String v) {
|
||||
return q("created:"+v);
|
||||
}
|
||||
|
||||
public GHUserSearchBuilder followers(String v) {
|
||||
return q("followers:"+v);
|
||||
}
|
||||
|
||||
public GHUserSearchBuilder sort(Sort sort) {
|
||||
req.with("sort",sort.toString().toLowerCase(Locale.ENGLISH));
|
||||
return this;
|
||||
}
|
||||
|
||||
public enum Sort { FOLLOWERS, REPOSITORIES, JOINED }
|
||||
|
||||
private static class UserSearchResult extends SearchResult<GHUser> {
|
||||
private GHUser[] items;
|
||||
|
||||
@Override
|
||||
/*package*/ GHUser[] getItems(GitHub root) {
|
||||
return GHUser.wrap(items,root);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getApiUrl() {
|
||||
return "/search/users";
|
||||
}
|
||||
}
|
||||
@@ -23,12 +23,13 @@
|
||||
*/
|
||||
package org.kohsuke.github;
|
||||
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.*;
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
@@ -38,13 +39,14 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -54,6 +56,12 @@ import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||
/**
|
||||
* Root of the GitHub API.
|
||||
*
|
||||
* <h2>Thread safety</h2>
|
||||
* <p>
|
||||
* This library aims to be safe for use by multiple threads concurrently, although
|
||||
* the library itself makes no attempt to control/serialize potentially conflicting
|
||||
* operations to GitHub, such as updating & deleting a repository at the same time.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class GitHub {
|
||||
@@ -64,19 +72,14 @@ public class GitHub {
|
||||
*/
|
||||
/*package*/ final String encodedAuthorization;
|
||||
|
||||
private final Map<String,GHUser> users = new HashMap<String, GHUser>();
|
||||
private final Map<String,GHOrganization> orgs = new HashMap<String, GHOrganization>();
|
||||
private final Map<String,GHUser> users = new Hashtable<String, GHUser>();
|
||||
private final Map<String,GHOrganization> orgs = new Hashtable<String, GHOrganization>();
|
||||
|
||||
private final String apiUrl;
|
||||
|
||||
private HttpConnector connector = HttpConnector.DEFAULT;
|
||||
/*package*/ final RateLimitHandler rateLimitHandler;
|
||||
|
||||
/**
|
||||
* Connects to GitHub.com
|
||||
*/
|
||||
private GitHub(String login, String oauthAccessToken, String password) throws IOException {
|
||||
this (GITHUB_URL, login, oauthAccessToken, password);
|
||||
}
|
||||
private HttpConnector connector = HttpConnector.DEFAULT;
|
||||
|
||||
/**
|
||||
* Creates a client API root object.
|
||||
@@ -111,10 +114,13 @@ public class GitHub {
|
||||
* Secret OAuth token.
|
||||
* @param password
|
||||
* User's password. Always used in conjunction with the {@code login} parameter
|
||||
* @param connector
|
||||
* HttpConnector to use. Pass null to use default connector.
|
||||
*/
|
||||
private GitHub(String apiUrl, String login, String oauthAccessToken, String password) throws IOException {
|
||||
/* package */ GitHub(String apiUrl, String login, String oauthAccessToken, String password, HttpConnector connector, RateLimitHandler rateLimitHandler) throws IOException {
|
||||
if (apiUrl.endsWith("/")) apiUrl = apiUrl.substring(0, apiUrl.length()-1); // normalize
|
||||
this.apiUrl = apiUrl;
|
||||
if (null != connector) this.connector = connector;
|
||||
|
||||
if (oauthAccessToken!=null) {
|
||||
encodedAuthorization = "token "+oauthAccessToken;
|
||||
@@ -127,24 +133,18 @@ public class GitHub {
|
||||
}
|
||||
}
|
||||
|
||||
this.rateLimitHandler = rateLimitHandler;
|
||||
|
||||
if (login==null && encodedAuthorization!=null)
|
||||
login = getMyself().getLogin();
|
||||
this.login = login;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the credential from "~/.github"
|
||||
* Obtains the credential from "~/.github" or from the System Environment Properties.
|
||||
*/
|
||||
public static GitHub connect() throws IOException {
|
||||
Properties props = new Properties();
|
||||
File homeDir = new File(System.getProperty("user.home"));
|
||||
FileInputStream in = new FileInputStream(new File(homeDir, ".github"));
|
||||
try {
|
||||
props.load(in);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(in);
|
||||
}
|
||||
return new GitHub(GITHUB_URL,props.getProperty("login"), props.getProperty("oauth"),props.getProperty("password"));
|
||||
return GitHubBuilder.fromCredentials().build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,15 +156,15 @@ public class GitHub {
|
||||
* For historical reasons, this parameter still accepts the bare domain name, but that's considered deprecated.
|
||||
*/
|
||||
public static GitHub connectToEnterprise(String apiUrl, String oauthAccessToken) throws IOException {
|
||||
return connectUsingOAuth(apiUrl, oauthAccessToken);
|
||||
return new GitHubBuilder().withEndpoint(apiUrl).withOAuthToken(oauthAccessToken).build();
|
||||
}
|
||||
|
||||
public static GitHub connectToEnterprise(String apiUrl, String login, String password) throws IOException {
|
||||
return new GitHub(apiUrl, login, null, password);
|
||||
return new GitHubBuilder().withEndpoint(apiUrl).withPassword(login, password).build();
|
||||
}
|
||||
|
||||
public static GitHub connect(String login, String oauthAccessToken) throws IOException {
|
||||
return new GitHub(login,oauthAccessToken,null);
|
||||
return new GitHubBuilder().withOAuthToken(oauthAccessToken, login).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,19 +173,19 @@ public class GitHub {
|
||||
* Use {@link #connectUsingPassword(String, String)} or {@link #connectUsingOAuth(String)}.
|
||||
*/
|
||||
public static GitHub connect(String login, String oauthAccessToken, String password) throws IOException {
|
||||
return new GitHub(login,oauthAccessToken,password);
|
||||
return new GitHubBuilder().withOAuthToken(oauthAccessToken, login).withPassword(login, password).build();
|
||||
}
|
||||
|
||||
public static GitHub connectUsingPassword(String login, String password) throws IOException {
|
||||
return new GitHub(login,null,password);
|
||||
return new GitHubBuilder().withPassword(login, password).build();
|
||||
}
|
||||
|
||||
public static GitHub connectUsingOAuth(String oauthAccessToken) throws IOException {
|
||||
return new GitHub(null, oauthAccessToken, null);
|
||||
return new GitHubBuilder().withOAuthToken(oauthAccessToken).build();
|
||||
}
|
||||
|
||||
public static GitHub connectUsingOAuth(String githubServer, String oauthAccessToken) throws IOException {
|
||||
return new GitHub(githubServer,null, oauthAccessToken,null);
|
||||
return new GitHubBuilder().withEndpoint(githubServer).withOAuthToken(oauthAccessToken).build();
|
||||
}
|
||||
/**
|
||||
* Connects to GitHub anonymously.
|
||||
@@ -193,7 +193,7 @@ public class GitHub {
|
||||
* All operations that requires authentication will fail.
|
||||
*/
|
||||
public static GitHub connectAnonymously() throws IOException {
|
||||
return new GitHub(null,null,null);
|
||||
return new GitHubBuilder().build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,11 +253,11 @@ public class GitHub {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link GHUser} that represents yourself.
|
||||
*/
|
||||
* Gets the {@link GHUser} that represents yourself.
|
||||
*/
|
||||
@WithBridgeMethods(GHUser.class)
|
||||
public GHMyself getMyself() throws IOException {
|
||||
requireCredential();
|
||||
public GHMyself getMyself() throws IOException {
|
||||
requireCredential();
|
||||
|
||||
GHMyself u = retrieve().to("/user", GHMyself.class);
|
||||
|
||||
@@ -265,20 +265,29 @@ public class GitHub {
|
||||
users.put(u.getLogin(), u);
|
||||
|
||||
return u;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the object that represents the named user.
|
||||
*/
|
||||
public GHUser getUser(String login) throws IOException {
|
||||
GHUser u = users.get(login);
|
||||
if (u == null) {
|
||||
/**
|
||||
* Obtains the object that represents the named user.
|
||||
*/
|
||||
public GHUser getUser(String login) throws IOException {
|
||||
GHUser u = users.get(login);
|
||||
if (u == null) {
|
||||
u = retrieve().to("/users/" + login, GHUser.class);
|
||||
u.root = this;
|
||||
users.put(u.getLogin(), u);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* clears all cached data in order for external changes (modifications and del
|
||||
*/
|
||||
public void refreshCache() {
|
||||
users.clear();
|
||||
orgs.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Interns the given {@link GHUser}.
|
||||
@@ -287,7 +296,7 @@ public class GitHub {
|
||||
GHUser u = users.get(orig.getLogin());
|
||||
if (u==null) {
|
||||
orig.root = this;
|
||||
users.put(login,orig);
|
||||
users.put(orig.getLogin(),orig);
|
||||
return orig;
|
||||
}
|
||||
return u;
|
||||
@@ -328,11 +337,32 @@ public class GitHub {
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets complete map of organizations/teams that current user belongs to.
|
||||
*
|
||||
* Leverages the new GitHub API /user/teams made available recently to
|
||||
* get in a single call the complete set of organizations, teams and permissions
|
||||
* in a single call.
|
||||
*/
|
||||
public Map<String, Set<GHTeam>> getMyTeams() throws IOException {
|
||||
Map<String, Set<GHTeam>> allMyTeams = new HashMap<String, Set<GHTeam>>();
|
||||
for (GHTeam team : retrieve().to("/user/teams", GHTeam[].class)) {
|
||||
team.wrapUp(this);
|
||||
String orgLogin = team.getOrganization().getLogin();
|
||||
Set<GHTeam> teamsPerOrg = allMyTeams.get(orgLogin);
|
||||
if (teamsPerOrg == null) {
|
||||
teamsPerOrg = new HashSet<GHTeam>();
|
||||
}
|
||||
teamsPerOrg.add(team);
|
||||
allMyTeams.put(orgLogin, teamsPerOrg);
|
||||
}
|
||||
return allMyTeams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public events visible to you. Equivalent of what's displayed on https://github.com/
|
||||
*/
|
||||
public List<GHEventInfo> getEvents() throws IOException {
|
||||
// TODO: pagination
|
||||
GHEventInfo[] events = retrieve().to("/events", GHEventInfo[].class);
|
||||
for (GHEventInfo e : events)
|
||||
e.wrapUp(this);
|
||||
@@ -386,14 +416,14 @@ public class GitHub {
|
||||
*
|
||||
* @see <a href="http://developer.github.com/v3/oauth/#create-a-new-authorization">Documentation</a>
|
||||
*/
|
||||
public GHAuthorization createToken(Collection<String> scope, String note, String noteUrl) throws IOException{
|
||||
Requester requester = new Requester(this)
|
||||
.with("scopes", scope)
|
||||
.with("note", note)
|
||||
.with("note_url", noteUrl);
|
||||
public GHAuthorization createToken(Collection<String> scope, String note, String noteUrl) throws IOException{
|
||||
Requester requester = new Requester(this)
|
||||
.with("scopes", scope)
|
||||
.with("note", note)
|
||||
.with("note_url", noteUrl);
|
||||
|
||||
return requester.method("POST").to("/authorizations", GHAuthorization.class).wrap(this);
|
||||
}
|
||||
return requester.method("POST").to("/authorizations", GHAuthorization.class).wrap(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the credential is valid.
|
||||
@@ -407,6 +437,89 @@ public class GitHub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search issues.
|
||||
*/
|
||||
public GHIssueSearchBuilder searchIssues() {
|
||||
return new GHIssueSearchBuilder(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search users.
|
||||
*/
|
||||
public GHUserSearchBuilder searchUsers() {
|
||||
return new GHUserSearchBuilder(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search repositories.
|
||||
*/
|
||||
public GHRepositorySearchBuilder searchRepositories() {
|
||||
return new GHRepositorySearchBuilder(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search content.
|
||||
*/
|
||||
public GHContentSearchBuilder searchContent() {
|
||||
return new GHContentSearchBuilder(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* List all the notifications.
|
||||
*/
|
||||
public GHNotificationStream listNotifications() {
|
||||
return new GHNotificationStream(this,"/notifications");
|
||||
}
|
||||
|
||||
/**
|
||||
* This provides a dump of every public repository, in the order that they were created.
|
||||
* @see <a href="https://developer.github.com/v3/repos/#list-all-public-repositories">documentation</a>
|
||||
*/
|
||||
public PagedIterable<GHRepository> listAllPublicRepositories() {
|
||||
return listAllPublicRepositories(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This provides a dump of every public repository, in the order that they were created.
|
||||
*
|
||||
* @param since
|
||||
* The integer ID of the last Repository that you’ve seen. See {@link GHRepository#getId()}
|
||||
* @see <a href="https://developer.github.com/v3/repos/#list-all-public-repositories">documentation</a>
|
||||
*/
|
||||
public PagedIterable<GHRepository> listAllPublicRepositories(final String since) {
|
||||
return new PagedIterable<GHRepository>() {
|
||||
public PagedIterator<GHRepository> iterator() {
|
||||
return new PagedIterator<GHRepository>(retrieve().with("since",since).asIterator("/repositories", GHRepository[].class)) {
|
||||
@Override
|
||||
protected void wrapUp(GHRepository[] page) {
|
||||
for (GHRepository c : page)
|
||||
c.wrap(GitHub.this);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Markdown document in raw mode.
|
||||
*
|
||||
* <p>
|
||||
* It takes a Markdown document as plaintext and renders it as plain Markdown
|
||||
* without a repository context (just like a README.md file is rendered – this
|
||||
* is the simplest way to preview a readme online).
|
||||
*
|
||||
* @see GHRepository#renderMarkdown(String, MarkdownMode)
|
||||
*/
|
||||
public Reader renderMarkdown(String text) throws IOException {
|
||||
return new InputStreamReader(
|
||||
new Requester(this)
|
||||
.with(new ByteArrayInputStream(text.getBytes("UTF-8")))
|
||||
.contentType("text/plain;charset=UTF-8")
|
||||
.asStream("/markdown/raw"),
|
||||
"UTF-8");
|
||||
}
|
||||
|
||||
/*package*/ static URL parseURL(String s) {
|
||||
try {
|
||||
return s==null ? null : new URL(s);
|
||||
@@ -442,5 +555,5 @@ public class GitHub {
|
||||
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
}
|
||||
|
||||
private static final String GITHUB_URL = "https://api.github.com";
|
||||
/* package */ static final String GITHUB_URL = "https://api.github.com";
|
||||
}
|
||||
|
||||
197
src/main/java/org/kohsuke/github/GitHubBuilder.java
Normal file
197
src/main/java/org/kohsuke/github/GitHubBuilder.java
Normal file
@@ -0,0 +1,197 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.util.Locale;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @since 1.59
|
||||
*/
|
||||
public class GitHubBuilder {
|
||||
|
||||
// default scoped so unit tests can read them.
|
||||
/* private */ String endpoint = GitHub.GITHUB_URL;
|
||||
/* private */ String user;
|
||||
/* private */ String password;
|
||||
/* private */ String oauthToken;
|
||||
|
||||
private HttpConnector connector;
|
||||
|
||||
private RateLimitHandler rateLimitHandler = RateLimitHandler.WAIT;
|
||||
|
||||
public GitHubBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* First check if the credentials are configured using the ~/.github properties file.
|
||||
*
|
||||
* If no user is specified it means there is no configuration present so check the environment instead.
|
||||
*
|
||||
* If there is still no user it means there are no credentials defined and throw an IOException.
|
||||
*
|
||||
* @return the configured Builder from credentials defined on the system or in the environment.
|
||||
*
|
||||
* @throws IOException If there are no credentials defined in the ~/.github properties file or the process environment.
|
||||
*/
|
||||
public static GitHubBuilder fromCredentials() throws IOException {
|
||||
Exception cause = null;
|
||||
GitHubBuilder builder;
|
||||
|
||||
try {
|
||||
builder = fromPropertyFile();
|
||||
|
||||
if (builder.user != null)
|
||||
return builder;
|
||||
} catch (FileNotFoundException e) {
|
||||
// fall through
|
||||
cause = e;
|
||||
}
|
||||
|
||||
builder = fromEnvironment();
|
||||
|
||||
if (builder.user != null)
|
||||
return builder;
|
||||
else
|
||||
throw (IOException)new IOException("Failed to resolve credentials from ~/.github or the environment.").initCause(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Use {@link #fromEnvironment()} to pick up standard set of environment variables, so that
|
||||
* different clients of this library will all recognize one consistent set of coordinates.
|
||||
*/
|
||||
public static GitHubBuilder fromEnvironment(String loginVariableName, String passwordVariableName, String oauthVariableName) throws IOException {
|
||||
return fromEnvironment(loginVariableName, passwordVariableName, oauthVariableName, "");
|
||||
}
|
||||
|
||||
private static void loadIfSet(String envName, Properties p, String propName) {
|
||||
String v = System.getenv(envName);
|
||||
if (v != null)
|
||||
p.put(propName, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Use {@link #fromEnvironment()} to pick up standard set of environment variables, so that
|
||||
* different clients of this library will all recognize one consistent set of coordinates.
|
||||
*/
|
||||
public static GitHubBuilder fromEnvironment(String loginVariableName, String passwordVariableName, String oauthVariableName, String endpointVariableName) throws IOException {
|
||||
Properties env = new Properties();
|
||||
loadIfSet(loginVariableName,env,"login");
|
||||
loadIfSet(passwordVariableName,env,"password");
|
||||
loadIfSet(oauthVariableName,env,"oauth");
|
||||
loadIfSet(endpointVariableName,env,"endpoint");
|
||||
return fromProperties(env);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link GitHubBuilder} by picking up coordinates from environment variables.
|
||||
*
|
||||
* <p>
|
||||
* The following environment variables are recognized:
|
||||
*
|
||||
* <ul>
|
||||
* <li>GITHUB_LOGIN: username like 'kohsuke'
|
||||
* <li>GITHUB_PASSWORD: raw password
|
||||
* <li>GITHUB_OAUTH: OAuth token to login
|
||||
* <li>GITHUB_ENDPOINT: URL of the API endpoint
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* See class javadoc for the relationship between these coordinates.
|
||||
*
|
||||
* <p>
|
||||
* For backward compatibility, the following environment variables are recognized but discouraged:
|
||||
* login, password, oauth
|
||||
*/
|
||||
public static GitHubBuilder fromEnvironment() throws IOException {
|
||||
Properties props = new Properties();
|
||||
for (Entry<String, String> e : System.getenv().entrySet()) {
|
||||
String name = e.getKey().toLowerCase(Locale.ENGLISH);
|
||||
if (name.startsWith("github_")) name=name.substring(7);
|
||||
props.put(name,e.getValue());
|
||||
}
|
||||
return fromProperties(props);
|
||||
}
|
||||
|
||||
public static GitHubBuilder fromPropertyFile() throws IOException {
|
||||
File homeDir = new File(System.getProperty("user.home"));
|
||||
File propertyFile = new File(homeDir, ".github");
|
||||
return fromPropertyFile(propertyFile.getPath());
|
||||
}
|
||||
|
||||
public static GitHubBuilder fromPropertyFile(String propertyFileName) throws IOException {
|
||||
Properties props = new Properties();
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(propertyFileName);
|
||||
props.load(in);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(in);
|
||||
}
|
||||
|
||||
return fromProperties(props);
|
||||
}
|
||||
|
||||
public static GitHubBuilder fromProperties(Properties props) {
|
||||
GitHubBuilder self = new GitHubBuilder();
|
||||
self.withOAuthToken(props.getProperty("oauth"), props.getProperty("login"));
|
||||
self.withPassword(props.getProperty("login"), props.getProperty("password"));
|
||||
self.withEndpoint(props.getProperty("endpoint", GitHub.GITHUB_URL));
|
||||
return self;
|
||||
}
|
||||
|
||||
public GitHubBuilder withEndpoint(String endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
return this;
|
||||
}
|
||||
public GitHubBuilder withPassword(String user, String password) {
|
||||
this.user = user;
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
public GitHubBuilder withOAuthToken(String oauthToken) {
|
||||
return withOAuthToken(oauthToken, null);
|
||||
}
|
||||
public GitHubBuilder withOAuthToken(String oauthToken, String user) {
|
||||
this.oauthToken = oauthToken;
|
||||
this.user = user;
|
||||
return this;
|
||||
}
|
||||
public GitHubBuilder withConnector(HttpConnector connector) {
|
||||
this.connector = connector;
|
||||
return this;
|
||||
}
|
||||
public GitHubBuilder withRateLimitHandler(RateLimitHandler handler) {
|
||||
this.rateLimitHandler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures {@linkplain #withConnector(HttpConnector) connector}
|
||||
* that uses HTTP library in JRE but use a specific proxy, instead of
|
||||
* the system default one.
|
||||
*/
|
||||
public GitHubBuilder withProxy(final Proxy p) {
|
||||
return withConnector(new HttpConnector() {
|
||||
public HttpURLConnection connect(URL url) throws IOException {
|
||||
return (HttpURLConnection) url.openConnection(p);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public GitHub build() throws IOException {
|
||||
return new GitHub(endpoint, user, oauthToken, password, connector, rateLimitHandler);
|
||||
}
|
||||
}
|
||||
29
src/main/java/org/kohsuke/github/MarkdownMode.java
Normal file
29
src/main/java/org/kohsuke/github/MarkdownMode.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Rendering mode of markdown.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GitHub#renderMarkdown(String)
|
||||
* @see GHRepository#renderMarkdown(String, MarkdownMode)
|
||||
*/
|
||||
public enum MarkdownMode {
|
||||
/**
|
||||
* Render a document as plain Markdown, just like README files are rendered.
|
||||
*/
|
||||
MARKDOWN,
|
||||
/**
|
||||
* Render a document as user-content, e.g. like user comments or issues are rendered.
|
||||
* In GFM mode, hard line breaks are always taken into account, and issue and user
|
||||
* mentions are linked accordingly.
|
||||
*
|
||||
* @see GHRepository#renderMarkdown(String, MarkdownMode)
|
||||
*/
|
||||
GFM;
|
||||
|
||||
public String toString() {
|
||||
return name().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* {@link Iterable} that returns {@link PagedIterator}
|
||||
@@ -21,4 +23,15 @@ public abstract class PagedIterable<T> implements Iterable<T> {
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly walk {@link Iterable} and return the result in a set.
|
||||
*/
|
||||
public Set<T> asSet() {
|
||||
LinkedHashSet<T> r = new LinkedHashSet<T>();
|
||||
for(PagedIterator<T> i = iterator(); i.hasNext();) {
|
||||
r.addAll(i.nextPage());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
60
src/main/java/org/kohsuke/github/PagedSearchIterable.java
Normal file
60
src/main/java/org/kohsuke/github/PagedSearchIterable.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* {@link PagedIterable} enhanced to report search result specific information.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public abstract class PagedSearchIterable<T> extends PagedIterable<T> {
|
||||
private final GitHub root;
|
||||
|
||||
/**
|
||||
* As soon as we have any result fetched, it's set here so that we can report the total count.
|
||||
*/
|
||||
private SearchResult<T> result;
|
||||
|
||||
/*package*/ PagedSearchIterable(GitHub root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of hit, including the results that's not yet fetched.
|
||||
*/
|
||||
public int getTotalCount() {
|
||||
populate();
|
||||
return result.total_count;
|
||||
}
|
||||
|
||||
public boolean isIncomplete() {
|
||||
populate();
|
||||
return result.incomplete_results;
|
||||
}
|
||||
|
||||
private void populate() {
|
||||
if (result==null)
|
||||
iterator().hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts {@link Iterator}.
|
||||
*/
|
||||
protected Iterator<T[]> adapt(final Iterator<? extends SearchResult<T>> base) {
|
||||
return new Iterator<T[]>() {
|
||||
public boolean hasNext() {
|
||||
return base.hasNext();
|
||||
}
|
||||
|
||||
public T[] next() {
|
||||
SearchResult<T> v = base.next();
|
||||
if (result==null) result = v;
|
||||
return v.getItems(root);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
61
src/main/java/org/kohsuke/github/RateLimitHandler.java
Normal file
61
src/main/java/org/kohsuke/github/RateLimitHandler.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
/**
|
||||
* Pluggable strategy to determine what to do when the API rate limit is reached.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GitHubBuilder#withRateLimitHandler(RateLimitHandler)
|
||||
*/
|
||||
public abstract class RateLimitHandler {
|
||||
/**
|
||||
* Called when the library encounters HTTP error indicating that the API rate limit is reached.
|
||||
*
|
||||
* <p>
|
||||
* Any exception thrown from this method will cause the request to fail, and the caller of github-api
|
||||
* will receive an exception. If this method returns normally, another request will be attempted.
|
||||
* For that to make sense, the implementation needs to wait for some time.
|
||||
*
|
||||
* @see <a href="https://developer.github.com/v3/#rate-limiting">API documentation from GitHub</a>
|
||||
* @param e
|
||||
* Exception from Java I/O layer. If you decide to fail the processing, you can throw
|
||||
* this exception (or wrap this exception into another exception and throw it.)
|
||||
* @param uc
|
||||
* Connection that resulted in an error. Useful for accessing other response headers.
|
||||
*/
|
||||
public abstract void onError(IOException e, HttpURLConnection uc) throws IOException;
|
||||
|
||||
/**
|
||||
* Block until the API rate limit is reset. Useful for long-running batch processing.
|
||||
*/
|
||||
public static final RateLimitHandler WAIT = new RateLimitHandler() {
|
||||
@Override
|
||||
public void onError(IOException e, HttpURLConnection uc) throws IOException {
|
||||
try {
|
||||
Thread.sleep(parseWaitTime(uc));
|
||||
} catch (InterruptedException _) {
|
||||
throw (InterruptedIOException)new InterruptedIOException().initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
private long parseWaitTime(HttpURLConnection uc) {
|
||||
String v = uc.getHeaderField("X-RateLimit-Reset");
|
||||
if (v==null) return 10000; // can't tell
|
||||
|
||||
return Math.max(10000, Long.parseLong(v)*1000 - System.currentTimeMillis());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Fail immediately.
|
||||
*/
|
||||
public static final RateLimitHandler FAIL = new RateLimitHandler() {
|
||||
@Override
|
||||
public void onError(IOException e, HttpURLConnection uc) throws IOException {
|
||||
throw (IOException)new IOException("API rate limit reached").initCause(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -23,15 +23,16 @@
|
||||
*/
|
||||
package org.kohsuke.github;
|
||||
|
||||
import static org.kohsuke.github.GitHub.MAPPER;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
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.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
@@ -43,13 +44,16 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import static org.kohsuke.github.GitHub.*;
|
||||
|
||||
/**
|
||||
* A builder pattern for making HTTP call and parsing its output.
|
||||
@@ -59,6 +63,7 @@ import org.apache.commons.io.IOUtils;
|
||||
class Requester {
|
||||
private final GitHub root;
|
||||
private final List<Entry> args = new ArrayList<Entry>();
|
||||
private final Map<String,String> headers = new LinkedHashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Request method.
|
||||
@@ -67,6 +72,11 @@ class Requester {
|
||||
private String contentType = "application/x-www-form-urlencoded";
|
||||
private InputStream body;
|
||||
|
||||
/**
|
||||
* Current connection.
|
||||
*/
|
||||
private HttpURLConnection uc;
|
||||
|
||||
private static class Entry {
|
||||
String key;
|
||||
Object value;
|
||||
@@ -81,6 +91,15 @@ class Requester {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the request HTTP header.
|
||||
*
|
||||
* If a header of the same name is already set, this method overrides it.
|
||||
*/
|
||||
public void setHeader(String name, String value) {
|
||||
headers.put(name,value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request with authentication credential.
|
||||
*/
|
||||
@@ -104,6 +123,10 @@ class Requester {
|
||||
public Requester with(String key, boolean value) {
|
||||
return _with(key, value);
|
||||
}
|
||||
public Requester with(String key, Boolean value) {
|
||||
return _with(key, value);
|
||||
}
|
||||
|
||||
|
||||
public Requester with(String key, String value) {
|
||||
return _with(key, value);
|
||||
@@ -129,6 +152,19 @@ class Requester {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike {@link #with(String, String)}, overrides the existing value
|
||||
*/
|
||||
public Requester set(String key, Object value) {
|
||||
for (Entry e : args) {
|
||||
if (e.key.equals(key)) {
|
||||
e.value = value;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
return _with(key,value);
|
||||
}
|
||||
|
||||
public Requester method(String method) {
|
||||
this.method = method;
|
||||
return this;
|
||||
@@ -172,14 +208,41 @@ class Requester {
|
||||
|
||||
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") && !args.isEmpty()) {
|
||||
StringBuilder qs=new StringBuilder();
|
||||
for (Entry arg : args) {
|
||||
qs.append(qs.length()==0 ? '?' : '&');
|
||||
qs.append(arg.key).append('=').append(URLEncoder.encode(arg.value.toString(),"UTF-8"));
|
||||
}
|
||||
tailApiUrl += qs.toString();
|
||||
}
|
||||
setupConnection(root.getApiURL(tailApiUrl));
|
||||
|
||||
buildRequest(uc);
|
||||
buildRequest();
|
||||
|
||||
try {
|
||||
return parse(uc,type,instance);
|
||||
T result = parse(type, instance);
|
||||
if (type != null && type.isArray()) { // we might have to loop for pagination - done through recursion
|
||||
final String links = uc.getHeaderField("link");
|
||||
if (links != null && links.contains("rel=\"next\"")) {
|
||||
Pattern nextLinkPattern = Pattern.compile(".*<(.*)>; rel=\"next\"");
|
||||
Matcher nextLinkMatcher = nextLinkPattern.matcher(links);
|
||||
if (nextLinkMatcher.find()) {
|
||||
final String link = nextLinkMatcher.group(1);
|
||||
T nextResult = _to(link, type, instance);
|
||||
|
||||
final int resultLength = Array.getLength(result);
|
||||
final int nextResultLength = Array.getLength(nextResult);
|
||||
T concatResult = (T) Array.newInstance(type.getComponentType(), resultLength + nextResultLength);
|
||||
System.arraycopy(result, 0, concatResult, 0, resultLength);
|
||||
System.arraycopy(nextResult, 0, concatResult, resultLength, nextResultLength);
|
||||
result = concatResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
handleApiError(e,uc);
|
||||
handleApiError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -189,19 +252,41 @@ class Requester {
|
||||
*/
|
||||
public int asHttpStatusCode(String tailApiUrl) throws IOException {
|
||||
while (true) {// loop while API rate limit is hit
|
||||
HttpURLConnection uc = setupConnection(root.getApiURL(tailApiUrl));
|
||||
setupConnection(root.getApiURL(tailApiUrl));
|
||||
|
||||
buildRequest(uc);
|
||||
buildRequest();
|
||||
|
||||
try {
|
||||
return uc.getResponseCode();
|
||||
} catch (IOException e) {
|
||||
handleApiError(e,uc);
|
||||
handleApiError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildRequest(HttpURLConnection uc) throws IOException {
|
||||
public InputStream asStream(String tailApiUrl) throws IOException {
|
||||
while (true) {// loop while API rate limit is hit
|
||||
setupConnection(root.getApiURL(tailApiUrl));
|
||||
|
||||
buildRequest();
|
||||
|
||||
try {
|
||||
return wrapStream(uc.getInputStream());
|
||||
} catch (IOException e) {
|
||||
handleApiError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getResponseHeader(String header) {
|
||||
return uc.getHeaderField(header);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set up the request parameters or POST payload.
|
||||
*/
|
||||
private void buildRequest() throws IOException {
|
||||
if (!method.equals("GET")) {
|
||||
uc.setDoOutput(true);
|
||||
uc.setRequestProperty("Content-type", contentType);
|
||||
@@ -290,14 +375,14 @@ class Requester {
|
||||
|
||||
try {
|
||||
while (true) {// loop while API rate limit is hit
|
||||
HttpURLConnection uc = setupConnection(url);
|
||||
setupConnection(url);
|
||||
try {
|
||||
next = parse(uc,type,null);
|
||||
next = parse(type,null);
|
||||
assert next!=null;
|
||||
findNextURL(uc);
|
||||
findNextURL();
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
handleApiError(e,uc);
|
||||
handleApiError(e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -308,7 +393,7 @@ class Requester {
|
||||
/**
|
||||
* Locate the next page from the pagination "Link" tag.
|
||||
*/
|
||||
private void findNextURL(HttpURLConnection uc) throws MalformedURLException {
|
||||
private void findNextURL() throws MalformedURLException {
|
||||
url = null; // start defensively
|
||||
String link = uc.getHeaderField("Link");
|
||||
if (link==null) return;
|
||||
@@ -329,14 +414,20 @@ class Requester {
|
||||
}
|
||||
|
||||
|
||||
private HttpURLConnection setupConnection(URL url) throws IOException {
|
||||
HttpURLConnection uc = root.getConnector().connect(url);
|
||||
private void setupConnection(URL url) throws IOException {
|
||||
uc = root.getConnector().connect(url);
|
||||
|
||||
// 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 (root.encodedAuthorization!=null)
|
||||
uc.setRequestProperty("Authorization", root.encodedAuthorization);
|
||||
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
String v = e.getValue();
|
||||
if (v!=null)
|
||||
uc.setRequestProperty(e.getKey(), v);
|
||||
}
|
||||
|
||||
try {
|
||||
uc.setRequestMethod(method);
|
||||
} catch (ProtocolException e) {
|
||||
@@ -350,16 +441,21 @@ class Requester {
|
||||
}
|
||||
}
|
||||
uc.setRequestProperty("Accept-Encoding", "gzip");
|
||||
return uc;
|
||||
}
|
||||
|
||||
private <T> T parse(HttpURLConnection uc, Class<T> type, T instance) throws IOException {
|
||||
private <T> T parse(Class<T> type, T instance) throws IOException {
|
||||
if (uc.getResponseCode()==304)
|
||||
return null; // special case handling for 304 unmodified, as the content will be ""
|
||||
InputStreamReader r = null;
|
||||
try {
|
||||
r = new InputStreamReader(wrapStream(uc, uc.getInputStream()), "UTF-8");
|
||||
r = new InputStreamReader(wrapStream(uc.getInputStream()), "UTF-8");
|
||||
String data = IOUtils.toString(r);
|
||||
if (type!=null)
|
||||
return MAPPER.readValue(data,type);
|
||||
try {
|
||||
return MAPPER.readValue(data,type);
|
||||
} catch (JsonMappingException e) {
|
||||
throw (IOException)new IOException("Failed to deserialize "+data).initCause(e);
|
||||
}
|
||||
if (instance!=null)
|
||||
return MAPPER.readerForUpdating(instance).<T>readValue(data);
|
||||
return null;
|
||||
@@ -371,7 +467,7 @@ class Requester {
|
||||
/**
|
||||
* Handles the "Content-Encoding" header.
|
||||
*/
|
||||
private InputStream wrapStream(HttpURLConnection uc, InputStream in) throws IOException {
|
||||
private InputStream wrapStream(InputStream in) throws IOException {
|
||||
String encoding = uc.getContentEncoding();
|
||||
if (encoding==null || in==null) return in;
|
||||
if (encoding.equals("gzip")) return new GZIPInputStream(in);
|
||||
@@ -380,28 +476,25 @@ class Requester {
|
||||
}
|
||||
|
||||
/**
|
||||
* If the error is because of the API limit, wait 10 sec and return normally.
|
||||
* Otherwise throw an exception reporting an error.
|
||||
* Handle API error by either throwing it or by returning normally to retry.
|
||||
*/
|
||||
/*package*/ void handleApiError(IOException e, HttpURLConnection uc) throws IOException {
|
||||
/*package*/ void handleApiError(IOException e) throws IOException {
|
||||
if (uc.getResponseCode() == 401) // Unauthorized == bad creds
|
||||
throw e;
|
||||
|
||||
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);
|
||||
}
|
||||
root.rateLimitHandler.onError(e,uc);
|
||||
}
|
||||
|
||||
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());
|
||||
InputStream es = wrapStream(uc.getErrorStream());
|
||||
try {
|
||||
if (es!=null)
|
||||
throw (IOException)new IOException(IOUtils.toString(es,"UTF-8")).initCause(e);
|
||||
else
|
||||
if (es!=null) {
|
||||
if (e instanceof FileNotFoundException) {
|
||||
// pass through 404 Not Found to allow the caller to handle it intelligently
|
||||
throw (IOException) new FileNotFoundException(IOUtils.toString(es, "UTF-8")).initCause(e);
|
||||
} else
|
||||
throw (IOException) new IOException(IOUtils.toString(es, "UTF-8")).initCause(e);
|
||||
} else
|
||||
throw e;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(es);
|
||||
|
||||
16
src/main/java/org/kohsuke/github/SearchResult.java
Normal file
16
src/main/java/org/kohsuke/github/SearchResult.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
/**
|
||||
* Represents the result of a search
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
abstract class SearchResult<T> {
|
||||
int total_count;
|
||||
boolean incomplete_results;
|
||||
|
||||
/**
|
||||
* Wraps up the retrieved object and return them. Only called once.
|
||||
*/
|
||||
/*package*/ abstract T[] getItems(GitHub root);
|
||||
}
|
||||
@@ -9,8 +9,7 @@ are used in favor of using string handle (such as `GHUser.isMemberOf(GHOrganizat
|
||||
|
||||
The library supports both github.com and GitHub Enterprise.
|
||||
|
||||
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.
|
||||
Most of the GitHub APIs are covered, although there are some corners that are still not yet implemented.
|
||||
|
||||
Sample Usage
|
||||
-----
|
||||
@@ -42,4 +41,11 @@ This library comes with a pluggable connector to use different HTTP client imple
|
||||
through `HttpConnector`. In particular, this means you can use [OkHttp](http://square.github.io/okhttp/),
|
||||
so we can make use of it's HTTP response cache.
|
||||
Making a conditional request against the GitHub API and receiving a 304 response
|
||||
[does not count against the rate limit](http://developer.github.com/v3/#conditional-requests).
|
||||
[does not count against the rate limit](http://developer.github.com/v3/#conditional-requests).
|
||||
|
||||
The following code shows an example of how to set up persistent cache on the disk:
|
||||
|
||||
Cache cache = new Cache(cacheDirectory, 10 * 1024 * 1024); // 10MB cache
|
||||
GitHub gitHub = GitHubBuilder.fromCredentials()
|
||||
.withConnector(new OkHttpConnector(new OkUrlFactory(new OkHttpClient().setCache(cache))))
|
||||
.build();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<item name="Introduction" href="/index.html"/>
|
||||
<item name="Download" href="http://mvnrepository.com/artifact/${project.groupId}/${project.artifactId}"/>
|
||||
<item name="Source code" href="https://github.com/kohsuke/${project.artifactId}"/>
|
||||
<item name="Mailing List" href="https://groups.google.com/forum/#!forum/github-api"/>
|
||||
</menu>
|
||||
|
||||
<menu name="References">
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
import org.kohsuke.github.GHOrganization;
|
||||
import org.kohsuke.github.GHTeam;
|
||||
import org.kohsuke.github.GHRepository;
|
||||
import org.kohsuke.github.GitHub;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class Foo {
|
||||
public static void main(String[] args) throws Exception {
|
||||
GHOrganization org = GitHub.connect().getOrganization("jenkinsci");
|
||||
Map<String, GHTeam> teams = org.getTeams();
|
||||
System.out.println(teams.size());
|
||||
|
||||
int sz = 0;
|
||||
for (GHTeam t : org.listTeams()) {
|
||||
sz++;
|
||||
Collection<GHRepository> lst = GitHub.connect().getUser("kohsuke").getRepositories().values();
|
||||
for (GHRepository r : lst) {
|
||||
System.out.println(r.getName());
|
||||
}
|
||||
System.out.println(sz);
|
||||
System.out.println(lst.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.kohsuke.randname.RandomNameGenerator;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.util.Properties;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
@@ -17,18 +15,13 @@ public abstract class AbstractGitHubApiTestBase extends Assert {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Properties props = new Properties();
|
||||
java.io.File f = new java.io.File(System.getProperty("user.home"), ".github.kohsuke2");
|
||||
File f = new File(System.getProperty("user.home"), ".github.kohsuke2");
|
||||
if (f.exists()) {
|
||||
FileInputStream in = new FileInputStream(f);
|
||||
try {
|
||||
props.load(in);
|
||||
gitHub = GitHub.connect(props.getProperty("login"),props.getProperty("oauth"));
|
||||
} finally {
|
||||
IOUtils.closeQuietly(in);
|
||||
}
|
||||
// use the non-standard credential preferentially, so that developers of this library do not have
|
||||
// to clutter their event stream.
|
||||
gitHub = GitHubBuilder.fromPropertyFile(f.getPath()).withRateLimitHandler(RateLimitHandler.FAIL).build();
|
||||
} else {
|
||||
gitHub = GitHub.connect();
|
||||
gitHub = GitHubBuilder.fromCredentials().withRateLimitHandler(RateLimitHandler.FAIL).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
316
src/test/java/org/kohsuke/github/AppTest.java
Normal file → Executable file
316
src/test/java/org/kohsuke/github/AppTest.java
Normal file → Executable file
@@ -1,30 +1,20 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
import org.kohsuke.github.GHCommit.File;
|
||||
import org.kohsuke.github.GHOrganization.Permission;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import java.util.Date;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Unit test for simple App.
|
||||
@@ -90,6 +80,51 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
o.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateDeployment() throws IOException {
|
||||
GHRepository repository = getTestRepository();
|
||||
GHDeployment deployment = repository.createDeployment("master")
|
||||
.payload("{\"user\":\"atmos\",\"room_id\":123456}")
|
||||
.description("question")
|
||||
.create();
|
||||
assertNotNull(deployment.getCreator());
|
||||
assertNotNull(deployment.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListDeployments() throws IOException {
|
||||
GHRepository repository = getTestRepository();
|
||||
GHDeployment deployment = repository.createDeployment("master")
|
||||
.payload("{\"user\":\"atmos\",\"room_id\":123456}")
|
||||
.description("question")
|
||||
.environment("unittest")
|
||||
.create();
|
||||
assertNotNull(deployment.getCreator());
|
||||
assertNotNull(deployment.getId());
|
||||
ArrayList<GHDeployment> deployments = Lists.newArrayList(repository.listDeployments(null, "master", null, "unittest"));
|
||||
assertNotNull(deployments);
|
||||
assertFalse(Iterables.isEmpty(deployments));
|
||||
GHDeployment unitTestDeployment = deployments.get(0);
|
||||
assertEquals("unittest",unitTestDeployment.getEnvironment());
|
||||
assertEquals("master", unitTestDeployment.getRef());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDeploymentStatuses() throws IOException {
|
||||
GHRepository repository = getTestRepository();
|
||||
GHDeployment deployment = repository.createDeployment("master")
|
||||
.description("question")
|
||||
.payload("{\"user\":\"atmos\",\"room_id\":123456}")
|
||||
.create();
|
||||
GHDeploymentStatus ghDeploymentStatus = repository.createDeployStatus(deployment.getId(), GHDeploymentState.SUCCESS)
|
||||
.description("success")
|
||||
.targetUrl("http://www.github.com").create();
|
||||
Iterable<GHDeploymentStatus> deploymentStatuses = repository.getDeploymentStatuses(deployment.getId());
|
||||
assertNotNull(deploymentStatuses);
|
||||
assertEquals(1,Iterables.size(deploymentStatuses));
|
||||
assertEquals(ghDeploymentStatus.getId(), Iterables.get(deploymentStatuses, 0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIssues() throws Exception {
|
||||
List<GHIssue> closedIssues = gitHub.getUser("kohsuke").getRepository("github-api").getIssues(GHIssueState.CLOSED);
|
||||
@@ -170,6 +205,35 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
System.out.println(org);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMyTeamsContainsAllMyOrganizations() throws IOException {
|
||||
Map<String, Set<GHTeam>> teams = gitHub.getMyTeams();
|
||||
Map<String, GHOrganization> myOrganizations = gitHub.getMyOrganizations();
|
||||
assertEquals(teams.keySet(), myOrganizations.keySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMyTeamsShouldIncludeMyself() throws IOException {
|
||||
Map<String, Set<GHTeam>> teams = gitHub.getMyTeams();
|
||||
for (Entry<String, Set<GHTeam>> teamsPerOrg : teams.entrySet()) {
|
||||
String organizationName = teamsPerOrg.getKey();
|
||||
for (GHTeam team : teamsPerOrg.getValue()) {
|
||||
String teamName = team.getName();
|
||||
assertTrue("Team " + teamName + " in organization " + organizationName
|
||||
+ " does not contain myself",
|
||||
shouldBelongToTeam(organizationName, teamName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldBelongToTeam(String organizationName, String teamName) throws IOException {
|
||||
GHOrganization org = gitHub.getOrganization(organizationName);
|
||||
assertNotNull(org);
|
||||
GHTeam team = org.getTeamByName(teamName);
|
||||
assertNotNull(team);
|
||||
return team.hasMember(gitHub.getMyself());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFetchPullRequest() throws Exception {
|
||||
GHRepository r = gitHub.getOrganization("jenkinsci").getRepository("jenkins");
|
||||
@@ -222,7 +286,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
@Test
|
||||
public void testGetTeamsForRepo() throws Exception {
|
||||
kohsuke();
|
||||
assertEquals(1,gitHub.getOrganization("github-api-test-org").getRepository("testGetTeamsForRepo").getTeams().size());
|
||||
assertEquals(1, gitHub.getOrganization("github-api-test-org").getRepository("testGetTeamsForRepo").getTeams().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -245,7 +309,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
assertNotNull(t.getName());
|
||||
sz++;
|
||||
}
|
||||
assertTrue(sz<100);
|
||||
assertTrue(sz < 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -437,7 +501,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
long start = System.currentTimeMillis();
|
||||
Map<String, GHRepository> repos = j.getRepositories();
|
||||
long end = System.currentTimeMillis();
|
||||
System.out.printf("%d repositories in %dms\n",repos.size(),end-start);
|
||||
System.out.printf("%d repositories in %dms\n", repos.size(), end - start);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -463,7 +527,7 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
state = lst.get(0);
|
||||
System.out.println(state);
|
||||
assertEquals("testing!",state.getDescription());
|
||||
assertEquals("http://kohsuke.org/",state.getTargetUrl());
|
||||
assertEquals("http://kohsuke.org/", state.getTargetUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -534,10 +598,10 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRef() throws IOException {
|
||||
GHRef masterRef = gitHub.getRepository("jenkinsci/jenkins").getRef("heads/master");
|
||||
assertEquals("https://api.github.com/repos/jenkinsci/jenkins/git/refs/heads/master", masterRef.getUrl().toString());
|
||||
}
|
||||
public void testRef() throws IOException {
|
||||
GHRef masterRef = gitHub.getRepository("jenkinsci/jenkins").getRef("heads/master");
|
||||
assertEquals("https://api.github.com/repos/jenkinsci/jenkins/git/refs/heads/master", masterRef.getUrl().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void directoryListing() throws IOException {
|
||||
@@ -554,8 +618,8 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
|
||||
@Test
|
||||
public void testAddDeployKey() throws IOException {
|
||||
GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(),0);
|
||||
final GHDeployKey newDeployKey = myRepository.addDeployKey("test", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUt0RAycC5cS42JKh6SecfFZBR1RrF+2hYMctz4mk74/arBE+wFb7fnSHGzdGKX2h5CFOWODifRCJVhB7hlVxodxe+QkQQYAEL/x1WVCJnGgTGQGOrhOMj95V3UE5pQKhsKD608C+u5tSofcWXLToP1/wZ7U4/AHjqYi08OLsWToHCax55TZkvdt2jo0hbIoYU+XI9Q8Uv4ONDN1oabiOdgeKi8+crvHAuvNleiBhWVBzFh8KdfzaH5uNdw7ihhFjEd1vzqACsjCINCjdMfzl6jD9ExuWuE92nZJnucls2cEoNC6k2aPmrZDg9hA32FXVpyseY+bDUWFU6LO2LG6PB kohsuke@atlas");
|
||||
GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(),0);
|
||||
final GHDeployKey newDeployKey = myRepository.addDeployKey("test", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUt0RAycC5cS42JKh6SecfFZBR1RrF+2hYMctz4mk74/arBE+wFb7fnSHGzdGKX2h5CFOWODifRCJVhB7hlVxodxe+QkQQYAEL/x1WVCJnGgTGQGOrhOMj95V3UE5pQKhsKD608C+u5tSofcWXLToP1/wZ7U4/AHjqYi08OLsWToHCax55TZkvdt2jo0hbIoYU+XI9Q8Uv4ONDN1oabiOdgeKi8+crvHAuvNleiBhWVBzFh8KdfzaH5uNdw7ihhFjEd1vzqACsjCINCjdMfzl6jD9ExuWuE92nZJnucls2cEoNC6k2aPmrZDg9hA32FXVpyseY+bDUWFU6LO2LG6PB kohsuke@atlas");
|
||||
try {
|
||||
assertNotNull(newDeployKey.getId());
|
||||
|
||||
@@ -572,11 +636,195 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
|
||||
@Test
|
||||
public void testCommitStatusContext() throws IOException {
|
||||
GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(), 0);
|
||||
GHRef masterRef = myRepository.getRef("heads/master");
|
||||
GHCommitStatus commitStatus = myRepository.createCommitStatus(masterRef.getObject().getSha(), GHCommitState.SUCCESS, "http://www.example.com", "test", "test/context");
|
||||
assertEquals("test/context", commitStatus.getContext());
|
||||
|
||||
GHRepository myRepository = Iterables.get(gitHub.getMyself().getRepositories().values(), 0);
|
||||
GHRef masterRef = myRepository.getRef("heads/master");
|
||||
GHCommitStatus commitStatus = myRepository.createCommitStatus(masterRef.getObject().getSha(), GHCommitState.SUCCESS, "http://www.example.com", "test", "test/context");
|
||||
assertEquals("test/context", commitStatus.getContext());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMemberPagenation() throws IOException {
|
||||
Set<GHUser> all = new HashSet<GHUser>();
|
||||
for (GHUser u : gitHub.getOrganization("github-api-test-org").getTeamByName("Core Developers").listMembers()) {
|
||||
System.out.println(u.getLogin());
|
||||
all.add(u);
|
||||
}
|
||||
assertFalse(all.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIssueSearch() throws IOException {
|
||||
PagedSearchIterable<GHIssue> r = gitHub.searchIssues().mentions("kohsuke").isOpen().list();
|
||||
for (GHIssue i : r) {
|
||||
System.out.println(i.getTitle());
|
||||
}
|
||||
}
|
||||
|
||||
@Test // issue #99
|
||||
public void testReadme() throws IOException {
|
||||
GHContent readme = gitHub.getRepository("github-api-test-org/test-readme").getReadme();
|
||||
assertEquals(readme.getName(),"README.md");
|
||||
assertEquals(readme.getContent(),"This is a markdown readme.\n");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTrees() throws IOException {
|
||||
GHTree masterTree = gitHub.getRepository("kohsuke/github-api").getTree("master");
|
||||
boolean foundReadme = false;
|
||||
for(GHTreeEntry e : masterTree.getTree()){
|
||||
if("readme".equalsIgnoreCase(e.getPath().replaceAll("\\.md", ""))){
|
||||
foundReadme = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue(foundReadme);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTreesRecursive() throws IOException {
|
||||
GHTree masterTree = gitHub.getRepository("kohsuke/github-api").getTreeRecursive("master", 1);
|
||||
boolean foundThisFile = false;
|
||||
for(GHTreeEntry e : masterTree.getTree()){
|
||||
if(e.getPath().endsWith(AppTest.class.getSimpleName() + ".java")){
|
||||
foundThisFile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue(foundThisFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRepoLabel() throws IOException {
|
||||
GHRepository r = gitHub.getRepository("github-api-test-org/test-labels");
|
||||
List<GHLabel> lst = r.listLabels().asList();
|
||||
for (GHLabel l : lst) {
|
||||
System.out.println(l.getName());
|
||||
}
|
||||
assertTrue(lst.size() > 5);
|
||||
GHLabel e = r.getLabel("enhancement");
|
||||
assertEquals("enhancement",e.getName());
|
||||
assertNotNull(e.getUrl());
|
||||
assertTrue(Pattern.matches("[0-9a-fA-F]{6}",e.getColor()));
|
||||
|
||||
{// CRUD
|
||||
GHLabel t = r.createLabel("test", "123456");
|
||||
GHLabel t2 = r.getLabel("test");
|
||||
assertEquals(t.getName(), t2.getName());
|
||||
assertEquals(t.getColor(), "123456");
|
||||
assertEquals(t.getColor(), t2.getColor());
|
||||
assertEquals(t.getUrl(), t2.getUrl());
|
||||
t.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribers() throws IOException {
|
||||
boolean kohsuke = false;
|
||||
GHRepository mr = gitHub.getRepository("kohsuke/github-api");
|
||||
for (GHUser u : mr.listSubscribers()) {
|
||||
System.out.println(u.getLogin());
|
||||
kohsuke |= u.getLogin().equals("kohsuke");
|
||||
}
|
||||
assertTrue(kohsuke);
|
||||
System.out.println("---");
|
||||
|
||||
boolean githubApi = false;
|
||||
for (GHRepository r : gitHub.getUser("kohsuke").listRepositories()) {
|
||||
System.out.println(r.getName());
|
||||
githubApi |= r.equals(mr);
|
||||
}
|
||||
assertTrue(githubApi);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListAllRepositories() throws Exception {
|
||||
Iterator<GHRepository> itr = gitHub.listAllPublicRepositories().iterator();
|
||||
for (int i=0; i<30; i++) {
|
||||
assertTrue(itr.hasNext());
|
||||
GHRepository r = itr.next();
|
||||
System.out.println(r.getFullName());
|
||||
assertNotNull(r.getUrl());
|
||||
assertNotEquals(0,r.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Test // issue #162
|
||||
public void testIssue162() throws Exception {
|
||||
GHRepository r = gitHub.getRepository("kohsuke/github-api");
|
||||
List<GHContent> contents = r.getDirectoryContent("", "gh-pages");
|
||||
for (GHContent content : contents) {
|
||||
if (content.isFile()) {
|
||||
String content1 = content.getContent();
|
||||
String content2 = r.getFileContent(content.getPath(), "gh-pages").getContent();
|
||||
System.out.println(content.getPath());
|
||||
assertEquals(content1, content2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void markDown() throws Exception {
|
||||
assertEquals("<p><strong>Test日本語</strong></p>", IOUtils.toString(gitHub.renderMarkdown("**Test日本語**")).trim());
|
||||
|
||||
String actual = IOUtils.toString(gitHub.getRepository("kohsuke/github-api").renderMarkdown("@kohsuke to fix issue #1", MarkdownMode.GFM));
|
||||
System.out.println(actual);
|
||||
assertTrue(actual.contains("href=\"https://github.com/kohsuke\""));
|
||||
assertTrue(actual.contains("href=\"https://github.com/kohsuke/github-api/pull/1\""));
|
||||
assertTrue(actual.contains("class=\"user-mention\""));
|
||||
assertTrue(actual.contains("class=\"issue-link\""));
|
||||
assertTrue(actual.contains("to fix issue"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchUsers() throws Exception {
|
||||
PagedSearchIterable<GHUser> r = gitHub.searchUsers().q("tom").repos(">42").followers(">1000").list();
|
||||
GHUser u = r.iterator().next();
|
||||
System.out.println(u.getName());
|
||||
assertNotNull(u.getId());
|
||||
assertTrue(r.getTotalCount() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchRepositories() throws Exception {
|
||||
PagedSearchIterable<GHRepository> r = gitHub.searchRepositories().q("tetris").language("assembly").sort(GHRepositorySearchBuilder.Sort.STARS).list();
|
||||
GHRepository u = r.iterator().next();
|
||||
System.out.println(u.getName());
|
||||
assertNotNull(u.getId());
|
||||
assertEquals("Assembly", u.getLanguage());
|
||||
assertTrue(r.getTotalCount() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchContent() throws Exception {
|
||||
PagedSearchIterable<GHContent> r = gitHub.searchContent().q("addClass").in("file").language("js").repo("jquery/jquery").list();
|
||||
GHContent c = r.iterator().next();
|
||||
System.out.println(c.getName());
|
||||
assertNotNull(c.getDownloadUrl());
|
||||
assertNotNull(c.getOwner());
|
||||
assertEquals("jquery/jquery",c.getOwner().getFullName());
|
||||
assertTrue(r.getTotalCount() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notifications() throws Exception {
|
||||
boolean found=false;
|
||||
for (GHThread t : gitHub.listNotifications().nonBlocking(true).read(true)) {
|
||||
if (!found) {
|
||||
found = true;
|
||||
t.markAsRead(); // test this by calling it once on old nofication
|
||||
}
|
||||
assertNotNull(t.getTitle());
|
||||
assertNotNull(t.getReason());
|
||||
|
||||
System.out.println(t.getTitle());
|
||||
System.out.println(t.getLastReadAt());
|
||||
System.out.println(t.getType());
|
||||
System.out.println();
|
||||
}
|
||||
assertTrue(found);
|
||||
gitHub.listNotifications().markAsRead();
|
||||
}
|
||||
|
||||
private void kohsuke() {
|
||||
|
||||
16
src/test/java/org/kohsuke/github/CommitTest.java
Normal file
16
src/test/java/org/kohsuke/github/CommitTest.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class CommitTest extends AbstractGitHubApiTestBase {
|
||||
@Test // issue 152
|
||||
public void lastStatus() throws IOException {
|
||||
GHTag t = gitHub.getRepository("stapler/stapler").listTags().iterator().next();
|
||||
t.getCommit().getLastStatus();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
@@ -21,4 +28,81 @@ public class GitHubTest extends TestCase {
|
||||
GitHub hub = GitHub.connectUsingPassword("kohsuke", "bogus");
|
||||
assertEquals("https://api.github.com/test", hub.getApiURL("/test").toString());
|
||||
}
|
||||
|
||||
public void testGitHubBuilderFromEnvironment() throws IOException {
|
||||
|
||||
Map<String, String>props = new HashMap<String, String>();
|
||||
|
||||
props.put("login", "bogus");
|
||||
props.put("oauth", "bogus");
|
||||
props.put("password", "bogus");
|
||||
|
||||
setupEnvironment(props);
|
||||
|
||||
GitHubBuilder builder = GitHubBuilder.fromEnvironment();
|
||||
|
||||
assertEquals("bogus", builder.user);
|
||||
assertEquals("bogus", builder.oauthToken);
|
||||
assertEquals("bogus", builder.password);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from StackOverflow: http://stackoverflow.com/a/7201825/2336755
|
||||
*
|
||||
* This allows changing the in memory process environment.
|
||||
*
|
||||
* Its used to wire in values for the github credentials to test that the GitHubBuilder works properly to resolve them.
|
||||
*/
|
||||
private void setupEnvironment(Map<String, String> newenv) {
|
||||
try {
|
||||
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
|
||||
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
|
||||
theEnvironmentField.setAccessible(true);
|
||||
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
|
||||
env.putAll(newenv);
|
||||
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
|
||||
theCaseInsensitiveEnvironmentField.setAccessible(true);
|
||||
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
|
||||
cienv.putAll(newenv);
|
||||
} catch (NoSuchFieldException e) {
|
||||
try {
|
||||
Class[] classes = Collections.class.getDeclaredClasses();
|
||||
Map<String, String> env = System.getenv();
|
||||
for (Class cl : classes) {
|
||||
if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
|
||||
Field field = cl.getDeclaredField("m");
|
||||
field.setAccessible(true);
|
||||
Object obj = field.get(env);
|
||||
Map<String, String> map = (Map<String, String>) obj;
|
||||
map.clear();
|
||||
map.putAll(newenv);
|
||||
}
|
||||
}
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void testGitHubBuilderFromCustomEnvironment() throws IOException {
|
||||
Map<String, String> props = new HashMap<String, String>();
|
||||
|
||||
props.put("customLogin", "bogusLogin");
|
||||
props.put("customOauth", "bogusOauth");
|
||||
props.put("customPassword", "bogusPassword");
|
||||
props.put("customEndpoint", "bogusEndpoint");
|
||||
|
||||
setupEnvironment(props);
|
||||
|
||||
GitHubBuilder builder = GitHubBuilder.fromEnvironment("customLogin", "customPassword", "customOauth", "customEndpoint");
|
||||
|
||||
assertEquals("bogusLogin", builder.user);
|
||||
assertEquals("bogusOauth", builder.oauthToken);
|
||||
assertEquals("bogusPassword", builder.password);
|
||||
assertEquals("bogusEndpoint", builder.endpoint);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +1,67 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class PullRequestTest extends AbstractGitHubApiTestBase {
|
||||
@Test
|
||||
public void createPullRequest() throws Exception {
|
||||
GHRepository j = gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
|
||||
String name = rnd.next();
|
||||
GHPullRequest p = j.createPullRequest(name, "stable", "master", "## test");
|
||||
GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
|
||||
System.out.println(p.getUrl());
|
||||
assertEquals(name, p.getTitle());
|
||||
p.close();
|
||||
}
|
||||
|
||||
@Test // Requires push access to the test repo to pass
|
||||
public void setLabels() throws Exception {
|
||||
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
|
||||
String label = rnd.next();
|
||||
p.setLabels(label);
|
||||
|
||||
Collection<GHLabel> labels = getRepository().getPullRequest(p.getNumber()).getLabels();
|
||||
assertEquals(1, labels.size());
|
||||
assertEquals(label, labels.iterator().next().getName());
|
||||
}
|
||||
|
||||
@Test // Requires push access to the test repo to pass
|
||||
public void setAssignee() throws Exception {
|
||||
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
|
||||
GHMyself user = gitHub.getMyself();
|
||||
p.assignTo(user);
|
||||
|
||||
assertEquals(user, getRepository().getPullRequest(p.getNumber()).getAssignee());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUser() throws IOException {
|
||||
GHPullRequest p = getRepository().createPullRequest(rnd.next(), "stable", "master", "## test");
|
||||
GHPullRequest prSingle = getRepository().getPullRequest(p.getNumber());
|
||||
assertNotNull(prSingle.getUser().root);
|
||||
prSingle.getMergeable();
|
||||
assertNotNull(prSingle.getUser().root);
|
||||
|
||||
PagedIterable<GHPullRequest> ghPullRequests = getRepository().listPullRequests(GHIssueState.OPEN);
|
||||
for (GHPullRequest pr : ghPullRequests) {
|
||||
assertNotNull(pr.getUser().root);
|
||||
assertFalse(pr.getMergeable());
|
||||
assertNotNull(pr.getUser().root);
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() throws Exception {
|
||||
for (GHPullRequest pr : getRepository().getPullRequests(GHIssueState.OPEN)) {
|
||||
pr.close();
|
||||
}
|
||||
}
|
||||
|
||||
private GHRepository getRepository() throws IOException {
|
||||
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
|
||||
}
|
||||
}
|
||||
|
||||
89
src/test/java/org/kohsuke/github/RepositoryMockTest.java
Normal file
89
src/test/java/org/kohsuke/github/RepositoryMockTest.java
Normal file
@@ -0,0 +1,89 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Luciano P. Sabenca (luciano.sabenca [at] movile [com] | lucianosabenca [at] gmail [dot] com
|
||||
*/
|
||||
public class RepositoryMockTest {
|
||||
|
||||
@Mock
|
||||
GitHub mockGitHub;
|
||||
|
||||
@Mock
|
||||
Iterator<GHUser[]> iterator;
|
||||
|
||||
@Mock
|
||||
GHRepository mockRepository;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listCollaborators() throws Exception {
|
||||
GHUser user1 = new GHUser();
|
||||
user1.login = "login1";
|
||||
|
||||
GHUser user2 = new GHUser();
|
||||
user2.login = "login2";
|
||||
|
||||
|
||||
when(iterator.hasNext()).thenReturn(true, false, true);
|
||||
when(iterator.next()).thenReturn(new GHUser[]{user1}, new GHUser[]{user2});
|
||||
|
||||
Requester requester = Mockito.mock(Requester.class);
|
||||
when(mockGitHub.retrieve()).thenReturn(requester);
|
||||
|
||||
|
||||
when(requester.asIterator("/repos/*/*/collaborators",
|
||||
GHUser[].class)).thenReturn(iterator, iterator);
|
||||
|
||||
|
||||
PagedIterable<GHUser> pagedIterable = Mockito.mock(PagedIterable.class);
|
||||
when(mockRepository.listCollaborators()).thenReturn(pagedIterable);
|
||||
|
||||
PagedIterator<GHUser> userPagedIterator = new PagedIterator<GHUser>(iterator) {
|
||||
@Override
|
||||
protected void wrapUp(GHUser[] page) {
|
||||
|
||||
}
|
||||
};
|
||||
PagedIterator<GHUser> userPagedIterator2 = new PagedIterator<GHUser>(iterator) {
|
||||
@Override
|
||||
protected void wrapUp(GHUser[] page) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
when(pagedIterable.iterator()).thenReturn(userPagedIterator, userPagedIterator2);
|
||||
|
||||
Iterator<GHUser> returnIterator1 = mockRepository.listCollaborators().iterator();
|
||||
|
||||
|
||||
Assert.assertTrue(returnIterator1.hasNext());
|
||||
GHUser user = returnIterator1.next();
|
||||
Assert.assertEquals(user, user1);
|
||||
Assert.assertFalse(returnIterator1.hasNext());
|
||||
|
||||
|
||||
Iterator returnIterator2 = mockRepository.listCollaborators().iterator();
|
||||
|
||||
|
||||
Assert.assertTrue(returnIterator2.hasNext());
|
||||
user = returnIterator1.next();
|
||||
Assert.assertEquals(user, user2);
|
||||
}
|
||||
}
|
||||
@@ -1,91 +1,53 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.kohsuke.github.GHRepository.Contributor;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Luciano P. Sabenca (luciano.sabenca [at] movile [com] | lucianosabenca [at] gmail [dot] com
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public class RepositoryTest {
|
||||
public class RepositoryTest extends AbstractGitHubApiTestBase {
|
||||
@Test
|
||||
public void subscription() throws Exception {
|
||||
GHRepository r = getRepository();
|
||||
assertNull(r.getSubscription());
|
||||
|
||||
@Mock
|
||||
GitHub mockGitHub;
|
||||
GHSubscription s = r.subscribe(true, false);
|
||||
assertEquals(s.getRepository(), r);
|
||||
|
||||
@Mock
|
||||
Iterator<GHUser[]> iterator;
|
||||
s.delete();
|
||||
|
||||
@Mock
|
||||
GHRepository mockRepository;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
assertNull(r.getSubscription());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listCollaborators() throws Exception {
|
||||
GHUser user1 = new GHUser();
|
||||
user1.login = "login1";
|
||||
public void listContributors() throws IOException {
|
||||
GHRepository r = gitHub.getOrganization("stapler").getRepository("stapler");
|
||||
int i=0;
|
||||
boolean kohsuke = false;
|
||||
|
||||
GHUser user2 = new GHUser();
|
||||
user2.login = "login2";
|
||||
for (Contributor c : r.listContributors()) {
|
||||
System.out.println(c.getName());
|
||||
assertTrue(c.getContributions()>0);
|
||||
if (c.getLogin().equals("kohsuke"))
|
||||
kohsuke = true;
|
||||
if (i++ > 5)
|
||||
break;
|
||||
}
|
||||
|
||||
assertTrue(kohsuke);
|
||||
}
|
||||
|
||||
when(iterator.hasNext()).thenReturn(true, false, true);
|
||||
when(iterator.next()).thenReturn(new GHUser[]{user1}, new GHUser[]{user2});
|
||||
|
||||
Requester requester = Mockito.mock(Requester.class);
|
||||
when(mockGitHub.retrieve()).thenReturn(requester);
|
||||
|
||||
|
||||
when(requester.asIterator("/repos/*/*/collaborators",
|
||||
GHUser[].class)).thenReturn(iterator, iterator);
|
||||
|
||||
|
||||
PagedIterable<GHUser> pagedIterable = Mockito.mock(PagedIterable.class);
|
||||
when(mockRepository.listCollaborators()).thenReturn(pagedIterable);
|
||||
|
||||
PagedIterator<GHUser> userPagedIterator = new PagedIterator<GHUser>(iterator) {
|
||||
@Override
|
||||
protected void wrapUp(GHUser[] page) {
|
||||
|
||||
}
|
||||
};
|
||||
PagedIterator<GHUser> userPagedIterator2 = new PagedIterator<GHUser>(iterator) {
|
||||
@Override
|
||||
protected void wrapUp(GHUser[] page) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
when(pagedIterable.iterator()).thenReturn(userPagedIterator, userPagedIterator2);
|
||||
|
||||
Iterator<GHUser> returnIterator1 = mockRepository.listCollaborators().iterator();
|
||||
|
||||
|
||||
Assert.assertTrue(returnIterator1.hasNext());
|
||||
GHUser user = returnIterator1.next();
|
||||
Assert.assertEquals(user, user1);
|
||||
Assert.assertFalse(returnIterator1.hasNext());
|
||||
|
||||
|
||||
Iterator returnIterator2 = mockRepository.listCollaborators().iterator();
|
||||
|
||||
|
||||
Assert.assertTrue(returnIterator2.hasNext());
|
||||
user = returnIterator1.next();
|
||||
Assert.assertEquals(user, user2);
|
||||
|
||||
private GHRepository getRepository() throws IOException {
|
||||
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listLanguages() throws IOException {
|
||||
GHRepository r = gitHub.getRepository("kohsuke/github-api");
|
||||
String mainLanguage = r.getLanguage();
|
||||
assertTrue(r.listLanguages().containsKey(mainLanguage));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user