mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-25 08:21:18 +00:00
460 lines
16 KiB
Java
460 lines
16 KiB
Java
package org.kohsuke.github;
|
|
|
|
import org.apache.commons.io.IOUtils;
|
|
import org.kohsuke.github.authorization.AuthorizationProvider;
|
|
import org.kohsuke.github.authorization.ImmutableAuthorizationProvider;
|
|
import org.kohsuke.github.extras.ImpatientHttpConnector;
|
|
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.IOException;
|
|
import java.net.HttpURLConnection;
|
|
import java.net.Proxy;
|
|
import java.util.Locale;
|
|
import java.util.Map.Entry;
|
|
import java.util.Properties;
|
|
|
|
import javax.annotation.Nonnull;
|
|
|
|
/**
|
|
* Configures connection details and produces {@link GitHub}.
|
|
*
|
|
* @since 1.59
|
|
*/
|
|
public class GitHubBuilder implements Cloneable {
|
|
|
|
// default scoped so unit tests can read them.
|
|
/* private */ String endpoint = GitHubClient.GITHUB_URL;
|
|
|
|
private HttpConnector connector;
|
|
|
|
private RateLimitHandler rateLimitHandler = RateLimitHandler.WAIT;
|
|
private AbuseLimitHandler abuseLimitHandler = AbuseLimitHandler.WAIT;
|
|
private GitHubRateLimitChecker rateLimitChecker = new GitHubRateLimitChecker();
|
|
/* private */ AuthorizationProvider authorizationProvider = AuthorizationProvider.ANONYMOUS;
|
|
|
|
/**
|
|
* Instantiates a new Git hub builder.
|
|
*/
|
|
public GitHubBuilder() {
|
|
}
|
|
|
|
/**
|
|
* First check if the credentials are configured in the environment. We use environment first because users are not
|
|
* likely to give required (full) permissions to their default key.
|
|
*
|
|
* If no user is specified it means there is no configuration present, so try using the ~/.github properties file.
|
|
**
|
|
* If there is still no user it means there are no credentials defined and throw an IOException.
|
|
*
|
|
* @return the configured Builder from credentials defined on the system or in the environment. Otherwise returns
|
|
* null.
|
|
*
|
|
* @throws IOException
|
|
* If there are no credentials defined in the ~/.github properties file or the process environment.
|
|
*/
|
|
static GitHubBuilder fromCredentials() throws IOException {
|
|
Exception cause = null;
|
|
GitHubBuilder builder = null;
|
|
|
|
builder = fromEnvironment();
|
|
|
|
if (builder.authorizationProvider != null)
|
|
return builder;
|
|
|
|
try {
|
|
builder = fromPropertyFile();
|
|
|
|
if (builder.authorizationProvider != null)
|
|
return builder;
|
|
} catch (FileNotFoundException e) {
|
|
// fall through
|
|
cause = e;
|
|
}
|
|
throw (IOException) new IOException("Failed to resolve credentials from ~/.github or the environment.")
|
|
.initCause(cause);
|
|
}
|
|
|
|
/**
|
|
* From environment git hub builder.
|
|
*
|
|
* @param loginVariableName
|
|
* the login variable name
|
|
* @param passwordVariableName
|
|
* the password variable name
|
|
* @param oauthVariableName
|
|
* the oauth variable name
|
|
* @return the git hub builder
|
|
* @throws IOException
|
|
* the io exception
|
|
* @deprecated Use {@link #fromEnvironment()} to pick up standard set of environment variables, so that different
|
|
* clients of this library will all recognize one consistent set of coordinates.
|
|
*/
|
|
@Deprecated
|
|
public static GitHubBuilder fromEnvironment(String loginVariableName,
|
|
String passwordVariableName,
|
|
String oauthVariableName) throws IOException {
|
|
return fromEnvironment(loginVariableName, passwordVariableName, oauthVariableName, "");
|
|
}
|
|
|
|
private static void loadIfSet(String envName, Properties p, String propName) {
|
|
String v = System.getenv(envName);
|
|
if (v != null)
|
|
p.put(propName, v);
|
|
}
|
|
|
|
/**
|
|
* From environment git hub builder.
|
|
*
|
|
* @param loginVariableName
|
|
* the login variable name
|
|
* @param passwordVariableName
|
|
* the password variable name
|
|
* @param oauthVariableName
|
|
* the oauth variable name
|
|
* @param endpointVariableName
|
|
* the endpoint variable name
|
|
* @return the git hub builder
|
|
* @throws IOException
|
|
* the io exception
|
|
* @deprecated Use {@link #fromEnvironment()} to pick up standard set of environment variables, so that different
|
|
* clients of this library will all recognize one consistent set of coordinates.
|
|
*/
|
|
@Deprecated
|
|
public static GitHubBuilder fromEnvironment(String loginVariableName,
|
|
String passwordVariableName,
|
|
String oauthVariableName,
|
|
String endpointVariableName) throws IOException {
|
|
Properties env = new Properties();
|
|
loadIfSet(loginVariableName, env, "login");
|
|
loadIfSet(passwordVariableName, env, "password");
|
|
loadIfSet(oauthVariableName, env, "oauth");
|
|
loadIfSet(endpointVariableName, env, "endpoint");
|
|
return fromProperties(env);
|
|
}
|
|
|
|
/**
|
|
* Creates {@link GitHubBuilder} by picking up coordinates from environment variables.
|
|
*
|
|
* <p>
|
|
* The following environment variables are recognized:
|
|
*
|
|
* <ul>
|
|
* <li>GITHUB_LOGIN: username like 'kohsuke'
|
|
* <li>GITHUB_PASSWORD: raw password
|
|
* <li>GITHUB_OAUTH: OAuth token to login
|
|
* <li>GITHUB_ENDPOINT: URL of the API endpoint
|
|
* <li>GITHUB_JWT: JWT token to login
|
|
* </ul>
|
|
*
|
|
* <p>
|
|
* See class javadoc for the relationship between these coordinates.
|
|
*
|
|
* <p>
|
|
* For backward compatibility, the following environment variables are recognized but discouraged: login, password,
|
|
* oauth
|
|
*
|
|
* @return the git hub builder
|
|
* @throws IOException
|
|
* the io exception
|
|
*/
|
|
public static GitHubBuilder fromEnvironment() throws IOException {
|
|
Properties props = new Properties();
|
|
for (Entry<String, String> e : System.getenv().entrySet()) {
|
|
String name = e.getKey().toLowerCase(Locale.ENGLISH);
|
|
if (name.startsWith("github_"))
|
|
name = name.substring(7);
|
|
props.put(name, e.getValue());
|
|
}
|
|
return fromProperties(props);
|
|
}
|
|
|
|
/**
|
|
* From property file git hub builder.
|
|
*
|
|
* @return the git hub builder
|
|
* @throws IOException
|
|
* the io exception
|
|
*/
|
|
public static GitHubBuilder fromPropertyFile() throws IOException {
|
|
File homeDir = new File(System.getProperty("user.home"));
|
|
File propertyFile = new File(homeDir, ".github");
|
|
return fromPropertyFile(propertyFile.getPath());
|
|
}
|
|
|
|
/**
|
|
* From property file git hub builder.
|
|
*
|
|
* @param propertyFileName
|
|
* the property file name
|
|
* @return the git hub builder
|
|
* @throws IOException
|
|
* the io exception
|
|
*/
|
|
public static GitHubBuilder fromPropertyFile(String propertyFileName) throws IOException {
|
|
Properties props = new Properties();
|
|
FileInputStream in = null;
|
|
try {
|
|
in = new FileInputStream(propertyFileName);
|
|
props.load(in);
|
|
} finally {
|
|
IOUtils.closeQuietly(in);
|
|
}
|
|
|
|
return fromProperties(props);
|
|
}
|
|
|
|
/**
|
|
* From properties git hub builder.
|
|
*
|
|
* @param props
|
|
* the props
|
|
* @return the git hub builder
|
|
*/
|
|
public static GitHubBuilder fromProperties(Properties props) {
|
|
GitHubBuilder self = new GitHubBuilder();
|
|
String oauth = props.getProperty("oauth");
|
|
String jwt = props.getProperty("jwt");
|
|
String login = props.getProperty("login");
|
|
String password = props.getProperty("password");
|
|
|
|
if (oauth != null) {
|
|
self.withOAuthToken(oauth, login);
|
|
}
|
|
if (jwt != null) {
|
|
self.withJwtToken(jwt);
|
|
}
|
|
if (password != null) {
|
|
self.withPassword(login, password);
|
|
}
|
|
self.withEndpoint(props.getProperty("endpoint", GitHubClient.GITHUB_URL));
|
|
return self;
|
|
}
|
|
|
|
/**
|
|
* With endpoint git hub builder.
|
|
*
|
|
* @param endpoint
|
|
* The URL of GitHub (or GitHub enterprise) API endpoint, such as "https://api.github.com" or
|
|
* "http://ghe.acme.com/api/v3". Note that GitHub Enterprise has <code>/api/v3</code> in the URL. For
|
|
* historical reasons, this parameter still accepts the bare domain name, but that's considered
|
|
* deprecated.
|
|
* @return the git hub builder
|
|
*/
|
|
public GitHubBuilder withEndpoint(String endpoint) {
|
|
this.endpoint = endpoint;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* With password git hub builder.
|
|
*
|
|
* @param user
|
|
* the user
|
|
* @param password
|
|
* the password
|
|
* @return the git hub builder
|
|
*/
|
|
public GitHubBuilder withPassword(String user, String password) {
|
|
return withAuthorizationProvider(ImmutableAuthorizationProvider.fromLoginAndPassword(user, password));
|
|
}
|
|
|
|
/**
|
|
* With o auth token git hub builder.
|
|
*
|
|
* @param oauthToken
|
|
* the oauth token
|
|
* @return the git hub builder
|
|
*/
|
|
public GitHubBuilder withOAuthToken(String oauthToken) {
|
|
return withAuthorizationProvider(ImmutableAuthorizationProvider.fromOauthToken(oauthToken));
|
|
}
|
|
|
|
/**
|
|
* With o auth token git hub builder.
|
|
*
|
|
* @param oauthToken
|
|
* the oauth token
|
|
* @param user
|
|
* the user
|
|
* @return the git hub builder
|
|
*/
|
|
public GitHubBuilder withOAuthToken(String oauthToken, String user) {
|
|
return withAuthorizationProvider(ImmutableAuthorizationProvider.fromOauthToken(oauthToken, user));
|
|
}
|
|
|
|
/**
|
|
* Configures a {@link AuthorizationProvider} for this builder
|
|
*
|
|
* There can be only one authorization provider per client instance.
|
|
*
|
|
* @param authorizationProvider
|
|
* the authorization provider
|
|
* @return the git hub builder
|
|
*
|
|
*/
|
|
public GitHubBuilder withAuthorizationProvider(final AuthorizationProvider authorizationProvider) {
|
|
this.authorizationProvider = authorizationProvider;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Configures {@link GitHubBuilder} with Installation Token generated by the GitHub Application
|
|
*
|
|
* @param appInstallationToken
|
|
* A string containing the GitHub App installation token
|
|
* @return the configured Builder from given GitHub App installation token.
|
|
* @see GHAppInstallation#createToken(java.util.Map) GHAppInstallation#createToken(java.util.Map)
|
|
*/
|
|
public GitHubBuilder withAppInstallationToken(String appInstallationToken) {
|
|
return withAuthorizationProvider(ImmutableAuthorizationProvider.fromAppInstallationToken(appInstallationToken));
|
|
}
|
|
|
|
/**
|
|
* With jwt token git hub builder.
|
|
*
|
|
* @param jwtToken
|
|
* the jwt token
|
|
* @return the git hub builder
|
|
*/
|
|
public GitHubBuilder withJwtToken(String jwtToken) {
|
|
return withAuthorizationProvider(ImmutableAuthorizationProvider.fromJwtToken(jwtToken));
|
|
}
|
|
|
|
/**
|
|
* With connector git hub builder.
|
|
*
|
|
* @param connector
|
|
* the connector
|
|
* @return the git hub builder
|
|
*/
|
|
public GitHubBuilder withConnector(HttpConnector connector) {
|
|
this.connector = connector;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds a {@link RateLimitHandler} to this {@link GitHubBuilder}.
|
|
* <p>
|
|
* GitHub allots a certain number of requests to each user or application per period of time (usually per hour). The
|
|
* number of requests remaining is returned in the response header and can also be requested using
|
|
* {@link GitHub#getRateLimit()}. This requests per interval is referred to as the "rate limit".
|
|
* </p>
|
|
* <p>
|
|
* When the remaining number of requests reaches zero, the next request will return an error. If this happens,
|
|
* {@link RateLimitHandler#onError(IOException, HttpURLConnection)} will be called.
|
|
* </p>
|
|
* <p>
|
|
* NOTE: GitHub treats clients that exceed their rate limit very harshly. If possible, clients should avoid
|
|
* exceeding their rate limit. Consider adding a {@link RateLimitChecker} to automatically check the rate limit for
|
|
* each request and wait if needed.
|
|
* </p>
|
|
*
|
|
* @param handler
|
|
* the handler
|
|
* @return the git hub builder
|
|
* @see #withRateLimitChecker(RateLimitChecker)
|
|
*/
|
|
public GitHubBuilder withRateLimitHandler(RateLimitHandler handler) {
|
|
this.rateLimitHandler = handler;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds a {@link AbuseLimitHandler} to this {@link GitHubBuilder}.
|
|
* <p>
|
|
* When a client sends too many requests in a short time span, GitHub may return an error and set a header telling
|
|
* the client to not make any more request for some period of time. If this happens,
|
|
* {@link AbuseLimitHandler#onError(IOException, HttpURLConnection)} will be called.
|
|
* </p>
|
|
*
|
|
* @param handler
|
|
* the handler
|
|
* @return the git hub builder
|
|
*/
|
|
public GitHubBuilder withAbuseLimitHandler(AbuseLimitHandler handler) {
|
|
this.abuseLimitHandler = handler;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds a {@link RateLimitChecker} for the Core API for this {@link GitHubBuilder}.
|
|
*
|
|
* @param coreRateLimitChecker
|
|
* the {@link RateLimitChecker} for core GitHub API requests
|
|
* @return the git hub builder
|
|
* @see #withRateLimitChecker(RateLimitChecker, RateLimitTarget)
|
|
*/
|
|
public GitHubBuilder withRateLimitChecker(@Nonnull RateLimitChecker coreRateLimitChecker) {
|
|
return withRateLimitChecker(coreRateLimitChecker, RateLimitTarget.CORE);
|
|
}
|
|
|
|
/**
|
|
* Adds a {@link RateLimitChecker} to this {@link GitHubBuilder}.
|
|
* <p>
|
|
* GitHub allots a certain number of requests to each user or application per period of time (usually per hour). The
|
|
* number of requests remaining is returned in the response header and can also be requested using
|
|
* {@link GitHub#getRateLimit()}. This requests per interval is referred to as the "rate limit".
|
|
* </p>
|
|
* <p>
|
|
* GitHub prefers that clients stop before exceeding their rate limit rather than stopping after they exceed it. The
|
|
* {@link RateLimitChecker} is called before each request to check the rate limit and wait if the checker criteria
|
|
* are met.
|
|
* </p>
|
|
* <p>
|
|
* Checking your rate limit using {@link GitHub#getRateLimit()} does not effect your rate limit, but each
|
|
* {@link GitHub} instance will attempt to cache and reuse the last seen rate limit rather than making a new
|
|
* request.
|
|
* </p>
|
|
*
|
|
* @param rateLimitChecker
|
|
* the {@link RateLimitChecker} for requests
|
|
* @param rateLimitTarget
|
|
* the {@link RateLimitTarget} specifying which rate limit record to check
|
|
* @return the git hub builder
|
|
*/
|
|
public GitHubBuilder withRateLimitChecker(@Nonnull RateLimitChecker rateLimitChecker,
|
|
@Nonnull RateLimitTarget rateLimitTarget) {
|
|
this.rateLimitChecker = this.rateLimitChecker.with(rateLimitChecker, rateLimitTarget);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Configures {@linkplain #withConnector(HttpConnector) connector} that uses HTTP library in JRE but use a specific
|
|
* proxy, instead of the system default one.
|
|
*
|
|
* @param p
|
|
* the p
|
|
* @return the git hub builder
|
|
*/
|
|
public GitHubBuilder withProxy(final Proxy p) {
|
|
return withConnector(new ImpatientHttpConnector(url -> (HttpURLConnection) url.openConnection(p)));
|
|
}
|
|
|
|
/**
|
|
* Builds a {@link GitHub} instance.
|
|
*
|
|
* @return the git hub
|
|
* @throws IOException
|
|
* the io exception
|
|
*/
|
|
public GitHub build() throws IOException {
|
|
return new GitHub(endpoint,
|
|
connector,
|
|
rateLimitHandler,
|
|
abuseLimitHandler,
|
|
rateLimitChecker,
|
|
authorizationProvider);
|
|
}
|
|
|
|
@Override
|
|
public GitHubBuilder clone() {
|
|
try {
|
|
return (GitHubBuilder) super.clone();
|
|
} catch (CloneNotSupportedException e) {
|
|
throw new RuntimeException("Clone should be supported", e);
|
|
}
|
|
}
|
|
}
|