mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-11 15:50:17 +00:00
Compare commits
58 Commits
github-api
...
github-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
14
pom.xml
14
pom.xml
@@ -3,11 +3,11 @@
|
||||
<parent>
|
||||
<groupId>org.kohsuke</groupId>
|
||||
<artifactId>pom</artifactId>
|
||||
<version>12</version>
|
||||
<version>14</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>github-api</artifactId>
|
||||
<version>1.61</version>
|
||||
<version>1.64-SNAPSHOT</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.61</tag>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
@@ -139,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,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;
|
||||
|
||||
@@ -26,6 +28,7 @@ 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;
|
||||
@@ -58,35 +61,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 +103,18 @@ public class GHContent {
|
||||
return html_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the actual content stored here.
|
||||
*/
|
||||
public InputStream read() throws IOException {
|
||||
return new Requester(owner.root).read(getDownloadUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to retrieve the raw content of the file. Null if this is a directory.
|
||||
*/
|
||||
public String getDownloadUrl() { return download_url; }
|
||||
|
||||
public boolean isFile() {
|
||||
return "file".equals(type);
|
||||
}
|
||||
|
||||
@@ -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,16 @@ public abstract class GHEventPayload {
|
||||
return commits;
|
||||
}
|
||||
|
||||
public GHRepository getRepository() {
|
||||
return repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
void wrapUp(GitHub root) {
|
||||
if (repository!=null)
|
||||
repository.wrap(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit in a push
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,7 @@ 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 extends GHObject {
|
||||
/*package almost final*/ GHUser owner;
|
||||
|
||||
@@ -52,6 +52,7 @@ public class GHIssue extends GHObject {
|
||||
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, html_url;
|
||||
@@ -59,22 +60,10 @@ public class GHIssue extends GHObject {
|
||||
protected GHMilestone milestone;
|
||||
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) {
|
||||
@@ -134,11 +123,11 @@ public class GHIssue extends GHObject {
|
||||
return Enum.valueOf(GHIssueState.class, state.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
public Collection<Label> getLabels() throws IOException {
|
||||
public Collection<GHLabel> getLabels() throws IOException {
|
||||
if(labels == null){
|
||||
return Collections.EMPTY_LIST;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.unmodifiableList(labels);
|
||||
return Collections.<GHLabel>unmodifiableList(labels);
|
||||
}
|
||||
|
||||
public Date getClosedAt() {
|
||||
@@ -237,7 +226,15 @@ public class GHIssue extends GHObject {
|
||||
public GHUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
@@ -250,10 +247,17 @@ public class GHIssue extends GHObject {
|
||||
return comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns non-null if this issue is a shadow of a pull request.
|
||||
*/
|
||||
public PullRequest getPullRequest() {
|
||||
return pull_request;
|
||||
}
|
||||
|
||||
public boolean isPullRequest() {
|
||||
return pull_request!=null;
|
||||
}
|
||||
|
||||
public GHMilestone getMilestone() {
|
||||
return milestone;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public abstract class GHPerson extends GHObject {
|
||||
*
|
||||
* 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);
|
||||
|
||||
@@ -127,7 +127,7 @@ public class GHPullRequest extends GHIssue {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Label> getLabels() throws IOException {
|
||||
public Collection<GHLabel> getLabels() throws IOException {
|
||||
fetchIssue();
|
||||
return super.getLabels();
|
||||
}
|
||||
@@ -194,7 +194,7 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ public class GHRelease extends GHObject {
|
||||
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))
|
||||
|
||||
@@ -30,7 +30,9 @@ 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.*;
|
||||
|
||||
@@ -195,7 +197,7 @@ public class GHRepository extends GHObject {
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -208,8 +210,8 @@ public class GHRepository extends GHObject {
|
||||
|
||||
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));
|
||||
}
|
||||
@@ -285,7 +287,19 @@ public class GHRepository extends GHObject {
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -371,7 +385,7 @@ public class GHRepository extends GHObject {
|
||||
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) {
|
||||
@@ -392,7 +406,7 @@ public class GHRepository extends GHObject {
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@@ -401,7 +415,7 @@ public class GHRepository extends GHObject {
|
||||
* 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 {
|
||||
@@ -423,7 +437,7 @@ public class GHRepository extends GHObject {
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,14 +445,14 @@ public class GHRepository extends GHObject {
|
||||
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(""));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -479,7 +493,7 @@ public class GHRepository extends GHObject {
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -492,7 +506,7 @@ public class GHRepository extends GHObject {
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -502,7 +516,7 @@ public class GHRepository extends GHObject {
|
||||
* 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++) {
|
||||
@@ -521,7 +535,7 @@ public class GHRepository extends GHObject {
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -539,7 +553,7 @@ public class GHRepository extends GHObject {
|
||||
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)
|
||||
@@ -578,14 +592,14 @@ public class GHRepository extends GHObject {
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -597,7 +611,7 @@ public class GHRepository extends GHObject {
|
||||
* @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);
|
||||
}
|
||||
|
||||
@@ -641,6 +655,35 @@ public class GHRepository extends GHObject {
|
||||
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.
|
||||
*/
|
||||
public GHCommit getCommit(String sha1) throws IOException {
|
||||
@@ -760,6 +803,54 @@ public class GHRepository extends GHObject {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -938,12 +1029,9 @@ public class GHRepository extends GHObject {
|
||||
|
||||
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 {
|
||||
@@ -952,20 +1040,21 @@ public class GHRepository extends GHObject {
|
||||
|
||||
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 {
|
||||
@@ -1012,12 +1101,75 @@ public class GHRepository extends GHObject {
|
||||
|
||||
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)));
|
||||
root.retrieve().to(getApiTailUrl("keys"), GHDeployKey[].class)));
|
||||
for (GHDeployKey h : list)
|
||||
h.wrap(this);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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())
|
||||
.read("/markdown"),
|
||||
"UTF-8");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
@@ -1041,6 +1193,7 @@ public class GHRepository extends GHObject {
|
||||
}
|
||||
|
||||
String getApiTailUrl(String tail) {
|
||||
return "/repos/" + owner.login + "/" + name +'/'+tail;
|
||||
if (tail.length()>0 && !tail.startsWith("/")) tail='/'+tail;
|
||||
return "/repos/" + owner.login + "/" + name +tail;
|
||||
}
|
||||
}
|
||||
|
||||
62
src/main/java/org/kohsuke/github/GHSubscription.java
Normal file
62
src/main/java/org/kohsuke/github/GHSubscription.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Represents your subscribing to a repository.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,10 @@ package org.kohsuke.github;
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
|
||||
|
||||
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,6 +40,7 @@ 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.Set;
|
||||
@@ -53,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 {
|
||||
@@ -63,11 +72,13 @@ 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;
|
||||
|
||||
/*package*/ final RateLimitHandler rateLimitHandler;
|
||||
|
||||
private HttpConnector connector = HttpConnector.DEFAULT;
|
||||
|
||||
/**
|
||||
@@ -106,7 +117,7 @@ public class GitHub {
|
||||
* @param connector
|
||||
* HttpConnector to use. Pass null to use default connector.
|
||||
*/
|
||||
/* package */ GitHub(String apiUrl, String login, String oauthAccessToken, String password, HttpConnector connector) 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;
|
||||
@@ -125,6 +136,7 @@ public class GitHub {
|
||||
if (login==null && encodedAuthorization!=null)
|
||||
login = getMyself().getLogin();
|
||||
this.login = login;
|
||||
this.rateLimitHandler = rateLimitHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,7 +295,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;
|
||||
@@ -324,27 +336,27 @@ 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);
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
return allMyTeams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public events visible to you. Equivalent of what's displayed on https://github.com/
|
||||
@@ -431,6 +443,53 @@ public class GitHub {
|
||||
return new GHIssueSearchBuilder(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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")
|
||||
.read("/markdown/raw"),
|
||||
"UTF-8");
|
||||
}
|
||||
|
||||
/*package*/ static URL parseURL(String s) {
|
||||
try {
|
||||
|
||||
@@ -6,102 +6,122 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
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 {
|
||||
private String endpoint = GitHub.GITHUB_URL;
|
||||
|
||||
|
||||
// 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;
|
||||
else {
|
||||
|
||||
// this is the case where the ~/.github file exists but has no content.
|
||||
|
||||
builder = fromEnvironment();
|
||||
|
||||
if (builder.user != null)
|
||||
return builder;
|
||||
else
|
||||
throw new IOException("Failed to resolve credentials from ~/.github or the environment.");
|
||||
}
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
builder = fromEnvironment();
|
||||
|
||||
if (builder.user != null)
|
||||
return builder;
|
||||
else
|
||||
throw new IOException("Failed to resolve credentials from ~/.github or the environment.", 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 {
|
||||
|
||||
|
||||
Properties env = new Properties();
|
||||
|
||||
Object loginValue = System.getenv(loginVariableName);
|
||||
|
||||
if (loginValue != null)
|
||||
env.put("login", loginValue);
|
||||
|
||||
Object passwordValue = System.getenv(passwordVariableName);
|
||||
|
||||
if (passwordValue != null)
|
||||
env.put("password", passwordValue);
|
||||
|
||||
Object oauthValue = System.getenv(oauthVariableName);
|
||||
|
||||
if (oauthValue != null)
|
||||
env.put("oauth", oauthValue);
|
||||
|
||||
return fromProperties(env);
|
||||
|
||||
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();
|
||||
|
||||
Map<String, String> env = System.getenv();
|
||||
|
||||
for (Map.Entry<String, String> element : env.entrySet()) {
|
||||
|
||||
props.put(element.getKey(), element.getValue());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -110,7 +130,7 @@ public class GitHubBuilder {
|
||||
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;
|
||||
@@ -128,6 +148,7 @@ public class GitHubBuilder {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -152,8 +173,25 @@ public class GitHubBuilder {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -29,7 +29,6 @@ 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;
|
||||
@@ -52,10 +51,9 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
/**
|
||||
* A builder pattern for making HTTP call and parsing its output.
|
||||
*
|
||||
@@ -190,6 +188,14 @@ class Requester {
|
||||
|
||||
private <T> T _to(String tailApiUrl, Class<T> type, T instance) throws IOException {
|
||||
while (true) {// loop while API rate limit is hit
|
||||
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();
|
||||
}
|
||||
HttpURLConnection uc = setupConnection(root.getApiURL(tailApiUrl));
|
||||
|
||||
buildRequest(uc);
|
||||
@@ -238,6 +244,20 @@ class Requester {
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream read(String tailApiUrl) throws IOException {
|
||||
while (true) {// loop while API rate limit is hit
|
||||
HttpURLConnection uc = setupConnection(root.getApiURL(tailApiUrl));
|
||||
|
||||
buildRequest(uc);
|
||||
|
||||
try {
|
||||
return wrapStream(uc,uc.getInputStream());
|
||||
} catch (IOException e) {
|
||||
handleApiError(e,uc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildRequest(HttpURLConnection uc) throws IOException {
|
||||
if (!method.equals("GET")) {
|
||||
uc.setDoOutput(true);
|
||||
@@ -396,7 +416,11 @@ class Requester {
|
||||
r = new InputStreamReader(wrapStream(uc, 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;
|
||||
@@ -417,18 +441,11 @@ 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 {
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
-----
|
||||
|
||||
@@ -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,22 +1,17 @@
|
||||
import org.kohsuke.github.GHIssue;
|
||||
import org.kohsuke.github.GHOrganization;
|
||||
import org.kohsuke.github.GHTeam;
|
||||
import org.kohsuke.github.GHRepository;
|
||||
import org.kohsuke.github.GitHub;
|
||||
import org.kohsuke.github.PagedIterable;
|
||||
import org.kohsuke.github.PagedSearchIterable;
|
||||
|
||||
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 {
|
||||
PagedSearchIterable<GHIssue> reviewbybees = GitHub.connect().searchIssues().mentions("reviewbybees").isOpen().list();
|
||||
for (GHIssue r : reviewbybees) {
|
||||
System.out.println(r.getTitle());
|
||||
Collection<GHRepository> lst = GitHub.connect().getUser("kohsuke").getRepositories().values();
|
||||
for (GHRepository r : lst) {
|
||||
System.out.println(r.getName());
|
||||
}
|
||||
System.out.println("total="+reviewbybees.getTotalCount());
|
||||
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,16 +15,11 @@ 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()).build();
|
||||
} else {
|
||||
gitHub = GitHub.connect();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package org.kohsuke.github;
|
||||
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;
|
||||
@@ -12,6 +14,7 @@ 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.
|
||||
@@ -204,31 +207,31 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
|
||||
@Test
|
||||
public void testMyTeamsContainsAllMyOrganizations() throws IOException {
|
||||
Map<String, Set<GHTeam>> teams = gitHub.getMyTeams();
|
||||
Map<String, GHOrganization> myOrganizations = gitHub.getMyOrganizations();
|
||||
assertEquals(teams.keySet(), myOrganizations.keySet());
|
||||
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));
|
||||
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());
|
||||
GHOrganization org = gitHub.getOrganization(organizationName);
|
||||
assertNotNull(org);
|
||||
GHTeam team = org.getTeamByName(teamName);
|
||||
assertNotNull(team);
|
||||
return team.hasMember(gitHub.getMyself());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -658,6 +661,122 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
}
|
||||
}
|
||||
|
||||
@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"));
|
||||
}
|
||||
|
||||
private void kohsuke() {
|
||||
String login = getUser().getLogin();
|
||||
Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -98,15 +98,16 @@ public class GitHubTest extends TestCase {
|
||||
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");
|
||||
GitHubBuilder builder = GitHubBuilder.fromEnvironment("customLogin", "customPassword", "customOauth", "customEndpoint");
|
||||
|
||||
assertEquals("bogusLogin", builder.user);
|
||||
assertEquals("bogusOauth", builder.oauthToken);
|
||||
assertEquals("bogusPassword", builder.password);
|
||||
|
||||
assertEquals("bogusEndpoint", builder.endpoint);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
|
||||
String label = rnd.next();
|
||||
p.setLabels(label);
|
||||
|
||||
Collection<GHIssue.Label> labels = getRepository().getPullRequest(p.getNumber()).getLabels();
|
||||
Collection<GHLabel> labels = getRepository().getPullRequest(p.getNumber()).getLabels();
|
||||
assertEquals(1, labels.size());
|
||||
assertEquals(label, labels.iterator().next().getName());
|
||||
}
|
||||
@@ -38,6 +38,22 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
|
||||
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)) {
|
||||
|
||||
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