Skip to content

Commit dea7f91

Browse files
authored
Merge pull request #313 from sirstrahd/allow_ignoring_rate_limits
[JENKINS-63078] Allow ignoring rate limits
2 parents 7a8db5f + 5e39143 commit dea7f91

File tree

3 files changed

+73
-3
lines changed

3 files changed

+73
-3
lines changed

src/main/java/org/jenkinsci/plugins/github_branch_source/ApiRateLimitChecker.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import edu.umd.cs.findbugs.annotations.NonNull;
44
import hudson.Util;
55
import hudson.model.TaskListener;
6+
import org.jenkinsci.plugins.github.config.GitHubServerConfig;
67
import org.kohsuke.github.GHRateLimit;
78
import org.kohsuke.github.GitHub;
89

@@ -107,7 +108,25 @@ public void checkApiRateLimit(@NonNull TaskListener listener, GitHub github) thr
107108
waitUntilRateLimit(listener, github, rateLimit, expiration);
108109
}
109110
}
110-
};
111+
},
112+
/**
113+
* Ignore GitHub API Rate limit. Useful for GitHub Enterprise instances that might not have a limit set up.
114+
*/
115+
NoThrottle(Messages.ApiRateLimitChecker_NoThrottle()) {
116+
117+
@Override
118+
public void checkApiRateLimit(@NonNull TaskListener listener, GitHub github) throws IOException, InterruptedException {
119+
if (GitHubServerConfig.GITHUB_URL.equals(github.getApiUrl())) {
120+
121+
// If the GitHub public API is being used, this will fallback to ThrottleOnOver
122+
listener.getLogger().println(GitHubConsoleNote.create(System.currentTimeMillis(),
123+
"GitHub throttling is disabled, which is not allowed for public GitHub usage, so ThrottleOnOver will be used instead. To configure a different rate limiting strategy, go to \"GitHub API usage\" under \"Configure System\" in the Jenkins settings."));
124+
ThrottleOnOver.checkApiRateLimit(listener, github);
125+
}
126+
// Nothing needed
127+
}
128+
}
129+
;
111130

112131

113132
private static final double MILLIS_PER_HOUR = TimeUnit.HOURS.toMillis(1);

src/main/resources/org/jenkinsci/plugins/github_branch_source/Messages.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ GitHubBuildStatusNotification.CommitStatusSet=GitHub has been notified of this c
2323

2424
ApiRateLimitChecker.ThrottleForNormalize=Normalize API requests
2525
ApiRateLimitChecker.ThrottleOnOver=Throttle at/near rate limit
26+
ApiRateLimitChecker.NoThrottle=Never check rate limit (NOT RECOMMENDED)
2627

2728
GitHubLink.DisplayName=GitHub
2829

src/test/java/org/jenkinsci/plugins/github_branch_source/ApiRateLimitCheckerTest.java

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
import com.github.tomakehurst.wiremock.WireMockServer;
44
import com.github.tomakehurst.wiremock.client.ScenarioMappingBuilder;
5+
import com.github.tomakehurst.wiremock.http.RequestMethod;
56
import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder;
67
import com.github.tomakehurst.wiremock.stubbing.Scenario;
78
import hudson.util.LogTaskListener;
89
import hudson.util.RingBufferLogHandler;
10+
import org.jenkinsci.plugins.github.config.GitHubServerConfig;
911
import org.junit.Test;
1012
import org.junit.Before;
1113
import org.kohsuke.github.GitHub;
14+
import org.mockito.Mock;
15+
import org.mockito.Mockito;
1216

1317
import java.time.LocalDateTime;
1418
import java.time.ZoneId;
@@ -24,6 +28,7 @@
2428
import static com.github.tomakehurst.wiremock.client.WireMock.get;
2529
import static com.github.tomakehurst.wiremock.client.WireMock.resetAllScenarios;
2630
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
31+
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
2732

2833
public class ApiRateLimitCheckerTest extends AbstractGitHubWireMockTest {
2934

@@ -168,6 +173,51 @@ public void ThrottleOnNormalizeTestWithQuota() throws Exception {
168173
assertEquals(100, getRequestCount(githubApi));
169174
}
170175

176+
/**
177+
* Verify that "NoThrottle" does not contact the GitHub api nor output any logs
178+
*
179+
* @author Marc Salles Navarro
180+
*/
181+
@Test
182+
public void NoThrottleTestShouldNotThrottle() throws Exception {
183+
// set up scenarios
184+
List<RateLimit> scenarios = new ArrayList<>();
185+
int limit = 5000;
186+
// Keep decreasing quota until there's none left
187+
for (int i = 500; i >= 0; i--) {
188+
scenarios.add(new RateLimit(limit, i, soon));
189+
}
190+
setupStubs(scenarios);
191+
ApiRateLimitChecker.NoThrottle.checkApiRateLimit(listener, github);
192+
// there should be no output
193+
assertEquals(0, countOfOutputLines(m -> m.matches(".*[sS]leeping.*")));
194+
// github rate_limit endpoint should not be contacted
195+
assertEquals(0, getRequestCount(githubApi));
196+
}
197+
198+
/**
199+
* Verify that "NoThrottle" falls back to "ThrottleOnOver" if using GitHub.com
200+
*
201+
* @author Marc Salles Navarro
202+
*/
203+
@Test
204+
public void NoThrottleTestShouldFallbackToThrottleOnOverForGitHubDotCom() throws Exception {
205+
GitHub spy = Mockito.spy(github);
206+
Mockito.when(spy.getApiUrl()).thenReturn(GitHubServerConfig.GITHUB_URL).thenReturn(github.getApiUrl());
207+
// set up scenarios
208+
List<RateLimit> scenarios = new ArrayList<>();
209+
int limit = 5000;
210+
int buffer = ApiRateLimitChecker.calculateBuffer(limit);
211+
scenarios.add(new RateLimit(limit, buffer -1, soon));
212+
scenarios.add(new RateLimit(limit, limit, new Date(soon.getTime() + 2000)));
213+
setupStubs(scenarios);
214+
ApiRateLimitChecker.NoThrottle.checkApiRateLimit(listener, spy);
215+
216+
assertEquals(1, countOfOutputLines(m -> m.matches(".*[sS]leeping.*")));
217+
// github rate_limit endpoint should be contacted by ThrottleOnOver
218+
assertEquals(3, getRequestCount(githubApi));
219+
}
220+
171221
/**
172222
* Verify exactly when the throttle is occurring in "OnOver"
173223
*
@@ -198,7 +248,7 @@ public void ThrottleOnOverTest() throws Exception {
198248
}
199249

200250
//should be no output
201-
assertEquals(0, countOfOutputLines(m -> m.matches("[sS]leeping")));
251+
assertEquals(0, countOfOutputLines(m -> m.matches(".*[sS]leeping.*")));
202252

203253
assertEquals(11, getRequestCount(githubApi));
204254

@@ -491,7 +541,7 @@ public void NormalizeExpectedIdealOverTime() throws Exception {
491541
// Making sure the budgets are correct
492542
assertEquals(12, countOfOutputLinesContaining("0 under budget"));
493543
// no occurrences of sleeping
494-
assertEquals(0, countOfOutputLines(m -> m.matches("[sS]leeping")));
544+
assertEquals(0, countOfOutputLines(m -> m.matches(".*[sS]leeping.*")));
495545
}
496546

497547
/**

0 commit comments

Comments
 (0)