mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-11 00:11:25 +00:00
Compare commits
47 Commits
github-api
...
github-api
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46715cac08 | ||
|
|
0f21eba57f | ||
|
|
cb7620395a | ||
|
|
e9b59c6bef | ||
|
|
3d03659508 | ||
|
|
0374d2de48 | ||
|
|
2627dc5ee4 | ||
|
|
1f4325e7db | ||
|
|
f2e7b40425 | ||
|
|
4ee3086b6d | ||
|
|
a3a715c3ba | ||
|
|
6cad4a3c33 | ||
|
|
b9b6f4fd44 | ||
|
|
17d1994a53 | ||
|
|
13184e72e1 | ||
|
|
911e8d21a7 | ||
|
|
5b69a2925f | ||
|
|
d1c900a620 | ||
|
|
6bfeb54f3c | ||
|
|
198fede915 | ||
|
|
1212ae3eb3 | ||
|
|
1266dcc0c7 | ||
|
|
6fcddf4a47 | ||
|
|
dfea424b94 | ||
|
|
9d03435aa1 | ||
|
|
26c20a7a22 | ||
|
|
470da06ecf | ||
|
|
a746a310bc | ||
|
|
3dbb516084 | ||
|
|
32177283b3 | ||
|
|
3a66e90b7a | ||
|
|
a454fb10ec | ||
|
|
b5386a35ee | ||
|
|
11651da411 | ||
|
|
88d52c44ad | ||
|
|
2d7d4bbd4e | ||
|
|
e6ee278fde | ||
|
|
6380cf9ed0 | ||
|
|
2e78dc52c7 | ||
|
|
ccb42d3249 | ||
|
|
c5009ab44b | ||
|
|
9d15cd43a3 | ||
|
|
0780e10fa2 | ||
|
|
0731f63237 | ||
|
|
a29896042b | ||
|
|
68ebc08c9d | ||
|
|
a1df526f93 |
6
pom.xml
6
pom.xml
@@ -3,11 +3,11 @@
|
||||
<parent>
|
||||
<groupId>org.kohsuke</groupId>
|
||||
<artifactId>pom</artifactId>
|
||||
<version>14</version>
|
||||
<version>17</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>github-api</artifactId>
|
||||
<version>1.81</version>
|
||||
<version>1.86</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.81</tag>
|
||||
<tag>github-api-1.86</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
|
||||
64
src/main/java/org/kohsuke/github/GHBlob.java
Normal file
64
src/main/java/org/kohsuke/github/GHBlob.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64InputStream;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author Kanstantsin Shautsou
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see GHTreeEntry#asBlob()
|
||||
* @see GHRepository#getBlob(String)
|
||||
* @see <a href="https://developer.github.com/v3/git/blobs/#get-a-blob">Get a blob</a>
|
||||
*/
|
||||
public class GHBlob {
|
||||
private String content, encoding, url, sha;
|
||||
private long size;
|
||||
|
||||
/**
|
||||
* API URL of this blob.
|
||||
*/
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
|
||||
public String getSha() {
|
||||
return sha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of bytes in this blob.
|
||||
*/
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getEncoding() {
|
||||
return encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoded content. You probably want {@link #read()}
|
||||
*/
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the actual bytes of the blob.
|
||||
*/
|
||||
public InputStream read() {
|
||||
if (encoding.equals("base64")) {
|
||||
try {
|
||||
return new Base64InputStream(new ByteArrayInputStream(content.getBytes("US-ASCII")), false);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AssertionError(e); // US-ASCII is mandatory
|
||||
}
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unrecognized encoding: "+encoding);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import org.kohsuke.github.BranchProtection.RequiredStatusChecks;
|
||||
import static org.kohsuke.github.Previews.LOKI;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.kohsuke.github.Previews.LOKI;
|
||||
import org.kohsuke.github.BranchProtection.RequiredStatusChecks;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
/**
|
||||
* A branch in a repository.
|
||||
@@ -22,6 +26,10 @@ public class GHBranch {
|
||||
|
||||
private String name;
|
||||
private Commit commit;
|
||||
@JsonProperty("protected")
|
||||
private boolean protection;
|
||||
private String protection_url;
|
||||
|
||||
|
||||
public static class Commit {
|
||||
String sha;
|
||||
@@ -45,6 +53,23 @@ public class GHBranch {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the push to this branch is restricted via branch protection.
|
||||
*/
|
||||
@Preview @Deprecated
|
||||
public boolean isProtected() {
|
||||
return protection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns API URL that deals with the protection of this branch.
|
||||
*/
|
||||
@Preview @Deprecated
|
||||
public URL getProtectionUrl() {
|
||||
return GitHub.parseURL(protection_url);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The commit that this branch currently points to.
|
||||
*/
|
||||
|
||||
@@ -37,6 +37,12 @@ public class GHCommit {
|
||||
|
||||
private int comment_count;
|
||||
|
||||
static class Tree {
|
||||
String sha;
|
||||
}
|
||||
|
||||
private Tree tree;
|
||||
|
||||
@WithBridgeMethods(value = GHAuthor.class, castRequired = true)
|
||||
public GitUser getAuthor() {
|
||||
return author;
|
||||
@@ -224,6 +230,13 @@ public class GHCommit {
|
||||
return stats.deletions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to walk the tree
|
||||
*/
|
||||
public GHTree getTree() throws IOException {
|
||||
return owner.getTree(getCommitShortInfo().tree.sha);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL of this commit like "https://github.com/kohsuke/sandbox-ant/commit/8ae38db0ea5837313ab5f39d43a6f73de3bd9000"
|
||||
*/
|
||||
|
||||
@@ -41,6 +41,11 @@ public class GHIssueSearchBuilder extends GHSearchBuilder<GHIssue> {
|
||||
return q("is:merged");
|
||||
}
|
||||
|
||||
public GHIssueSearchBuilder order(GHDirection v) {
|
||||
req.with("order",v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHIssueSearchBuilder sort(Sort sort) {
|
||||
req.with("sort",sort);
|
||||
return this;
|
||||
|
||||
59
src/main/java/org/kohsuke/github/GHPermission.java
Normal file
59
src/main/java/org/kohsuke/github/GHPermission.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright 2016 CloudBees, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Permission for a user in a repository.
|
||||
* @see <a href="https://developer.github.com/v3/repos/collaborators/#review-a-users-permission-level">API</a>
|
||||
*/
|
||||
/*package*/ class GHPermission {
|
||||
|
||||
private String permission;
|
||||
private GHUser user;
|
||||
|
||||
/**
|
||||
* @return one of {@code admin}, {@code write}, {@code read}, or {@code none}
|
||||
*/
|
||||
public String getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public GHPermissionType getPermissionType() {
|
||||
return Enum.valueOf(GHPermissionType.class, permission.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
public GHUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
void wrapUp(GitHub root) {
|
||||
if (user != null) {
|
||||
user.root = root;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
11
src/main/java/org/kohsuke/github/GHPermissionType.java
Normal file
11
src/main/java/org/kohsuke/github/GHPermissionType.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
public enum GHPermissionType {
|
||||
ADMIN,
|
||||
WRITE,
|
||||
READ,
|
||||
NONE
|
||||
}
|
||||
@@ -93,10 +93,10 @@ public abstract class GHPerson extends GHObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads repository list in a pagenated fashion.
|
||||
* Loads repository list in a paginated fashion.
|
||||
*
|
||||
* <p>
|
||||
* For a person with a lot of repositories, GitHub returns the list of repositories in a pagenated fashion.
|
||||
* For a person with a lot of repositories, GitHub returns the list of repositories in a paginated fashion.
|
||||
* Unlike {@link #getRepositories()}, this method allows the caller to start processing data as it arrives.
|
||||
*
|
||||
* Every {@link Iterator#next()} call results in I/O. Exceptions that occur during the processing is wrapped
|
||||
|
||||
@@ -213,7 +213,7 @@ public class GHPullRequest extends GHIssue {
|
||||
public PagedIterable<GHPullRequestFileDetail> listFiles() {
|
||||
return new PagedIterable<GHPullRequestFileDetail>() {
|
||||
public PagedIterator<GHPullRequestFileDetail> _iterator(int pageSize) {
|
||||
return new PagedIterator<GHPullRequestFileDetail>(root.retrieve().asIterator(String.format("%s/files", getApiURL()),
|
||||
return new PagedIterator<GHPullRequestFileDetail>(root.retrieve().asIterator(String.format("%s/files", getApiRoute()),
|
||||
GHPullRequestFileDetail[].class, pageSize)) {
|
||||
@Override
|
||||
protected void wrapUp(GHPullRequestFileDetail[] page) {
|
||||
@@ -247,7 +247,7 @@ public class GHPullRequest extends GHIssue {
|
||||
return new PagedIterable<GHPullRequestCommitDetail>() {
|
||||
public PagedIterator<GHPullRequestCommitDetail> _iterator(int pageSize) {
|
||||
return new PagedIterator<GHPullRequestCommitDetail>(root.retrieve().asIterator(
|
||||
String.format("%s/commits", getApiURL()),
|
||||
String.format("%s/commits", getApiRoute()),
|
||||
GHPullRequestCommitDetail[].class, pageSize)) {
|
||||
@Override
|
||||
protected void wrapUp(GHPullRequestCommitDetail[] page) {
|
||||
|
||||
@@ -121,9 +121,7 @@ public class GHRelease extends GHObject {
|
||||
* Java 7 or greater. Options for fixing this for earlier JVMs can be found here
|
||||
* http://stackoverflow.com/questions/12361090/server-name-indication-sni-on-java but involve more complicated
|
||||
* handling of the HTTP requests to github's API.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
*/
|
||||
public GHAsset uploadAsset(File file, String contentType) throws IOException {
|
||||
Requester builder = new Requester(owner.root);
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ public class GHReleaseBuilder {
|
||||
*
|
||||
* @param commitish Defaults to the repository’s default branch (usually "master"). Unused if the Git tag
|
||||
* already exists.
|
||||
* @return
|
||||
*/
|
||||
public GHReleaseBuilder commitish(String commitish) {
|
||||
if (commitish != null) {
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.Reader;
|
||||
@@ -448,7 +449,6 @@ public class GHRepository extends GHObject {
|
||||
* Lists up the collaborators on this repository.
|
||||
*
|
||||
* @return Users
|
||||
* @throws IOException
|
||||
*/
|
||||
public PagedIterable<GHUser> listCollaborators() throws IOException {
|
||||
return listUsers("collaborators");
|
||||
@@ -480,6 +480,29 @@ public class GHRepository extends GHObject {
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain permission for a given user in this repository.
|
||||
* @param user a {@link GHUser#getLogin}
|
||||
* @throws FileNotFoundException under some conditions (e.g., private repo you can see but are not an admin of); treat as unknown
|
||||
* @throws HttpException with a 403 under other conditions (e.g., public repo you have no special rights to); treat as unknown
|
||||
*/
|
||||
@Deprecated @Preview
|
||||
public GHPermissionType getPermission(String user) throws IOException {
|
||||
GHPermission perm = root.retrieve().withPreview(KORRA).to(getApiTailUrl("collaborators/" + user + "/permission"), GHPermission.class);
|
||||
perm.wrapUp(root);
|
||||
return perm.getPermissionType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain permission for a given user in this repository.
|
||||
* @throws FileNotFoundException under some conditions (e.g., private repo you can see but are not an admin of); treat as unknown
|
||||
* @throws HttpException with a 403 under other conditions (e.g., public repo you have no special rights to); treat as unknown
|
||||
*/
|
||||
@Deprecated @Preview
|
||||
public GHPermissionType getPermission(GHUser u) throws IOException {
|
||||
return getPermission(u.getLogin());
|
||||
}
|
||||
|
||||
/**
|
||||
* If this repository belongs to an organization, return a set of teams.
|
||||
*/
|
||||
@@ -504,7 +527,6 @@ 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(getApiTailUrl("collaborators/" + user.getLogin()));
|
||||
}
|
||||
@@ -799,7 +821,7 @@ public class GHRepository extends GHObject {
|
||||
*/
|
||||
public GHTree getTree(String sha) throws IOException {
|
||||
String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha);
|
||||
return root.retrieve().to(url, GHTree.class).wrap(root);
|
||||
return root.retrieve().to(url, GHTree.class).wrap(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -814,7 +836,32 @@ public class GHRepository extends GHObject {
|
||||
*/
|
||||
public GHTree getTreeRecursive(String sha, int recursive) throws IOException {
|
||||
String url = String.format("/repos/%s/%s/git/trees/%s?recursive=%d", getOwnerName(), name, sha, recursive);
|
||||
return root.retrieve().to(url, GHTree.class).wrap(root);
|
||||
return root.retrieve().to(url, GHTree.class).wrap(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the metadata & the content of a blob.
|
||||
*
|
||||
* <p>
|
||||
* This method retrieves the whole content in memory, so beware when you are dealing with large BLOB.
|
||||
*
|
||||
* @see <a href="https://developer.github.com/v3/git/blobs/#get-a-blob">Get a blob</a>
|
||||
* @see #readBlob(String)
|
||||
*/
|
||||
public GHBlob getBlob(String blobSha) throws IOException {
|
||||
String target = getApiTailUrl("git/blobs/" + blobSha);
|
||||
return root.retrieve().to(target, GHBlob.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the content of a blob as a stream for better efficiency.
|
||||
*
|
||||
* @see <a href="https://developer.github.com/v3/git/blobs/#get-a-blob">Get a blob</a>
|
||||
* @see #getBlob(String)
|
||||
*/
|
||||
public InputStream readBlob(String blobSha) throws IOException {
|
||||
String target = getApiTailUrl("git/blobs/" + blobSha);
|
||||
return root.retrieve().withHeader("Accept","application/vnd.github.VERSION.raw").asStream(target);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1092,11 +1139,6 @@ public class GHRepository extends GHObject {
|
||||
// return root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root);
|
||||
// }
|
||||
|
||||
private void verifyMine() throws IOException {
|
||||
if (!root.login.equals(getOwnerName()))
|
||||
throw new IOException("Operation not applicable to a repository owned by someone else: " + getOwnerName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set that represents the post-commit hook URLs.
|
||||
* The returned set is live, and changes made to them are reflected to GitHub.
|
||||
|
||||
@@ -57,6 +57,11 @@ public class GHRepositorySearchBuilder extends GHSearchBuilder<GHRepository> {
|
||||
return q("stars:"+v);
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder order(GHDirection v) {
|
||||
req.with("order",v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHRepositorySearchBuilder sort(Sort sort) {
|
||||
req.with("sort",sort);
|
||||
return this;
|
||||
|
||||
@@ -10,10 +10,12 @@ import java.util.List;
|
||||
* https://developer.github.com/v3/git/trees/
|
||||
*
|
||||
* @author Daniel Teixeira - https://github.com/ddtxra
|
||||
* @see GHCommit#getTree()
|
||||
* @see GHRepository#getTree(String)
|
||||
* @see GHTreeEntry#asTree()
|
||||
*/
|
||||
public class GHTree {
|
||||
/* package almost final */GitHub root;
|
||||
/* package almost final */GHRepository repo;
|
||||
|
||||
private boolean truncated;
|
||||
private String sha, url;
|
||||
@@ -28,12 +30,24 @@ public class GHTree {
|
||||
|
||||
/**
|
||||
* Return an array of entries of the trees
|
||||
* @return
|
||||
*/
|
||||
public List<GHTreeEntry> getTree() {
|
||||
return Collections.unmodifiableList(Arrays.asList(tree));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a tree entry by its name.
|
||||
*
|
||||
* IOW, find a directory entry by a file name.
|
||||
*/
|
||||
public GHTreeEntry getEntry(String path) {
|
||||
for (GHTreeEntry e : tree) {
|
||||
if (e.getPath().equals(path))
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -50,8 +64,11 @@ public class GHTree {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
|
||||
/* package */GHTree wrap(GitHub root) {
|
||||
this.root = root;
|
||||
/* package */GHTree wrap(GHRepository repo) {
|
||||
this.repo = repo;
|
||||
for (GHTreeEntry e : tree) {
|
||||
e.tree = this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
@@ -10,6 +12,8 @@ import java.net.URL;
|
||||
* @see GHTree
|
||||
*/
|
||||
public class GHTreeEntry {
|
||||
/* package almost final */GHTree tree;
|
||||
|
||||
private String path, mode, type, sha, url;
|
||||
private long size;
|
||||
|
||||
@@ -44,7 +48,7 @@ public class GHTreeEntry {
|
||||
|
||||
/**
|
||||
* Gets the type such as:
|
||||
* "blob"
|
||||
* "blob", "tree", etc.
|
||||
*
|
||||
* @return The type
|
||||
*/
|
||||
@@ -68,4 +72,37 @@ public class GHTreeEntry {
|
||||
public URL getUrl() {
|
||||
return GitHub.parseURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* If this tree entry represents a file, then return its information.
|
||||
* Otherwise null.
|
||||
*/
|
||||
public GHBlob asBlob() throws IOException {
|
||||
if (type.equals("blob"))
|
||||
return tree.repo.getBlob(sha);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this tree entry represents a file, then return its content.
|
||||
* Otherwise null.
|
||||
*/
|
||||
public InputStream readAsBlob() throws IOException {
|
||||
if (type.equals("blob"))
|
||||
return tree.repo.readBlob(sha);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this tree entry represents a directory, then return it.
|
||||
* Otherwise null.
|
||||
*/
|
||||
public GHTree asTree() throws IOException {
|
||||
if (type.equals("tree"))
|
||||
return tree.repo.getTree(sha);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ public class GHUserSearchBuilder extends GHSearchBuilder<GHUser> {
|
||||
return q("followers:"+v);
|
||||
}
|
||||
|
||||
public GHUserSearchBuilder order(GHDirection v) {
|
||||
req.with("order",v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GHUserSearchBuilder sort(Sort sort) {
|
||||
req.with("sort",sort);
|
||||
return this;
|
||||
|
||||
@@ -23,12 +23,10 @@
|
||||
*/
|
||||
package org.kohsuke.github;
|
||||
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
|
||||
import static java.util.logging.Level.FINE;
|
||||
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
|
||||
import static org.kohsuke.github.Previews.DRAX;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std;
|
||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
@@ -49,17 +47,18 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.CheckForNull;
|
||||
import javax.annotation.Nonnull;
|
||||
import org.apache.commons.codec.Charsets;
|
||||
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;
|
||||
import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std;
|
||||
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.logging.Logger;
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
|
||||
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
|
||||
import static java.util.logging.Level.FINE;
|
||||
import static org.kohsuke.github.Previews.DRAX;
|
||||
|
||||
/**
|
||||
* Root of the GitHub API.
|
||||
@@ -90,6 +89,10 @@ public class GitHub {
|
||||
|
||||
private HttpConnector connector = HttpConnector.DEFAULT;
|
||||
|
||||
private final Object headerRateLimitLock = new Object();
|
||||
private GHRateLimit headerRateLimit = null;
|
||||
private volatile GHRateLimit rateLimit = null;
|
||||
|
||||
/**
|
||||
* Creates a client API root object.
|
||||
*
|
||||
@@ -254,6 +257,10 @@ public class GitHub {
|
||||
return connector;
|
||||
}
|
||||
|
||||
public String getApiUrl() {
|
||||
return apiUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom connector used to make requests to GitHub.
|
||||
*/
|
||||
@@ -287,19 +294,63 @@ public class GitHub {
|
||||
*/
|
||||
public GHRateLimit getRateLimit() throws IOException {
|
||||
try {
|
||||
return retrieve().to("/rate_limit", JsonRateLimit.class).rate;
|
||||
return rateLimit = retrieve().to("/rate_limit", JsonRateLimit.class).rate;
|
||||
} catch (FileNotFoundException e) {
|
||||
// GitHub Enterprise doesn't have the rate limit, so in that case
|
||||
// return some big number that's not too big.
|
||||
// see issue #78
|
||||
GHRateLimit r = new GHRateLimit();
|
||||
r.limit = r.remaining = 1000000;
|
||||
long hours = 1000L * 60 * 60;
|
||||
r.reset = new Date(System.currentTimeMillis() + 1 * hours );
|
||||
return r;
|
||||
long hour = 60L * 60L; // this is madness, storing the date as seconds in a Date object
|
||||
r.reset = new Date(System.currentTimeMillis() / 1000L + hour);
|
||||
return rateLimit = r;
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void updateRateLimit(@Nonnull GHRateLimit observed) {
|
||||
synchronized (headerRateLimitLock) {
|
||||
if (headerRateLimit == null
|
||||
|| headerRateLimit.getResetDate().getTime() < observed.getResetDate().getTime()
|
||||
|| headerRateLimit.remaining > observed.remaining) {
|
||||
headerRateLimit = observed;
|
||||
LOGGER.log(FINE, "Rate limit now: {0}", headerRateLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recently observed rate limit data or {@code null} if either there is no rate limit
|
||||
* (for example GitHub Enterprise) or if no requests have been made.
|
||||
*
|
||||
* @return the most recently observed rate limit data or {@code null}.
|
||||
*/
|
||||
@CheckForNull
|
||||
public GHRateLimit lastRateLimit() {
|
||||
synchronized (headerRateLimitLock) {
|
||||
return headerRateLimit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current rate limit while trying not to actually make any remote requests unless absolutely necessary.
|
||||
*
|
||||
* @return the current rate limit data.
|
||||
* @throws IOException if we couldn't get the current rate limit data.
|
||||
*/
|
||||
@Nonnull
|
||||
public GHRateLimit rateLimit() throws IOException {
|
||||
synchronized (headerRateLimitLock) {
|
||||
if (headerRateLimit != null) {
|
||||
return headerRateLimit;
|
||||
}
|
||||
}
|
||||
GHRateLimit rateLimit = this.rateLimit;
|
||||
if (rateLimit == null || rateLimit.getResetDate().getTime() < System.currentTimeMillis()) {
|
||||
rateLimit = getRateLimit();
|
||||
}
|
||||
return rateLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link GHUser} that represents yourself.
|
||||
*/
|
||||
@@ -416,7 +467,6 @@ public class GitHub {
|
||||
*
|
||||
* @param key The license key provided from the API
|
||||
* @return The license details
|
||||
* @throws IOException
|
||||
* @see GHLicense#getKey()
|
||||
*/
|
||||
@Preview @Deprecated
|
||||
@@ -652,8 +702,18 @@ public class GitHub {
|
||||
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
|
||||
X-Content-Type-Options: nosniff
|
||||
*/
|
||||
return uc.getResponseCode() == HTTP_UNAUTHORIZED
|
||||
&& uc.getHeaderField("X-GitHub-Media-Type") != null;
|
||||
try {
|
||||
return uc.getResponseCode() == HTTP_UNAUTHORIZED
|
||||
&& uc.getHeaderField("X-GitHub-Media-Type") != null;
|
||||
} finally {
|
||||
// ensure that the connection opened by getResponseCode gets closed
|
||||
try {
|
||||
IOUtils.closeQuietly(uc.getInputStream());
|
||||
} catch (IOException ignore) {
|
||||
// ignore
|
||||
}
|
||||
IOUtils.closeQuietly(uc.getErrorStream());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Iterator over a pagenated data source.
|
||||
* Iterator over a paginated data source.
|
||||
*
|
||||
* Aside from the normal iterator operation, this method exposes {@link #nextPage()}
|
||||
* that allows the caller to retrieve items per page.
|
||||
|
||||
@@ -7,4 +7,5 @@ package org.kohsuke.github;
|
||||
static final String LOKI = "application/vnd.github.loki-preview+json";
|
||||
static final String DRAX = "application/vnd.github.drax-preview+json";
|
||||
static final String SQUIRREL_GIRL = "application/vnd.github.squirrel-girl-preview";
|
||||
static final String KORRA = "application/vnd.github.korra-preview";
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@ package org.kohsuke.github;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -38,10 +36,12 @@ import java.lang.reflect.Field;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -53,12 +53,14 @@ import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.annotation.WillClose;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.logging.Level.FINE;
|
||||
import static org.kohsuke.github.GitHub.*;
|
||||
import java.util.logging.Level;
|
||||
import static java.util.logging.Level.*;
|
||||
import static org.kohsuke.github.GitHub.MAPPER;
|
||||
|
||||
/**
|
||||
* A builder pattern for making HTTP call and parsing its output.
|
||||
@@ -281,6 +283,8 @@ class Requester {
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
handleApiError(e);
|
||||
} finally {
|
||||
noteRateLimit(tailApiUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,6 +303,8 @@ class Requester {
|
||||
return uc.getResponseCode();
|
||||
} catch (IOException e) {
|
||||
handleApiError(e);
|
||||
} finally {
|
||||
noteRateLimit(tailApiUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -313,6 +319,59 @@ class Requester {
|
||||
return wrapStream(uc.getInputStream());
|
||||
} catch (IOException e) {
|
||||
handleApiError(e);
|
||||
} finally {
|
||||
noteRateLimit(tailApiUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void noteRateLimit(String tailApiUrl) {
|
||||
if ("/rate_limit".equals(tailApiUrl)) {
|
||||
// the rate_limit API is "free"
|
||||
return;
|
||||
}
|
||||
if (tailApiUrl.startsWith("/search")) {
|
||||
// the search API uses a different rate limit
|
||||
return;
|
||||
}
|
||||
String limit = uc.getHeaderField("X-RateLimit-Limit");
|
||||
if (StringUtils.isBlank(limit)) {
|
||||
// if we are missing a header, return fast
|
||||
return;
|
||||
}
|
||||
String remaining = uc.getHeaderField("X-RateLimit-Remaining");
|
||||
if (StringUtils.isBlank(remaining)) {
|
||||
// if we are missing a header, return fast
|
||||
return;
|
||||
}
|
||||
String reset = uc.getHeaderField("X-RateLimit-Reset");
|
||||
if (StringUtils.isBlank(reset)) {
|
||||
// if we are missing a header, return fast
|
||||
return;
|
||||
}
|
||||
GHRateLimit observed = new GHRateLimit();
|
||||
try {
|
||||
observed.limit = Integer.parseInt(limit);
|
||||
} catch (NumberFormatException e) {
|
||||
if (LOGGER.isLoggable(FINEST)) {
|
||||
LOGGER.log(FINEST, "Malformed X-RateLimit-Limit header value " + limit, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
observed.remaining = Integer.parseInt(remaining);
|
||||
} catch (NumberFormatException e) {
|
||||
if (LOGGER.isLoggable(FINEST)) {
|
||||
LOGGER.log(FINEST, "Malformed X-RateLimit-Remaining header value " + remaining, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
observed.reset = new Date(Long.parseLong(reset)); // this is madness, storing the date as seconds
|
||||
root.updateRateLimit(observed);
|
||||
} catch (NumberFormatException e) {
|
||||
if (LOGGER.isLoggable(FINEST)) {
|
||||
LOGGER.log(FINEST, "Malformed X-RateLimit-Reset header value " + reset, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -355,7 +414,7 @@ class Requester {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads pagenated resources.
|
||||
* Loads paginated resources.
|
||||
*
|
||||
* Every iterator call reports a new batch.
|
||||
*/
|
||||
@@ -382,7 +441,7 @@ class Requester {
|
||||
}
|
||||
|
||||
try {
|
||||
return new PagingIterator<T>(type, root.getApiURL(s.toString()));
|
||||
return new PagingIterator<T>(type, tailApiUrl, root.getApiURL(s.toString()));
|
||||
} catch (IOException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
@@ -391,6 +450,7 @@ class Requester {
|
||||
class PagingIterator<T> implements Iterator<T> {
|
||||
|
||||
private final Class<T> type;
|
||||
private final String tailApiUrl;
|
||||
|
||||
/**
|
||||
* The next batch to be returned from {@link #next()}.
|
||||
@@ -402,9 +462,10 @@ class Requester {
|
||||
*/
|
||||
private URL url;
|
||||
|
||||
PagingIterator(Class<T> type, URL url) {
|
||||
this.url = url;
|
||||
PagingIterator(Class<T> type, String tailApiUrl, URL url) {
|
||||
this.type = type;
|
||||
this.tailApiUrl = tailApiUrl;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
@@ -438,6 +499,8 @@ class Requester {
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
handleApiError(e);
|
||||
} finally {
|
||||
noteRateLimit(tailApiUrl);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -518,6 +581,10 @@ class Requester {
|
||||
}
|
||||
|
||||
private <T> T parse(Class<T> type, T instance) throws IOException {
|
||||
return parse(type, instance, 2);
|
||||
}
|
||||
|
||||
private <T> T parse(Class<T> type, T instance, int timeouts) throws IOException {
|
||||
InputStreamReader r = null;
|
||||
int responseCode = -1;
|
||||
String responseMessage = null;
|
||||
@@ -548,6 +615,10 @@ class Requester {
|
||||
// to preserve backward compatibility
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
if (e instanceof SocketTimeoutException && timeouts > 0) {
|
||||
LOGGER.log(Level.INFO, "timed out accessing " + uc.getURL() + "; will try " + timeouts + " more time(s)", e);
|
||||
return parse(type, instance, timeouts - 1);
|
||||
}
|
||||
throw new HttpException(responseCode, responseMessage, uc.getURL(), e);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(r);
|
||||
@@ -580,6 +651,24 @@ class Requester {
|
||||
" handling exception " + e, e);
|
||||
throw e;
|
||||
}
|
||||
InputStream es = wrapStream(uc.getErrorStream());
|
||||
if (es != null) {
|
||||
try {
|
||||
String error = IOUtils.toString(es, "UTF-8");
|
||||
if (e instanceof FileNotFoundException) {
|
||||
// pass through 404 Not Found to allow the caller to handle it intelligently
|
||||
e = (IOException) new FileNotFoundException(error).initCause(e);
|
||||
} else if (e instanceof HttpException) {
|
||||
HttpException http = (HttpException) e;
|
||||
e = new HttpException(error, http.getResponseCode(), http.getResponseMessage(),
|
||||
http.getUrl(), e);
|
||||
} else {
|
||||
e = (IOException) new IOException(error).initCause(e);
|
||||
}
|
||||
} finally {
|
||||
IOUtils.closeQuietly(es);
|
||||
}
|
||||
}
|
||||
if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) // 401 / Unauthorized == bad creds
|
||||
throw e;
|
||||
|
||||
@@ -595,19 +684,7 @@ class Requester {
|
||||
return;
|
||||
}
|
||||
|
||||
InputStream es = wrapStream(uc.getErrorStream());
|
||||
try {
|
||||
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);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
private static final List<String> METHODS_WITHOUT_BODY = asList("GET", "DELETE");
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.kohsuke.randname.RandomNameGenerator;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Kohsuke Kawaguchi
|
||||
@@ -25,5 +27,18 @@ public abstract class AbstractGitHubApiTestBase extends Assert {
|
||||
}
|
||||
}
|
||||
|
||||
protected GHUser getUser() {
|
||||
try {
|
||||
return gitHub.getMyself();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void kohsuke() {
|
||||
String login = getUser().getLogin();
|
||||
Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
|
||||
}
|
||||
|
||||
protected static final RandomNameGenerator rnd = new RandomNameGenerator();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.kohsuke.github.GHCommit.File;
|
||||
import org.kohsuke.github.GHOrganization.Permission;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
@@ -172,14 +173,6 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
return repository;
|
||||
}
|
||||
|
||||
private GHUser getUser() {
|
||||
try {
|
||||
return gitHub.getMyself();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListIssues() throws IOException {
|
||||
GHUser u = getUser();
|
||||
@@ -362,6 +355,11 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
assertEquals(48,f.getLinesChanged());
|
||||
assertEquals("modified",f.getStatus());
|
||||
assertEquals("changelog.html", f.getFileName());
|
||||
|
||||
// walk the tree
|
||||
GHTree t = commit.getTree();
|
||||
assertThat(IOUtils.toString(t.getEntry("todo.txt").readAsBlob()), containsString("executor rendering"));
|
||||
assertNotNull(t.getEntry("war").asTree());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -903,8 +901,23 @@ public class AppTest extends AbstractGitHubApiTestBase {
|
||||
}
|
||||
}
|
||||
|
||||
private void kohsuke() {
|
||||
String login = getUser().getLogin();
|
||||
Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
|
||||
@Test
|
||||
public void blob() throws Exception {
|
||||
GHRepository r = gitHub.getRepository("kohsuke/github-api");
|
||||
String sha1 = "a12243f2fc5b8c2ba47dd677d0b0c7583539584d";
|
||||
|
||||
assertBlobContent(r.readBlob(sha1));
|
||||
|
||||
GHBlob blob = r.getBlob(sha1);
|
||||
assertBlobContent(blob.read());
|
||||
assertThat(blob.getSha(),is("a12243f2fc5b8c2ba47dd677d0b0c7583539584d"));
|
||||
assertThat(blob.getSize(),is(1104L));
|
||||
}
|
||||
|
||||
private void assertBlobContent(InputStream is) throws Exception {
|
||||
String content = new String(IOUtils.toByteArray(is),"UTF-8");
|
||||
assertThat(content,containsString("Copyright (c) 2011- Kohsuke Kawaguchi and other contributors"));
|
||||
assertThat(content,containsString("FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR"));
|
||||
assertThat(content.length(),is(1104));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.kohsuke.github;
|
||||
import org.junit.Test;
|
||||
import org.kohsuke.github.GHRepository.Contributor;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@@ -40,6 +41,33 @@ public class RepositoryTest extends AbstractGitHubApiTestBase {
|
||||
assertTrue(kohsuke);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPermission() throws Exception {
|
||||
kohsuke();
|
||||
GHRepository r = gitHub.getRepository("github-api-test-org/test-permission");
|
||||
assertEquals(GHPermissionType.ADMIN, r.getPermission("kohsuke"));
|
||||
assertEquals(GHPermissionType.READ, r.getPermission("dude"));
|
||||
r = gitHub.getOrganization("apache").getRepository("groovy");
|
||||
try {
|
||||
r.getPermission("jglick");
|
||||
fail();
|
||||
} catch (HttpException x) {
|
||||
x.printStackTrace(); // good
|
||||
assertEquals(403, x.getResponseCode());
|
||||
}
|
||||
|
||||
if (false) {
|
||||
// can't easily test this; there's no private repository visible to the test user
|
||||
r = gitHub.getOrganization("cloudbees").getRepository("private-repo-not-writable-by-me");
|
||||
try {
|
||||
r.getPermission("jglick");
|
||||
fail();
|
||||
} catch (FileNotFoundException x) {
|
||||
x.printStackTrace(); // good
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GHRepository getRepository() throws IOException {
|
||||
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
|
||||
}
|
||||
|
||||
@@ -65,8 +65,7 @@
|
||||
"issues_url": "https://api.github.com/repos/baxterandthehackers/public-repo/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/baxterandthehackers/public-repo/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/baxterandthehackers/public-repo/notifications{?since,all,
|
||||
participating}",
|
||||
"notifications_url": "https://api.github.com/repos/baxterandthehackers/public-repo/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/baxterandthehackers/public-repo/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/baxterandthehackers/public-repo/releases{/id}",
|
||||
"deployments_url": "https://api.github.com/repos/baxterandthehackers/public-repo/deployments",
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
"action": "created",
|
||||
"milestone": {
|
||||
"url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones/3",
|
||||
"html_url": "https://github.com/baxterandthehackers/public-repo/milestones/Test%20milestone%20creation%20webhook
|
||||
%20from%20command%20line2",
|
||||
"html_url": "https://github.com/baxterandthehackers/public-repo/milestones/Test%20milestone%20creation%20webhook%20from%20command%20line2",
|
||||
"labels_url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones/3/labels",
|
||||
"id": 2055681,
|
||||
"number": 3,
|
||||
@@ -96,8 +95,7 @@
|
||||
"issues_url": "https://api.github.com/repos/baxterandthehackers/public-repo/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/baxterandthehackers/public-repo/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/baxterandthehackers/public-repo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/baxterandthehackers/public-repo/notifications{?since,all,
|
||||
participating}",
|
||||
"notifications_url": "https://api.github.com/repos/baxterandthehackers/public-repo/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/baxterandthehackers/public-repo/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/baxterandthehackers/public-repo/releases{/id}",
|
||||
"deployments_url": "https://api.github.com/repos/baxterandthehackers/public-repo/deployments",
|
||||
|
||||
Reference in New Issue
Block a user