-
Notifications
You must be signed in to change notification settings - Fork 10
/
GithubApi.java
127 lines (102 loc) · 4.35 KB
/
GithubApi.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package org.shipkit.changelog;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import javax.net.ssl.HttpsURLConnection;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Optional;
import java.util.TimeZone;
/**
* Wrapper for making REST requests to Github API
*/
public class GithubApi {
private static final Logger LOG = Logging.getLogger(GithubApi.class);
private final String authToken;
public GithubApi(String authToken) {
this.authToken = authToken;
}
public String post(String url, String body) throws IOException {
return doRequest(url, "POST", Optional.of(body)).content;
}
public String patch(String url, String body) throws IOException {
return doRequest(url, "PATCH", Optional.of(body)).content;
}
public Response get(String url) throws IOException {
return doRequest(url, "GET", Optional.empty());
}
private Response doRequest(String urlString, String method, Optional<String> body) throws IOException {
URL url = new URL(urlString);
HttpsURLConnection c = (HttpsURLConnection) url.openConnection();
//workaround for Java limitation (https://bugs.openjdk.java.net/browse/JDK-7016595), works with GitHub REST API
if (method.equals("PATCH")) {
c.setRequestMethod("POST");
}
c.setDoOutput(true);
c.setRequestProperty("Content-Type", "application/json");
if (method.equals("PATCH")) {
c.setRequestProperty("X-HTTP-Method-Override", "PATCH");
}
if (authToken != null) {
c.setRequestProperty("Authorization", "token " + authToken);
}
if (body.isPresent()) {
try (OutputStream os = c.getOutputStream()) {
os.write(body.get().getBytes(StandardCharsets.UTF_8));
os.flush();
}
}
String resetInLocalTime = resetLimitInLocalTimeOrEmpty(c);
String rateRemaining = c.getHeaderField("X-RateLimit-Remaining");
String rateLimit = c.getHeaderField("X-RateLimit-Limit");
//TODO instead of a lifecycle message, we should include the rate limiting information only when the request fails
LOG.lifecycle("Github API rate info => Remaining : " + rateRemaining + ", Limit : " + rateLimit + ", Reset at: " + resetInLocalTime);
String linkHeader = c.getHeaderField("Link");
LOG.info("Next page 'Link' from Github: {}", linkHeader);
String content = call(method, c);
return new Response(content, linkHeader);
}
private String resetLimitInLocalTimeOrEmpty(URLConnection urlConnection) {
String rateLimitReset = urlConnection.getHeaderField("X-RateLimit-Reset");
if (rateLimitReset == null) {
return "";
}
Date resetInEpochSeconds = DateUtil.parseDateInEpochSeconds(rateLimitReset);
return DateUtil.formatDateToLocalTime(resetInEpochSeconds, TimeZone.getDefault());
}
private String call(String method, HttpsURLConnection conn) throws IOException {
if (conn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
return IOUtil.readFully(conn.getInputStream());
} else {
String errorMessage =
String.format("%s %s failed, response code = %s, response body:%n%s",
method, conn.getURL(), conn.getResponseCode(), IOUtil.readFully(conn.getErrorStream()));
throw new ResponseException(conn.getResponseCode(), errorMessage);
}
}
public static class ResponseException extends IOException {
public final int responseCode;
public ResponseException(int responseCode, String errorMessage) {
super(errorMessage);
this.responseCode = responseCode;
}
}
public static class Response {
private final String content;
private final String linkHeader;
public Response(String content, String linkHeader) {
this.content = content;
this.linkHeader = linkHeader;
}
public String getLinkHeader() {
return linkHeader;
}
public String getContent() {
return content;
}
}
}