From 54c3070607fb1957c89aa224cdf99f3445311379 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Mon, 29 Feb 2016 21:03:34 -0800 Subject: [PATCH 01/25] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 05d286b718..0af43488f1 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.73 + 1.74-SNAPSHOT GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java @@ -16,7 +16,7 @@ scm:git:git@github.com/kohsuke/${project.artifactId}.git scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git http://${project.artifactId}.kohsuke.org/ - github-api-1.73 + HEAD From dbc79f8c423749311495cb548c1a9cda1d8638cf Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Tue, 1 Mar 2016 19:46:50 -0800 Subject: [PATCH 02/25] Fixing issue raised in https://github.com/kohsuke/github-api/pull/247 From Shredder121, -------------------- Only the HttpURLConnection.method was set by that change. Not the Requester.method. This means that Requester.method is still set to POST, isMethodWithBody will return true, and uc.setDoOutput(true) will be called. I use Okhttp, and their HttpURLConnectionImpl's method changes to POST if you tell it to open a stream to write to. --- src/main/java/org/kohsuke/github/Requester.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index c9835677ea..af4819c3a1 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -264,10 +264,9 @@ private T _to(String tailApiUrl, Class type, T instance) throws IOExcepti */ public int asHttpStatusCode(String tailApiUrl) throws IOException { while (true) {// loop while API rate limit is hit + method("GET"); setupConnection(root.getApiURL(tailApiUrl)); - uc.setRequestMethod("GET"); - buildRequest(); try { @@ -280,12 +279,10 @@ public int asHttpStatusCode(String tailApiUrl) throws IOException { public InputStream asStream(String tailApiUrl) throws IOException { while (true) {// loop while API rate limit is hit + method("GET"); // if the download link is encoded with a token on the query string, the default behavior of POST will fail setupConnection(root.getApiURL(tailApiUrl)); - // if the download link is encoded with a token on the query string, the default behavior of POST will fail - uc.setRequestMethod("GET"); - - buildRequest(); + buildRequest(); try { return wrapStream(uc.getInputStream()); From ae85cf4b6c02ba9c330d436bbee39d211428755d Mon Sep 17 00:00:00 2001 From: Manuel Recena Date: Sat, 5 Mar 2016 17:42:25 +0100 Subject: [PATCH 03/25] Improve checkApiUrlValidity() method to support the private mode in GitHub Enterprise servers --- src/main/java/org/kohsuke/github/GitHub.java | 30 ++++++++++++++++++- .../java/org/kohsuke/github/GitHubTest.java | 7 ++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 77d178800c..14e7b13368 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -31,6 +31,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; +import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.text.ParseException; @@ -482,7 +483,34 @@ void check(String apiUrl) throws IOException { * Otherwise this method throws {@link IOException} to indicate the problem. */ public void checkApiUrlValidity() throws IOException { - retrieve().to("/", GHApiInfo.class).check(apiUrl); + try { + retrieve().to("/", GHApiInfo.class).check(apiUrl); + } catch (IOException ioe) { + if (isPrivateModeEnabled()) { + throw new IOException("GitHub Enterprise server (" + apiUrl + ") with private mode enabled"); + } + throw ioe; + } + } + + /** + * Ensures if a GitHub Enterprise server is configured in private mode. + * + * @return {@code true} if private mode is enabled. If it tries to use this method with GitHub, returns {@code + * false}. + */ + private boolean isPrivateModeEnabled() { + try { + HttpURLConnection connect = getConnector().connect(getApiURL("/")); + if (connect.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED + && connect.getHeaderField("Server") != null + && connect.getHeaderField("Server").equals("GitHub.com")) { + return true; + } + return false; + } catch (IOException e) { + return false; + } } /** diff --git a/src/test/java/org/kohsuke/github/GitHubTest.java b/src/test/java/org/kohsuke/github/GitHubTest.java index 1663d24144..b8ae4ff0df 100644 --- a/src/test/java/org/kohsuke/github/GitHubTest.java +++ b/src/test/java/org/kohsuke/github/GitHubTest.java @@ -124,6 +124,11 @@ public void testGitHubEnterpriseDoesNotHaveRateLimit() throws IOException { @Test public void testGitHubIsApiUrlValid() throws IOException { GitHub github = GitHub.connectAnonymously(); - github.checkApiUrlValidity(); + //GitHub github = GitHub.connectToEnterpriseAnonymously("https://github.mycompany.com/api/v3/"); + try { + github.checkApiUrlValidity(); + } catch (IOException ioe) { + assertTrue(ioe.getMessage().contains("private mode enabled")); + } } } From ba951cb6e301a56c673f00395e08e87d80422da3 Mon Sep 17 00:00:00 2001 From: Cyrille Le Clerc Date: Sun, 6 Mar 2016 18:09:36 +0100 Subject: [PATCH 04/25] Fix #252: infinite loop because the "hypertext engine" may duplicate '?' generating invalid "https://api.github.com/notifications?all=true&page=2?all=true" instead of "https://api.github.com/notifications?all=true&page=2&all=true". A better fix will be to prevent duplication of parameters ("all=true" in this case). --- .../java/org/kohsuke/github/Requester.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index af4819c3a1..5096f5ff49 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -45,6 +45,7 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; +import java.util.ListIterator; import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; @@ -219,15 +220,19 @@ public T to(String tailApiUrl, Class type, String method) throws IOExcept } private T _to(String tailApiUrl, Class type, T instance) throws IOException { - while (true) {// loop while API rate limit is hit - if (METHODS_WITHOUT_BODY.contains(method) && !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")); + if (METHODS_WITHOUT_BODY.contains(method) && !args.isEmpty()) { + boolean questionMarkFound = tailApiUrl.indexOf('?') != -1; + tailApiUrl += questionMarkFound ? '&' : '?'; + for (Iterator it = args.listIterator(); it.hasNext();) { + Entry arg = it.next(); + tailApiUrl += arg.key + '=' + URLEncoder.encode(arg.value.toString(),"UTF-8"); + if (it.hasNext()) { + tailApiUrl += '&'; } - tailApiUrl += qs.toString(); } + } + + while (true) {// loop while API rate limit is hit setupConnection(root.getApiURL(tailApiUrl)); buildRequest(); From 027e4b4f25390627b1ccc386e688246d07a2016d Mon Sep 17 00:00:00 2001 From: Cyrille Le Clerc Date: Sun, 6 Mar 2016 16:11:56 +0100 Subject: [PATCH 05/25] Better error message: introduce HttpException, subclass of IOException with url, http responseCode and http responseMessage to help exception handling. --- pom.xml | 8 ++ src/main/java/org/kohsuke/github/GitHub.java | 6 + .../org/kohsuke/github/HttpException.java | 119 ++++++++++++++++++ .../java/org/kohsuke/github/Requester.java | 28 ++++- 4 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/kohsuke/github/HttpException.java diff --git a/pom.xml b/pom.xml index 0af43488f1..dde789075d 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,14 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + org.codehaus.mojo findbugs-maven-plugin diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 77d178800c..fe94840fda 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -31,6 +31,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; +import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.text.ParseException; @@ -55,6 +56,8 @@ import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import java.nio.charset.Charset; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Root of the GitHub API. @@ -68,6 +71,8 @@ * @author Kohsuke Kawaguchi */ public class GitHub { + protected final transient Logger logger = Logger.getLogger(getClass().getName()); + /*package*/ final String login; /** @@ -458,6 +463,7 @@ public boolean isCredentialValid() throws IOException { retrieve().to("/user", GHUser.class); return true; } catch (IOException e) { + logger.log(Level.FINEST, "Exception validating credentials on {0} with login {1}: {2}", new Object[]{this.apiUrl, this.login, e, e}); return false; } } diff --git a/src/main/java/org/kohsuke/github/HttpException.java b/src/main/java/org/kohsuke/github/HttpException.java new file mode 100644 index 0000000000..37c16f4a12 --- /dev/null +++ b/src/main/java/org/kohsuke/github/HttpException.java @@ -0,0 +1,119 @@ +package org.kohsuke.github; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * Http exception + * + * @author Cyrille Le Clerc + */ +public class HttpException extends IOException { + static final long serialVersionUID = 1L; + + private final int responseCode; + private final String responseMessage; + private final String url; + + /** + * @param message The detail message (which is saved for later retrieval + * by the {@link #getMessage()} method) + * @param responseCode Http response code. {@code -1} if no code can be discerned. + * @param responseMessage Http response message + * @param url The url that was invoked + * @see HttpURLConnection#getResponseCode() + * @see HttpURLConnection#getResponseMessage() + */ + public HttpException(String message, int responseCode, String responseMessage, String url) { + super(message); + this.responseCode = responseCode; + this.responseMessage = responseMessage; + this.url = url; + } + + /** + * @param message The detail message (which is saved for later retrieval + * by the {@link #getMessage()} method) + * @param responseCode Http response code. {@code -1} if no code can be discerned. + * @param responseMessage Http response message + * @param url The url that was invoked + * @param cause The cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is permitted, + * and indicates that the cause is nonexistent or unknown.) + * @see HttpURLConnection#getResponseCode() + * @see HttpURLConnection#getResponseMessage() + */ + public HttpException(String message, int responseCode, String responseMessage, String url, Throwable cause) { + super(message, cause); + this.responseCode = responseCode; + this.responseMessage = responseMessage; + this.url = url; + } + + /** + * @param message The detail message (which is saved for later retrieval + * by the {@link #getMessage()} method) + * @param responseCode Http response code. {@code -1} if no code can be discerned. + * @param responseMessage Http response message + * @param url The url that was invoked + * @param cause The cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is permitted, + * and indicates that the cause is nonexistent or unknown.) + * @see HttpURLConnection#getResponseCode() + * @see HttpURLConnection#getResponseMessage() + */ + public HttpException(int responseCode, String responseMessage, String url, Throwable cause) { + super("Server returned HTTP response code: " + responseCode + ", message: '" + responseMessage + "'" + + " for URL: " + url, cause); + this.responseCode = responseCode; + this.responseMessage = responseMessage; + this.url = url; + } + + /** + * @param responseCode Http response code. {@code -1} if no code can be discerned. + * @param responseMessage Http response message + * @param url The url that was invoked + * @param cause The cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is permitted, + * and indicates that the cause is nonexistent or unknown.) + * @see HttpURLConnection#getResponseCode() + * @see HttpURLConnection#getResponseMessage() + */ + public HttpException(int responseCode, String responseMessage, URL url, Throwable cause) { + this(responseCode, responseMessage, url == null ? null : url.toString(), cause); + } + + /** + * Http response code of the request that cause the exception + * + * @return {@code -1} if no code can be discerned. + */ + public int getResponseCode() { + return responseCode; + } + + /** + * Http response message of the request that cause the exception + * + * @return {@code null} if no response message can be discerned. + */ + public String getResponseMessage() { + return responseMessage; + } + + /** + * The http URL that caused the exception + * + * @return url + */ + public String getUrl() { + return url; + } + + @Override + public String getMessage() { + return super.getMessage(); + } +} diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index af4819c3a1..4670b00a8e 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -473,21 +473,33 @@ private void setupConnection(URL url) throws IOException { } private T parse(Class type, T instance) throws IOException { - if (uc.getResponseCode()==304) - return null; // special case handling for 304 unmodified, as the content will be "" InputStreamReader r = null; + int responseCode = -1; + String responseMessage = null; try { + responseCode = uc.getResponseCode(); + responseMessage = uc.getResponseMessage(); + if (responseCode == 304) { + return null; // special case handling for 304 unmodified, as the content will be "" + } + r = new InputStreamReader(wrapStream(uc.getInputStream()), "UTF-8"); String data = IOUtils.toString(r); if (type!=null) try { return MAPPER.readValue(data,type); } catch (JsonMappingException e) { - throw (IOException)new IOException("Failed to deserialize "+data).initCause(e); + throw (IOException)new IOException("Failed to deserialize " +data).initCause(e); } if (instance!=null) return MAPPER.readerForUpdating(instance).readValue(data); return null; + } catch (FileNotFoundException e) { + // java.net.URLConnection handles 404 exception has FileNotFoundException, don't wrap exception in HttpException + // to preserve backward compatibility + throw e; + } catch (IOException e) { + throw new HttpException(responseCode, responseMessage, uc.getURL(), e); } finally { IOUtils.closeQuietly(r); } @@ -508,7 +520,15 @@ private InputStream wrapStream(InputStream in) throws IOException { * Handle API error by either throwing it or by returning normally to retry. */ /*package*/ void handleApiError(IOException e) throws IOException { - if (uc.getResponseCode() == 401) // Unauthorized == bad creds + int responseCode; + try { + responseCode = uc.getResponseCode(); + } catch (IOException e2) { + // likely to be a network exception (e.g. SSLHandshakeException), + // uc.getResponseCode() and any other getter on the response will cause an exception + throw e; + } + if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) // 401 / Unauthorized == bad creds throw e; if ("0".equals(uc.getHeaderField("X-RateLimit-Remaining"))) { From 56379bb3b99ea8c25cf85c0a3577fa633d2c5eec Mon Sep 17 00:00:00 2001 From: Cyrille Le Clerc Date: Mon, 7 Mar 2016 19:25:42 +0100 Subject: [PATCH 06/25] Fix broken log message in GitHub.java and cleanup code as recommended by @jglick --- src/main/java/org/kohsuke/github/GitHub.java | 3 ++- src/main/java/org/kohsuke/github/HttpException.java | 13 ++++++------- src/main/java/org/kohsuke/github/Requester.java | 9 ++++++++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index fe94840fda..850edaf531 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -463,7 +463,8 @@ public boolean isCredentialValid() throws IOException { retrieve().to("/user", GHUser.class); return true; } catch (IOException e) { - logger.log(Level.FINEST, "Exception validating credentials on {0} with login {1}: {2}", new Object[]{this.apiUrl, this.login, e, e}); + if (logger.isLoggable(Level.FINE)) + logger.log(Level.FINE, "Exception validating credentials on " + this.apiUrl + " with login '" + this.login + "' " + e, e); return false; } } diff --git a/src/main/java/org/kohsuke/github/HttpException.java b/src/main/java/org/kohsuke/github/HttpException.java index 37c16f4a12..718642299d 100644 --- a/src/main/java/org/kohsuke/github/HttpException.java +++ b/src/main/java/org/kohsuke/github/HttpException.java @@ -4,8 +4,12 @@ import java.net.HttpURLConnection; import java.net.URL; +import javax.annotation.CheckForNull; + /** - * Http exception + * {@link IOException} for http exceptions because {@link HttpURLConnection} throws un-discerned + * {@link IOException} and it can help to know the http response code to decide how to handle an + * http exceptions. * * @author Cyrille Le Clerc */ @@ -81,7 +85,7 @@ public HttpException(int responseCode, String responseMessage, String url, Throw * @see HttpURLConnection#getResponseCode() * @see HttpURLConnection#getResponseMessage() */ - public HttpException(int responseCode, String responseMessage, URL url, Throwable cause) { + public HttpException(int responseCode, String responseMessage, @CheckForNull URL url, Throwable cause) { this(responseCode, responseMessage, url == null ? null : url.toString(), cause); } @@ -111,9 +115,4 @@ public String getResponseMessage() { public String getUrl() { return url; } - - @Override - public String getMessage() { - return super.getMessage(); - } } diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index 4670b00a8e..6ac2a084c2 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -48,6 +48,8 @@ import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; @@ -64,7 +66,9 @@ */ class Requester { private static final List METHODS_WITHOUT_BODY = asList("GET", "DELETE"); - + + protected final transient Logger logger = Logger.getLogger(getClass().getName()); + private final GitHub root; private final List args = new ArrayList(); private final Map headers = new LinkedHashMap(); @@ -526,6 +530,9 @@ private InputStream wrapStream(InputStream in) throws IOException { } catch (IOException e2) { // likely to be a network exception (e.g. SSLHandshakeException), // uc.getResponseCode() and any other getter on the response will cause an exception + if (logger.isLoggable(Level.FINE)) + logger.log(Level.FINE, "Silently ignore exception retrieving response code for '" + uc.getURL() + "'" + + " handling exception " + e, e); throw e; } if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) // 401 / Unauthorized == bad creds From e09185fd0eb92d464ee44ce845db26dd889a5677 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 11 Mar 2016 22:51:48 -0800 Subject: [PATCH 07/25] Logger should be static --- src/main/java/org/kohsuke/github/GitHub.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 850edaf531..4ac80c9942 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -25,13 +25,13 @@ 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 java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; -import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.text.ParseException; @@ -56,7 +56,6 @@ import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import java.nio.charset.Charset; -import java.util.logging.Level; import java.util.logging.Logger; /** @@ -71,8 +70,6 @@ * @author Kohsuke Kawaguchi */ public class GitHub { - protected final transient Logger logger = Logger.getLogger(getClass().getName()); - /*package*/ final String login; /** @@ -463,8 +460,8 @@ public boolean isCredentialValid() throws IOException { retrieve().to("/user", GHUser.class); return true; } catch (IOException e) { - if (logger.isLoggable(Level.FINE)) - logger.log(Level.FINE, "Exception validating credentials on " + this.apiUrl + " with login '" + this.login + "' " + e, e); + if (LOGGER.isLoggable(FINE)) + LOGGER.log(FINE, "Exception validating credentials on " + this.apiUrl + " with login '" + this.login + "' " + e, e); return false; } } @@ -611,4 +608,6 @@ public Reader renderMarkdown(String text) throws IOException { } /* package */ static final String GITHUB_URL = "https://api.github.com"; + + private static final Logger LOGGER = Logger.getLogger(GitHub.class.getName()); } From ae49166aa2f162a1e65322641ccc8247e6ca9a5b Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 11 Mar 2016 22:55:44 -0800 Subject: [PATCH 08/25] No such parameter exists on this method --- src/main/java/org/kohsuke/github/HttpException.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/HttpException.java b/src/main/java/org/kohsuke/github/HttpException.java index 718642299d..670cb491f4 100644 --- a/src/main/java/org/kohsuke/github/HttpException.java +++ b/src/main/java/org/kohsuke/github/HttpException.java @@ -56,8 +56,6 @@ public HttpException(String message, int responseCode, String responseMessage, S } /** - * @param message The detail message (which is saved for later retrieval - * by the {@link #getMessage()} method) * @param responseCode Http response code. {@code -1} if no code can be discerned. * @param responseMessage Http response message * @param url The url that was invoked From dba84a33b9702b0fde265dad9bdb3bec897a5ce0 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 11 Mar 2016 22:55:58 -0800 Subject: [PATCH 09/25] Logger should be static --- src/main/java/org/kohsuke/github/Requester.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index 6ac2a084c2..311b3320b4 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -48,7 +48,6 @@ import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; -import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -57,6 +56,7 @@ import javax.annotation.WillClose; import static java.util.Arrays.asList; +import static java.util.logging.Level.FINE; import static org.kohsuke.github.GitHub.*; /** @@ -65,10 +65,6 @@ * @author Kohsuke Kawaguchi */ class Requester { - private static final List METHODS_WITHOUT_BODY = asList("GET", "DELETE"); - - protected final transient Logger logger = Logger.getLogger(getClass().getName()); - private final GitHub root; private final List args = new ArrayList(); private final Map headers = new LinkedHashMap(); @@ -530,8 +526,8 @@ private InputStream wrapStream(InputStream in) throws IOException { } catch (IOException e2) { // likely to be a network exception (e.g. SSLHandshakeException), // uc.getResponseCode() and any other getter on the response will cause an exception - if (logger.isLoggable(Level.FINE)) - logger.log(Level.FINE, "Silently ignore exception retrieving response code for '" + uc.getURL() + "'" + + if (LOGGER.isLoggable(FINE)) + LOGGER.log(FINE, "Silently ignore exception retrieving response code for '" + uc.getURL() + "'" + " handling exception " + e, e); throw e; } @@ -557,4 +553,7 @@ private InputStream wrapStream(InputStream in) throws IOException { IOUtils.closeQuietly(es); } } + + private static final List METHODS_WITHOUT_BODY = asList("GET", "DELETE"); + private static final Logger LOGGER = Logger.getLogger(Requester.class.getName()); } From cd8d9556468475e8ed6108a6499f4cd119a0a899 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 11 Mar 2016 23:06:21 -0800 Subject: [PATCH 10/25] Documenting what one gets --- src/main/java/org/kohsuke/github/GitHub.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 14e7b13368..10bb3ea090 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -502,6 +502,25 @@ public void checkApiUrlValidity() throws IOException { private boolean isPrivateModeEnabled() { try { HttpURLConnection connect = getConnector().connect(getApiURL("/")); + /* + $ curl -i https://github.mycompany.com/api/v3/ + HTTP/1.1 401 Unauthorized + Server: GitHub.com + Date: Sat, 05 Mar 2016 19:45:01 GMT + Content-Type: application/json; charset=utf-8 + Content-Length: 130 + Status: 401 Unauthorized + X-GitHub-Media-Type: github.v3 + X-XSS-Protection: 1; mode=block + X-Frame-Options: deny + Content-Security-Policy: default-src 'none' + Access-Control-Allow-Credentials: true + Access-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval + Access-Control-Allow-Origin: * + X-GitHub-Request-Id: dbc70361-b11d-4131-9a7f-674b8edd0411 + Strict-Transport-Security: max-age=31536000; includeSubdomains; preload + X-Content-Type-Options: nosniff + */ if (connect.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED && connect.getHeaderField("Server") != null && connect.getHeaderField("Server").equals("GitHub.com")) { From 10f55cc54926ab47da73da6d54dc3dd52f397add Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 11 Mar 2016 23:10:41 -0800 Subject: [PATCH 11/25] Checking another header I think it's better to pick a header that's unique to GitHub. --- src/main/java/org/kohsuke/github/GitHub.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 10bb3ea090..b8673e4533 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -25,6 +25,7 @@ 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 java.io.ByteArrayInputStream; import java.io.FileNotFoundException; @@ -501,7 +502,7 @@ public void checkApiUrlValidity() throws IOException { */ private boolean isPrivateModeEnabled() { try { - HttpURLConnection connect = getConnector().connect(getApiURL("/")); + HttpURLConnection uc = getConnector().connect(getApiURL("/")); /* $ curl -i https://github.mycompany.com/api/v3/ HTTP/1.1 401 Unauthorized @@ -521,12 +522,8 @@ private boolean isPrivateModeEnabled() { Strict-Transport-Security: max-age=31536000; includeSubdomains; preload X-Content-Type-Options: nosniff */ - if (connect.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED - && connect.getHeaderField("Server") != null - && connect.getHeaderField("Server").equals("GitHub.com")) { - return true; - } - return false; + return uc.getResponseCode() == HTTP_UNAUTHORIZED + && uc.getHeaderField("X-GitHub-Media-Type") != null; } catch (IOException e) { return false; } From 3b764f9c9081df2a93922603506f5df976394182 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 11 Mar 2016 23:11:22 -0800 Subject: [PATCH 12/25] Don't lose the original problem --- src/main/java/org/kohsuke/github/GitHub.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index b8673e4533..cb94f1076e 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -486,11 +486,11 @@ void check(String apiUrl) throws IOException { public void checkApiUrlValidity() throws IOException { try { retrieve().to("/", GHApiInfo.class).check(apiUrl); - } catch (IOException ioe) { + } catch (IOException e) { if (isPrivateModeEnabled()) { - throw new IOException("GitHub Enterprise server (" + apiUrl + ") with private mode enabled"); + throw (IOException)new IOException("GitHub Enterprise server (" + apiUrl + ") with private mode enabled").initCause(e); } - throw ioe; + throw e; } } From 1954a9f3f8d998ad6a349c044960a33cd24bfd9a Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 11 Mar 2016 23:12:50 -0800 Subject: [PATCH 13/25] This isn't just about API URL but it also checks the valid credential --- src/main/java/org/kohsuke/github/GitHub.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index cb94f1076e..7aa928e782 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -477,7 +477,10 @@ void check(String apiUrl) throws IOException { } /** - * Ensures that the API URL is valid. + * Tests the connection. + * + *

+ * Verify that the API URL and credentials are valid to access this GitHub. * *

* This method returns normally if the endpoint is reachable and verified to be GitHub API URL. From 7a78f9f5aac0d35d07cc7d958fe5d7ba8a5440ff Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 11 Mar 2016 23:14:40 -0800 Subject: [PATCH 14/25] No need to require 1.6 --- pom.xml | 8 -------- src/main/java/org/kohsuke/github/HttpException.java | 6 ++++-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index dde789075d..0af43488f1 100644 --- a/pom.xml +++ b/pom.xml @@ -46,14 +46,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - - 1.6 - 1.6 - - org.codehaus.mojo findbugs-maven-plugin diff --git a/src/main/java/org/kohsuke/github/HttpException.java b/src/main/java/org/kohsuke/github/HttpException.java index 670cb491f4..16c8e68be2 100644 --- a/src/main/java/org/kohsuke/github/HttpException.java +++ b/src/main/java/org/kohsuke/github/HttpException.java @@ -49,7 +49,8 @@ public HttpException(String message, int responseCode, String responseMessage, S * @see HttpURLConnection#getResponseMessage() */ public HttpException(String message, int responseCode, String responseMessage, String url, Throwable cause) { - super(message, cause); + super(message); + initCause(cause); this.responseCode = responseCode; this.responseMessage = responseMessage; this.url = url; @@ -67,7 +68,8 @@ public HttpException(String message, int responseCode, String responseMessage, S */ public HttpException(int responseCode, String responseMessage, String url, Throwable cause) { super("Server returned HTTP response code: " + responseCode + ", message: '" + responseMessage + "'" + - " for URL: " + url, cause); + " for URL: " + url); + initCause(cause); this.responseCode = responseCode; this.responseMessage = responseMessage; this.url = url; From c1c2a2735895622fafe69003c015a7b8a4285f50 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 11 Mar 2016 23:21:07 -0800 Subject: [PATCH 15/25] Doc improvement --- src/main/java/org/kohsuke/github/GitHubBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GitHubBuilder.java b/src/main/java/org/kohsuke/github/GitHubBuilder.java index 42a0f2be6f..2abe16f9c1 100644 --- a/src/main/java/org/kohsuke/github/GitHubBuilder.java +++ b/src/main/java/org/kohsuke/github/GitHubBuilder.java @@ -15,7 +15,7 @@ import java.util.Properties; /** - * + * Configures connection details and produces {@link GitHub}. * * @since 1.59 */ From 14dcb37ee1ea225b73b548faae313ab512ae69a4 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 11 Mar 2016 23:29:58 -0800 Subject: [PATCH 16/25] Not all caller wants GET --- src/main/java/org/kohsuke/github/GHContent.java | 3 ++- src/main/java/org/kohsuke/github/Requester.java | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index 8955505219..88a5517364 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -115,7 +115,8 @@ public String getHtmlUrl() { * Retrieves the actual content stored here. */ public InputStream read() throws IOException { - return new Requester(root).asStream(getDownloadUrl()); + // if the download link is encoded with a token on the query string, the default behavior of POST will fail + return new Requester(root).method("GET").asStream(getDownloadUrl()); } /** diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index b305787596..4a9bf67ee7 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -284,7 +284,6 @@ public int asHttpStatusCode(String tailApiUrl) throws IOException { public InputStream asStream(String tailApiUrl) throws IOException { while (true) {// loop while API rate limit is hit - method("GET"); // if the download link is encoded with a token on the query string, the default behavior of POST will fail setupConnection(root.getApiURL(tailApiUrl)); buildRequest(); From 906d9af7b757d6b4da5a7b6f15eb60bafe490120 Mon Sep 17 00:00:00 2001 From: Ruben Dijkstra Date: Sat, 12 Mar 2016 21:48:50 +0100 Subject: [PATCH 17/25] Include the animal sniffer plugin 7a78f9f5aac0d35d07cc7d958fe5d7ba8a5440ff set the compiler level back to 5, but there are no guarantees that we don't accidentally use any features from newer class libraries. --- pom.xml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pom.xml b/pom.xml index 0af43488f1..63ff3acb00 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,27 @@ + + org.codehaus.mojo + animal-sniffer-maven-plugin + 1.15 + + + org.codehaus.mojo.signature + java15 + 1.0 + + + + + ensure-java-1.5-class-library + test + + check + + + + com.infradna.tool bridge-method-injector From 755d5f77ea0d990184d1068b5bcb450380b9d7d1 Mon Sep 17 00:00:00 2001 From: Ruben Dijkstra Date: Sat, 12 Mar 2016 21:56:56 +0100 Subject: [PATCH 18/25] Java 5 doesn't have Arrays.copyOf() http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Arrays.html --- src/main/java/org/kohsuke/github/GHCompare.java | 10 ++++++---- .../org/kohsuke/github/GHPullRequestCommitDetail.java | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHCompare.java b/src/main/java/org/kohsuke/github/GHCompare.java index c9c882ba4e..100753db01 100644 --- a/src/main/java/org/kohsuke/github/GHCompare.java +++ b/src/main/java/org/kohsuke/github/GHCompare.java @@ -4,8 +4,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.net.URL; -import java.util.Arrays; -import java.util.Date; /** * The model user for comparing 2 commits in the GitHub API. @@ -72,7 +70,9 @@ public Commit getMergeBaseCommit() { * @return A copy of the array being stored in the class. */ public Commit[] getCommits() { - return Arrays.copyOf(commits, commits.length); + Commit[] newValue = new Commit[commits.length]; + System.arraycopy(commits, 0, newValue, 0, commits.length); + return newValue; } /** @@ -80,7 +80,9 @@ public Commit[] getCommits() { * @return A copy of the array being stored in the class. */ public GHCommit.File[] getFiles() { - return Arrays.copyOf(files, files.length); + GHCommit.File[] newValue = new GHCommit.File[files.length]; + System.arraycopy(files, 0, newValue, 0, files.length); + return newValue; } public GHCompare wrap(GHRepository owner) { diff --git a/src/main/java/org/kohsuke/github/GHPullRequestCommitDetail.java b/src/main/java/org/kohsuke/github/GHPullRequestCommitDetail.java index d4b48da538..e6c558b9e1 100644 --- a/src/main/java/org/kohsuke/github/GHPullRequestCommitDetail.java +++ b/src/main/java/org/kohsuke/github/GHPullRequestCommitDetail.java @@ -27,7 +27,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.net.URL; -import java.util.Arrays; /** * Commit detail inside a {@link GHPullRequest}. @@ -144,6 +143,8 @@ public URL getCommentsUrl() { } public CommitPointer[] getParents() { - return Arrays.copyOf(parents, parents.length); + CommitPointer[] newValue = new CommitPointer[parents.length]; + System.arraycopy(parents, 0, newValue, 0, parents.length); + return newValue; } } From f9014dbab36bd8b48275ab49c127b6132d32969c Mon Sep 17 00:00:00 2001 From: Ruben Dijkstra Date: Sat, 12 Mar 2016 21:58:27 +0100 Subject: [PATCH 19/25] Convert to legacy Throwable.initCause() --- src/main/java/org/kohsuke/github/GHRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index fbd64709a6..c74d9095aa 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -1152,7 +1152,7 @@ public GHContentUpdateResponse createContent(String content, String commitMessag try { payload = content.getBytes("UTF-8"); } catch (UnsupportedEncodingException ex) { - throw new IOException("UTF-8 encoding is not supported", ex); + throw (IOException) new IOException("UTF-8 encoding is not supported").initCause(ex); } return createContent(payload, commitMessage, path, branch); } From 36d5b092d77660ab0d7b59f6f94ca37ba6f76d1a Mon Sep 17 00:00:00 2001 From: Ruben Dijkstra Date: Sat, 12 Mar 2016 21:59:51 +0100 Subject: [PATCH 20/25] Java 5 doesn't have new String(byte[], Charset) http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/String.html --- src/main/java/org/kohsuke/github/GitHub.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index d957212b2b..6180f768b1 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -57,7 +57,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.introspect.VisibilityChecker.Std; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; -import java.nio.charset.Charset; import java.util.logging.Logger; /** @@ -134,8 +133,8 @@ public class GitHub { } else { if (password!=null) { String authorization = (login + ':' + password); - Charset charset = Charsets.UTF_8; - encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes(charset)), charset); + String charsetName = Charsets.UTF_8.name(); + encodedAuthorization = "Basic "+new String(Base64.encodeBase64(authorization.getBytes(charsetName)), charsetName); } else {// anonymous access encodedAuthorization = null; } From 0cd5147e1ab2c4549c817db340d94bcdf51d02d3 Mon Sep 17 00:00:00 2001 From: Ruben Dijkstra Date: Sat, 12 Mar 2016 22:01:25 +0100 Subject: [PATCH 21/25] Java 5 doesn't have TimeUnit.HOURS http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/TimeUnit.html --- src/main/java/org/kohsuke/github/GitHub.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 6180f768b1..22792a8798 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -48,7 +48,6 @@ import java.util.Map; import java.util.Set; import java.util.TimeZone; -import java.util.concurrent.TimeUnit; import org.apache.commons.codec.Charsets; import org.apache.commons.codec.binary.Base64; @@ -264,7 +263,8 @@ public GHRateLimit getRateLimit() throws IOException { // see issue #78 GHRateLimit r = new GHRateLimit(); r.limit = r.remaining = 1000000; - r.reset = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1)); + long hours = 1000L * 60 * 60; + r.reset = new Date(System.currentTimeMillis() + 1 * hours ); return r; } } From 397886d289cd4e2c1a5acabb7b2397c907d484be Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 18 Mar 2016 19:08:51 -0700 Subject: [PATCH 22/25] Excluding a flaky test --- src/test/java/org/kohsuke/github/GHContentIntegrationTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java b/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java index 7848143a86..8e3873708b 100644 --- a/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java +++ b/src/test/java/org/kohsuke/github/GHContentIntegrationTest.java @@ -66,7 +66,8 @@ public void testCRUDContent() throws Exception { assertNotNull(updatedContentResponse.getCommit()); assertNotNull(updatedContentResponse.getContent()); - assertEquals("this is some new content\n", updatedContent.getContent()); + // due to what appears to be a cache propagation delay, this test is too flaky + // assertEquals("this is some new content\n", updatedContent.getContent()); GHContentUpdateResponse deleteResponse = updatedContent.delete("Enough of this foolishness!"); From a31395ed806aed032243672d3e4f1d796cefadd9 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 18 Mar 2016 19:15:52 -0700 Subject: [PATCH 23/25] Signature fix for Java5 --- .../java/org/kohsuke/github/GHContent.java | 4 ++-- .../java/org/kohsuke/github/GHRepository.java | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHContent.java b/src/main/java/org/kohsuke/github/GHContent.java index 88a5517364..8b6f6fea54 100644 --- a/src/main/java/org/kohsuke/github/GHContent.java +++ b/src/main/java/org/kohsuke/github/GHContent.java @@ -78,7 +78,7 @@ public String getPath() { */ @SuppressFBWarnings("DM_DEFAULT_ENCODING") public String getContent() throws IOException { - return new String(DatatypeConverter.parseBase64Binary(getEncodedContent())); + return new String(Base64.decodeBase64(getEncodedContent())); } /** @@ -179,7 +179,7 @@ public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessa } public GHContentUpdateResponse update(byte[] newContentBytes, String commitMessage, String branch) throws IOException { - String encodedContent = DatatypeConverter.printBase64Binary(newContentBytes); + String encodedContent = Base64.encodeBase64String(newContentBytes); Requester requester = new Requester(root) .with("path", path) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index c74d9095aa..326564e521 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -26,9 +26,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils; -import javax.xml.bind.DatatypeConverter; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; @@ -36,7 +36,19 @@ import java.io.Reader; import java.io.UnsupportedEncodingException; import java.net.URL; -import java.util.*; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; import static java.util.Arrays.asList; @@ -1165,7 +1177,7 @@ public GHContentUpdateResponse createContent(byte[] contentBytes, String commitM Requester requester = new Requester(root) .with("path", path) .with("message", commitMessage) - .with("content", DatatypeConverter.printBase64Binary(contentBytes)) + .with("content", Base64.encodeBase64String(contentBytes)) .method("PUT"); if (branch != null) { From 557ae4165c05b7c37d09e93ac5025cdae6b1db7b Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 18 Mar 2016 19:19:51 -0700 Subject: [PATCH 24/25] Not important --- src/main/java/org/kohsuke/github/Requester.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index 4a9bf67ee7..8f922b4ff3 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -24,6 +24,7 @@ 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; @@ -138,7 +139,7 @@ public Requester with(String key, Enum e) { // by convention Java constant names are upper cases, but github uses // lower-case constants. GitHub also uses '-', which in Java we always // replace by '_' - return with(key, e.toString().toLowerCase(Locale.ENGLISH).replace('_','-')); + return with(key, e.toString().toLowerCase(Locale.ENGLISH).replace('_', '-')); } public Requester with(String key, String value) { @@ -216,9 +217,10 @@ public T to(String tailApiUrl, T existingInstance) throws IOException { */ @Deprecated public T to(String tailApiUrl, Class type, String method) throws IOException { - return method(method).to(tailApiUrl,type); + return method(method).to(tailApiUrl, type); } + @SuppressFBWarnings("SBSC_USE_STRINGBUFFER_CONCATENATION") private T _to(String tailApiUrl, Class type, T instance) throws IOException { if (METHODS_WITHOUT_BODY.contains(method) && !args.isEmpty()) { boolean questionMarkFound = tailApiUrl.indexOf('?') != -1; From 255c9935488c4d64e9869703382e06934d826a8b Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 18 Mar 2016 19:22:34 -0700 Subject: [PATCH 25/25] [maven-release-plugin] prepare release github-api-1.74 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 63ff3acb00..af07ce2d59 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ github-api - 1.74-SNAPSHOT + 1.74 GitHub API for Java http://github-api.kohsuke.org/ GitHub API for Java @@ -16,7 +16,7 @@ scm:git:git@github.com/kohsuke/${project.artifactId}.git scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git http://${project.artifactId}.kohsuke.org/ - HEAD + github-api-1.74