Compare commits

...

16 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
13184e72e1 [maven-release-plugin] prepare release github-api-1.83 2017-01-09 16:37:56 -08:00
Kohsuke Kawaguchi
911e8d21a7 Made the test case runnable, at least for me 2017-01-09 16:26:58 -08:00
Kohsuke Kawaguchi
5b69a2925f Merge pull request #324 2017-01-09 16:18:48 -08:00
Kohsuke Kawaguchi
d1c900a620 Marking the fact that these APIs are still in preview and subject to change 2017-01-09 16:18:40 -08:00
Kohsuke Kawaguchi
6bfeb54f3c Just exposing permission type enum until there's more to this relation than one property 2017-01-09 16:14:30 -08:00
Kohsuke Kawaguchi
198fede915 Merge pull request #325 2017-01-09 16:06:14 -08:00
Kohsuke Kawaguchi
1212ae3eb3 Touch up for uniformity
- Prefer typed 'URL' over 'String' that is URL
- Mark API as @Preview to communicate that this is subject to change

More branch protection stuff needs to be added. See https://developer.github.com/v3/repos/branches/
2017-01-09 16:06:05 -08:00
Kohsuke Kawaguchi
1266dcc0c7 Merge pull request #327 from stephenc/expose-rate-limit-headers
Expose Rate Limit Headers
2017-01-10 08:57:07 +09:00
Stephen Connolly
6fcddf4a47 Some usage patterns require more pro-active rate limit queries 2017-01-05 10:25:40 +00:00
Stephen Connolly
dfea424b94 Expose the API url used by the GitHub 2017-01-05 09:36:58 +00:00
Stephen Connolly
9d03435aa1 Expose Rate Limit Headers
Exposes the rate limit header responses so that consumers of the API can proactively tune their usage
2017-01-05 09:21:32 +00:00
Jeffrey.Nelson
26c20a7a22 add branch protection attributes 2016-12-22 11:55:01 -06:00
Kohsuke Kawaguchi
470da06ecf Cleaning up javadoc warnings 2016-12-17 08:17:20 -08:00
Kohsuke Kawaguchi
a746a310bc [maven-release-plugin] prepare for next development iteration 2016-12-17 07:50:55 -08:00
Jesse Glick
ccb42d3249 [JENKINS-36240] Added GHRepository.getPermission(String). 2016-12-16 18:02:28 -05:00
Jeff Nelson
9d15cd43a3 Merge pull request #1 from kohsuke/master
catchup
2016-12-14 12:12:57 -06:00
14 changed files with 317 additions and 55 deletions

View File

@@ -3,11 +3,11 @@
<parent> <parent>
<groupId>org.kohsuke</groupId> <groupId>org.kohsuke</groupId>
<artifactId>pom</artifactId> <artifactId>pom</artifactId>
<version>14</version> <version>17</version>
</parent> </parent>
<artifactId>github-api</artifactId> <artifactId>github-api</artifactId>
<version>1.82</version> <version>1.83</version>
<name>GitHub API for Java</name> <name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url> <url>http://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description> <description>GitHub API for Java</description>
@@ -16,7 +16,7 @@
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection> <connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection> <developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
<url>http://${project.artifactId}.kohsuke.org/</url> <url>http://${project.artifactId}.kohsuke.org/</url>
<tag>github-api-1.82</tag> <tag>github-api-1.83</tag>
</scm> </scm>
<distributionManagement> <distributionManagement>

View File

@@ -1,13 +1,17 @@
package org.kohsuke.github; package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import static org.kohsuke.github.Previews.LOKI;
import org.kohsuke.github.BranchProtection.RequiredStatusChecks;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; 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. * A branch in a repository.
@@ -22,6 +26,10 @@ public class GHBranch {
private String name; private String name;
private Commit commit; private Commit commit;
@JsonProperty("protected")
private boolean protection;
private String protection_url;
public static class Commit { public static class Commit {
String sha; String sha;
@@ -45,6 +53,23 @@ public class GHBranch {
return name; 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. * The commit that this branch currently points to.
*/ */

View 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;
}
}
}

View File

@@ -0,0 +1,11 @@
package org.kohsuke.github;
/**
* @author Kohsuke Kawaguchi
*/
public enum GHPermissionType {
ADMIN,
WRITE,
READ,
NONE
}

View File

@@ -121,9 +121,7 @@ public class GHRelease extends GHObject {
* Java 7 or greater. Options for fixing this for earlier JVMs can be found here * 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 * http://stackoverflow.com/questions/12361090/server-name-indication-sni-on-java but involve more complicated
* handling of the HTTP requests to github's API. * handling of the HTTP requests to github's API.
* */
* @throws IOException
*/
public GHAsset uploadAsset(File file, String contentType) throws IOException { public GHAsset uploadAsset(File file, String contentType) throws IOException {
Requester builder = new Requester(owner.root); Requester builder = new Requester(owner.root);

View File

@@ -33,7 +33,6 @@ public class GHReleaseBuilder {
* *
* @param commitish Defaults to the repositorys default branch (usually "master"). Unused if the Git tag * @param commitish Defaults to the repositorys default branch (usually "master"). Unused if the Git tag
* already exists. * already exists.
* @return
*/ */
public GHReleaseBuilder commitish(String commitish) { public GHReleaseBuilder commitish(String commitish) {
if (commitish != null) { if (commitish != null) {

View File

@@ -449,7 +449,6 @@ public class GHRepository extends GHObject {
* Lists up the collaborators on this repository. * Lists up the collaborators on this repository.
* *
* @return Users * @return Users
* @throws IOException
*/ */
public PagedIterable<GHUser> listCollaborators() throws IOException { public PagedIterable<GHUser> listCollaborators() throws IOException {
return listUsers("collaborators"); return listUsers("collaborators");
@@ -481,6 +480,29 @@ public class GHRepository extends GHObject {
return r; 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. * If this repository belongs to an organization, return a set of teams.
*/ */
@@ -818,7 +840,7 @@ public class GHRepository extends GHObject {
} }
/** /**
* Obtains the metadata & the content of a blob. * Obtains the metadata &amp; the content of a blob.
* *
* <p> * <p>
* This method retrieves the whole content in memory, so beware when you are dealing with large BLOB. * This method retrieves the whole content in memory, so beware when you are dealing with large BLOB.

View File

@@ -30,7 +30,6 @@ public class GHTree {
/** /**
* Return an array of entries of the trees * Return an array of entries of the trees
* @return
*/ */
public List<GHTreeEntry> getTree() { public List<GHTreeEntry> getTree() {
return Collections.unmodifiableList(Arrays.asList(tree)); return Collections.unmodifiableList(Arrays.asList(tree));

View File

@@ -23,12 +23,10 @@
*/ */
package org.kohsuke.github; package org.kohsuke.github;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY; import com.fasterxml.jackson.databind.DeserializationFeature;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE; import com.fasterxml.jackson.databind.ObjectMapper;
import static java.util.logging.Level.FINE; import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std;
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import static org.kohsuke.github.Previews.DRAX;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@@ -49,17 +47,19 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import org.apache.commons.codec.Charsets; import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import com.fasterxml.jackson.databind.DeserializationFeature; import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import com.fasterxml.jackson.databind.ObjectMapper; import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std; import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import static java.util.logging.Level.FINE;
import static org.kohsuke.github.Previews.DRAX;
import javax.annotation.Nonnull;
import java.util.logging.Logger;
/** /**
* Root of the GitHub API. * Root of the GitHub API.
@@ -90,6 +90,10 @@ public class GitHub {
private HttpConnector connector = HttpConnector.DEFAULT; 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. * Creates a client API root object.
* *
@@ -254,6 +258,10 @@ public class GitHub {
return connector; return connector;
} }
public String getApiUrl() {
return apiUrl;
}
/** /**
* Sets the custom connector used to make requests to GitHub. * Sets the custom connector used to make requests to GitHub.
*/ */
@@ -287,19 +295,63 @@ public class GitHub {
*/ */
public GHRateLimit getRateLimit() throws IOException { public GHRateLimit getRateLimit() throws IOException {
try { try {
return retrieve().to("/rate_limit", JsonRateLimit.class).rate; return rateLimit = retrieve().to("/rate_limit", JsonRateLimit.class).rate;
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
// GitHub Enterprise doesn't have the rate limit, so in that case // GitHub Enterprise doesn't have the rate limit, so in that case
// return some big number that's not too big. // return some big number that's not too big.
// see issue #78 // see issue #78
GHRateLimit r = new GHRateLimit(); GHRateLimit r = new GHRateLimit();
r.limit = r.remaining = 1000000; r.limit = r.remaining = 1000000;
long hours = 1000L * 60 * 60; long hour = 60L * 60L; // this is madness, storing the date as seconds in a Date object
r.reset = new Date(System.currentTimeMillis() + 1 * hours ); r.reset = new Date((System.currentTimeMillis() + hour) / 1000L );
return r; 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(Level.INFO, "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. * Gets the {@link GHUser} that represents yourself.
*/ */
@@ -416,7 +468,6 @@ public class GitHub {
* *
* @param key The license key provided from the API * @param key The license key provided from the API
* @return The license details * @return The license details
* @throws IOException
* @see GHLicense#getKey() * @see GHLicense#getKey()
*/ */
@Preview @Deprecated @Preview @Deprecated

View File

@@ -7,4 +7,5 @@ package org.kohsuke.github;
static final String LOKI = "application/vnd.github.loki-preview+json"; static final String LOKI = "application/vnd.github.loki-preview+json";
static final String DRAX = "application/vnd.github.drax-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 SQUIRREL_GIRL = "application/vnd.github.squirrel-girl-preview";
static final String KORRA = "application/vnd.github.korra-preview";
} }

View File

@@ -25,8 +25,6 @@ package org.kohsuke.github;
import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonMappingException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.io.IOUtils;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -42,6 +40,7 @@ import java.net.URL;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -49,16 +48,18 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import javax.annotation.WillClose; 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.Arrays.asList;
import static java.util.logging.Level.FINE; import static java.util.logging.Level.FINE;
import static org.kohsuke.github.GitHub.*; import static org.kohsuke.github.GitHub.MAPPER;
/** /**
* A builder pattern for making HTTP call and parsing its output. * A builder pattern for making HTTP call and parsing its output.
@@ -281,6 +282,8 @@ class Requester {
return result; return result;
} catch (IOException e) { } catch (IOException e) {
handleApiError(e); handleApiError(e);
} finally {
noteRateLimit(tailApiUrl);
} }
} }
} }
@@ -299,6 +302,8 @@ class Requester {
return uc.getResponseCode(); return uc.getResponseCode();
} catch (IOException e) { } catch (IOException e) {
handleApiError(e); handleApiError(e);
} finally {
noteRateLimit(tailApiUrl);
} }
} }
} }
@@ -313,6 +318,59 @@ class Requester {
return wrapStream(uc.getInputStream()); return wrapStream(uc.getInputStream());
} catch (IOException e) { } catch (IOException e) {
handleApiError(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(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Malformed X-RateLimit-Limit header value " + limit, e);
}
return;
}
try {
observed.remaining = Integer.parseInt(remaining);
} catch (NumberFormatException e) {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.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(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Malformed X-RateLimit-Reset header value " + reset, e);
} }
} }
} }
@@ -382,7 +440,7 @@ class Requester {
} }
try { try {
return new PagingIterator<T>(type, root.getApiURL(s.toString())); return new PagingIterator<T>(type, tailApiUrl, root.getApiURL(s.toString()));
} catch (IOException e) { } catch (IOException e) {
throw new Error(e); throw new Error(e);
} }
@@ -391,6 +449,7 @@ class Requester {
class PagingIterator<T> implements Iterator<T> { class PagingIterator<T> implements Iterator<T> {
private final Class<T> type; private final Class<T> type;
private final String tailApiUrl;
/** /**
* The next batch to be returned from {@link #next()}. * The next batch to be returned from {@link #next()}.
@@ -402,9 +461,10 @@ class Requester {
*/ */
private URL url; private URL url;
PagingIterator(Class<T> type, URL url) { PagingIterator(Class<T> type, String tailApiUrl, URL url) {
this.url = url;
this.type = type; this.type = type;
this.tailApiUrl = tailApiUrl;
this.url = url;
} }
public boolean hasNext() { public boolean hasNext() {
@@ -438,6 +498,8 @@ class Requester {
return; return;
} catch (IOException e) { } catch (IOException e) {
handleApiError(e); handleApiError(e);
} finally {
noteRateLimit(tailApiUrl);
} }
} }
} catch (IOException e) { } catch (IOException e) {
@@ -598,11 +660,16 @@ class Requester {
InputStream es = wrapStream(uc.getErrorStream()); InputStream es = wrapStream(uc.getErrorStream());
try { try {
if (es!=null) { if (es!=null) {
String error = IOUtils.toString(es, "UTF-8");
if (e instanceof FileNotFoundException) { if (e instanceof FileNotFoundException) {
// pass through 404 Not Found to allow the caller to handle it intelligently // pass through 404 Not Found to allow the caller to handle it intelligently
throw (IOException) new FileNotFoundException(IOUtils.toString(es, "UTF-8")).initCause(e); throw (IOException) new FileNotFoundException(error).initCause(e);
} else } else if (e instanceof HttpException) {
throw (IOException) new IOException(IOUtils.toString(es, "UTF-8")).initCause(e); HttpException http = (HttpException) e;
throw (IOException) new HttpException(error, http.getResponseCode(), http.getResponseMessage(), http.getUrl(), e);
} else {
throw (IOException) new IOException(error).initCause(e);
}
} else } else
throw e; throw e;
} finally { } finally {

View File

@@ -1,10 +1,12 @@
package org.kohsuke.github; package org.kohsuke.github;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before; import org.junit.Before;
import org.kohsuke.randname.RandomNameGenerator; import org.kohsuke.randname.RandomNameGenerator;
import java.io.File; import java.io.File;
import java.io.IOException;
/** /**
* @author Kohsuke Kawaguchi * @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(); protected static final RandomNameGenerator rnd = new RandomNameGenerator();
} }

View File

@@ -173,14 +173,6 @@ public class AppTest extends AbstractGitHubApiTestBase {
return repository; return repository;
} }
private GHUser getUser() {
try {
return gitHub.getMyself();
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@Test @Test
public void testListIssues() throws IOException { public void testListIssues() throws IOException {
GHUser u = getUser(); GHUser u = getUser();
@@ -928,9 +920,4 @@ public class AppTest extends AbstractGitHubApiTestBase {
assertThat(content,containsString("FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR")); assertThat(content,containsString("FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR"));
assertThat(content.length(),is(1104)); assertThat(content.length(),is(1104));
} }
private void kohsuke() {
String login = getUser().getLogin();
Assume.assumeTrue(login.equals("kohsuke") || login.equals("kohsuke2"));
}
} }

View File

@@ -3,6 +3,7 @@ package org.kohsuke.github;
import org.junit.Test; import org.junit.Test;
import org.kohsuke.github.GHRepository.Contributor; import org.kohsuke.github.GHRepository.Contributor;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
/** /**
@@ -40,6 +41,33 @@ public class RepositoryTest extends AbstractGitHubApiTestBase {
assertTrue(kohsuke); 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 { private GHRepository getRepository() throws IOException {
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins"); return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");
} }