Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into bump-ghapi
Browse files Browse the repository at this point in the history
  • Loading branch information
jtnord committed May 6, 2022
2 parents 03d36c3 + 01cb1ac commit 7fb89a1
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 16 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/cd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ jobs:
if: needs.validate.outputs.should_release == 'true'
steps:
- name: Check out
uses: actions/checkout@v2.3.4
uses: actions/checkout@v3.0.2
with:
fetch-depth: 0
- name: Set up JDK 8
uses: actions/setup-java@v2
uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: 8
Expand Down
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
buildPlugin(configurations: [
[ platform: "linux", jdk: "8"],
[ platform: "windows", jdk: "8"],
[ platform: "linux", jdk: "11", javaLevel: "8" ]
[ platform: "linux", jdk: "11" ]
])
2 changes: 1 addition & 1 deletion docs/github-app.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ credentials:

== Configuring the github organization folder

See the link:https://docs.cloudbees.com/docs/admin-resources/latest/plugins/github-branch-source[main documentation]
See the link:https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-admin-guide/github-branch-source-plugin[main documentation]
for how to create a GitHub folder.

- Load the folders configuration page
Expand Down
8 changes: 6 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8-standalone</artifactId>
<version>2.32.0</version>
<version>2.33.2</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -114,6 +114,10 @@
<artifactId>workflow-cps-global-lib</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>okhttp-api</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
Expand All @@ -136,7 +140,7 @@
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>2.21.0</version>
<version>2.22.4</version>
<executions>
<execution>
<id>spotless-check</id>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import hudson.model.TaskListener;
import hudson.util.LogTaskListener;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.github.config.GitHubServerConfig;
import org.kohsuke.github.GHRateLimit;
import org.kohsuke.github.GitHub;
Expand Down Expand Up @@ -231,13 +233,22 @@ protected boolean checkRateLimit(GHRateLimit.Record rateLimitRecord, long count)
throws InterruptedException {
LocalChecker checker = getLocalChecker();
if (checker == null) {
// If a checker was not configured for this thread, try our best and continue.
configureThreadLocalChecker(
new LogTaskListener(LOGGER, Level.INFO), GitHubServerConfig.GITHUB_URL);
// If a checker was not configured for this thread, try our best by attempting to get the
// URL from the first configured GitHub endpoint, else default to the public endpoint.
// NOTE: Defaulting to the public GitHub endpoint is insufficient for those using GitHub
// enterprise as it forces rate limit checking in those cases.
String apiUrl = GitHubServerConfig.GITHUB_URL;
List<Endpoint> endpoints = GitHubConfiguration.get().getEndpoints();
if (endpoints.size() > 0 && !StringUtils.isBlank(endpoints.get(0).getApiUri())) {
apiUrl = endpoints.get(0).getApiUri();
}
configureThreadLocalChecker(new LogTaskListener(LOGGER, Level.INFO), apiUrl);
checker = getLocalChecker();
checker.writeLog(
"LocalChecker for rate limit was not set for this thread. "
+ "Configured using system settings.");
+ "Configured using system settings with API URL '"
+ apiUrl
+ "'.");
}
return checker.checkRateLimit(rateLimitRecord, count);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import hudson.security.ACL;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import io.jenkins.plugins.okhttp.api.JenkinsOkHttpClient;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
Expand Down Expand Up @@ -100,7 +101,8 @@ public class Connector {

private static final Random ENTROPY = new Random();
private static final String SALT = Long.toHexString(ENTROPY.nextLong());
private static final OkHttpClient baseClient = new OkHttpClient();
private static final OkHttpClient baseClient =
JenkinsOkHttpClient.newClientBuilder(new OkHttpClient()).build();

private Connector() {
throw new IllegalAccessError("Utility class");
Expand Down Expand Up @@ -544,7 +546,8 @@ public void onError(IOException e, HttpURLConnection uc) throws IOException {

/**
* Alternative to {@link GitHub#isCredentialValid()} that relies on the cached user object in the
* {@link GitHub} instance and hence reduced rate limit consumption.
* {@link GitHub} instance and hence reduced rate limit consumption. It also uses a separate
* endpoint if rate limit checking is disabled.
*
* @param gitHub the instance to check.
* @return {@code true} if the credentials are valid.
Expand All @@ -554,7 +557,15 @@ static boolean isCredentialValid(GitHub gitHub) {
return true;
} else {
try {
gitHub.getRateLimit();
// If rate limit checking is disabled, use the meta endpoint instead
// of the rate limiting endpoint
GitHubConfiguration gitHubConfiguration = GitHubConfiguration.get();
if (gitHubConfiguration != null
&& gitHubConfiguration.getApiRateLimitChecker() == ApiRateLimitChecker.NoThrottle) {
gitHub.getMeta();
} else {
gitHub.getRateLimit();
}
return true;
} catch (IOException e) {
if (LOGGER.isLoggable(FINE)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import hudson.util.ListBoxModel;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
Expand Down Expand Up @@ -1574,15 +1575,21 @@ public List<Action> retrieveActions(
// trusted source
listener.getLogger().printf("Looking up details of %s...%n", getRepoOwner());
List<Action> result = new ArrayList<>();
String apiUri = Util.fixEmptyAndTrim(getApiUri());
StandardCredentials credentials =
Connector.lookupScanCredentials((Item) owner, getApiUri(), credentialsId);
GitHub hub = Connector.connect(getApiUri(), credentials);
Connector.lookupScanCredentials((Item) owner, apiUri, credentialsId);
GitHub hub = Connector.connect(apiUri, credentials);
boolean privateMode = determinePrivateMode(apiUri);
try {
Connector.configureLocalRateLimitChecker(listener, hub);
GHUser u = hub.getUser(getRepoOwner());
String objectUrl = u.getHtmlUrl() == null ? null : u.getHtmlUrl().toExternalForm();
result.add(new ObjectMetadataAction(Util.fixEmpty(u.getName()), null, objectUrl));
result.add(new GitHubOrgMetadataAction(u));
if (privateMode) {
result.add(new GitHubOrgMetadataAction((String) null));
} else {
result.add(new GitHubOrgMetadataAction(u));
}
result.add(new GitHubLink("icon-github-logo", u.getHtmlUrl()));
if (objectUrl == null) {
listener.getLogger().println("Organization URL: unspecified");
Expand All @@ -1600,6 +1607,23 @@ public List<Action> retrieveActions(
}
}

private static boolean determinePrivateMode(String apiUri) {
if (apiUri == null || apiUri.equals(GitHubServerConfig.GITHUB_URL)) {
return false;
}
try {
GitHub.connectToEnterpriseAnonymously(apiUri).checkApiUrlValidity();
} catch (MalformedURLException e) {
// URL is bogus so there is never going to be an avatar - or anything else come to think of it
return true;
} catch (IOException e) {
if (e.getMessage().contains("private mode enabled")) {
return true;
}
}
return false;
}

/** {@inheritDoc} */
@Override
public void afterSave(@NonNull SCMNavigatorOwner owner) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.logging.Logger;
import java.util.stream.Stream;
import org.jenkinsci.plugins.github.config.GitHubServerConfig;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.kohsuke.github.GHRateLimit;
Expand Down Expand Up @@ -92,6 +93,11 @@ public void setUp() throws Exception {
ApiRateLimitChecker.resetLocalChecker();
}

@After
public void tearDown() throws Exception {
GitHubConfiguration.get().setEndpoints(new ArrayList<>());
}

private void setupStubs(List<RateLimit> scenarios) throws Exception {

githubApi.stubFor(
Expand Down Expand Up @@ -187,6 +193,7 @@ public void NoCheckerConfigured() throws Exception {
assertEquals(
3,
countOfOutputLinesContaining("LocalChecker for rate limit was not set for this thread."));
assertEquals(3, countOfOutputLinesContaining("with API URL 'https://api.github.com'"));
assertEquals(3, countOfOutputLines(m -> m.matches(".*[sS]leeping.*")));
// github rate_limit endpoint should be contacted for ThrottleOnOver
// rateLimit()
Expand All @@ -199,6 +206,38 @@ public void NoCheckerConfigured() throws Exception {
assertEquals(initialRequestCount + 9, getRequestCount(githubApi));
}

@Test
public void NoCheckerConfiguredWithEndpoint() throws Exception {
// set up scenarios
List<RateLimit> scenarios = new ArrayList<>();
long now = System.currentTimeMillis();
int limit = 5000;
scenarios.add(new RateLimit(limit, 30, new Date(now - 10000)));
scenarios.add(new RateLimit(limit, limit, new Date(now - 8000)));
scenarios.add(new RateLimit(limit, 20, new Date(now - 6000)));
scenarios.add(new RateLimit(limit, limit, new Date(now - 4000)));
scenarios.add(new RateLimit(limit, 10, new Date(now - 2000)));
scenarios.add(new RateLimit(limit, limit, new Date(now)));
setupStubs(scenarios);

List<Endpoint> endpoints = new ArrayList<>();
endpoints.add(new Endpoint("https://git.company.com/api/v3", "Company GitHub"));
endpoints.add(new Endpoint("https://git2.company.com/api/v3", "Company GitHub 2"));
GitHubConfiguration.get().setEndpoints(endpoints);

GitHubConfiguration.get().setApiRateLimitChecker(ApiRateLimitChecker.NoThrottle);
github.getMeta();

assertEquals(
1,
countOfOutputLinesContaining("LocalChecker for rate limit was not set for this thread."));
assertEquals(1, countOfOutputLinesContaining("with API URL 'https://git.company.com/api/v3'"));
// ThrottleOnOver should not be used for NoThrottle since it is not the public GitHub endpoint
assertEquals(0, countOfOutputLinesContaining("ThrottleOnOver will be used instead"));

assertEquals(initialRequestCount + 2, getRequestCount(githubApi));
}

/**
* Verify that the throttle does not happen in OnOver throttle when none of the quota has been
* used
Expand Down

0 comments on commit 7fb89a1

Please sign in to comment.