Skip to content

Commit e5b073f

Browse files
committed
Allow short-term caching of /builds
1 parent 9e53e29 commit e5b073f

File tree

3 files changed

+67
-17
lines changed

3 files changed

+67
-17
lines changed

src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/Api.kt

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package com.gabrielfeo.gradle.enterprise.api
44

55
import com.gabrielfeo.gradle.enterprise.api.internal.*
66
import java.io.File
7+
import kotlin.time.Duration.Companion.days
78

89
/**
910
* The global instance of [GradleEnterpriseApi].
@@ -42,19 +43,51 @@ fun shutdown() {
4243
}
4344

4445
/**
45-
* Regex pattern to match API URLs that are OK to store in the HTTP cache. Matches by default:
46+
* Regex pattern to match API URLs that are OK to store long-term in the HTTP cache, up to
47+
* [longTermCacheMaxAge] (1y by default, max value). By default, uses environment variable
48+
* `GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_URL_PATTERN` or a pattern matching:
4649
* - {host}/api/builds/{id}/gradle-attributes
4750
* - {host}/api/builds/{id}/maven-attributes
4851
*
49-
* By default, the Gradle Enterprise API disallows HTTP caching via response headers. This library
50-
* removes such headers to forcefully allow caching, if the path is matched by any of these
51-
* patterns.
52+
* Gradle Enterprise API disallows HTTP caching, but this library forcefully removes such
53+
* restriction.
5254
*
5355
* Use `|` to define multiple patterns in one, e.g. `.*gradle-attributes|.*test-distribution`.
56+
*/
57+
var longTermCacheUrlPattern: Regex =
58+
System.getenv("GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_URL_PATTERN")?.toRegex()
59+
?: """.*/api/builds/[\d\w]+/(?:gradle|maven)-attributes""".toRegex()
60+
61+
/**
62+
* Max age in seconds for URLs to be cached long-term (matched by [longTermCacheUrlPattern]).
63+
* By default, uses environment variable `GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_MAX_AGE` or 1 year.
64+
*/
65+
var longTermCacheMaxAge: Long =
66+
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE")?.toLong()
67+
?: 365.days.inWholeSeconds
68+
69+
/**
70+
* Regex pattern to match API URLs that are OK to store short-term in the HTTP cache, up to
71+
* [shortTermCacheMaxAge] (1d by default). By default, uses environment variable
72+
* `GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_URL_PATTERN` or a pattern matching:
73+
* - {host}/api/builds
74+
*
75+
* Gradle Enterprise API disallows HTTP caching, but this library forcefully removes such
76+
* restriction.
77+
*
78+
* Use `|` to define multiple patterns in one, e.g. `.*gradle-attributes|.*test-distribution`.
79+
*/
80+
var shortTermCacheUrlPattern: Regex =
81+
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_URL_PATTERN")?.toRegex()
82+
?: """.*/builds(?:\?.*|\Z)""".toRegex()
83+
84+
/**
85+
* Max age in seconds for URLs to be cached short-term (matched by [shortTermCacheUrlPattern]).
86+
* By default, uses environment variable `GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE` or 1 day.
5487
*/
55-
val cacheableUrlPattern: Regex = System.getenv("GRADLE_ENTERPRISE_API_CACHEABLE_URL_PATTERN")
56-
?.toRegex()
57-
?: """.*/api/builds/[\d\w]+/(?:gradle|maven)-attributes""".toRegex()
88+
var shortTermCacheMaxAge: Long =
89+
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE")?.toLong()
90+
?: 1.days.inWholeSeconds
5891

5992
/**
6093
* Maximum amount of concurrent requests allowed. Further requests will be queued. By default,
Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,33 @@
11
package com.gabrielfeo.gradle.enterprise.api.internal
22

3-
import com.gabrielfeo.gradle.enterprise.api.accessToken
43
import com.gabrielfeo.gradle.enterprise.api.auth.HttpBearerAuth
5-
import com.gabrielfeo.gradle.enterprise.api.cacheableUrlPattern
64
import com.gabrielfeo.gradle.enterprise.api.internal.caching.CacheEnforcingInterceptor
75
import com.gabrielfeo.gradle.enterprise.api.internal.caching.CacheHitLoggingInterceptor
86
import com.gabrielfeo.gradle.enterprise.api.internal.caching.cache
7+
import com.gabrielfeo.gradle.enterprise.api.accessToken
8+
import com.gabrielfeo.gradle.enterprise.api.longTermCacheMaxAge
9+
import com.gabrielfeo.gradle.enterprise.api.longTermCacheUrlPattern
910
import com.gabrielfeo.gradle.enterprise.api.maxConcurrentRequests
11+
import com.gabrielfeo.gradle.enterprise.api.shortTermCacheMaxAge
12+
import com.gabrielfeo.gradle.enterprise.api.shortTermCacheUrlPattern
1013
import okhttp3.OkHttpClient
1114

1215
val okHttpClient: OkHttpClient by lazy {
1316
OkHttpClient.Builder()
1417
.cache(cache)
1518
.addInterceptor(HttpBearerAuth("bearer", accessToken()))
1619
.addInterceptor(CacheHitLoggingInterceptor())
17-
.addNetworkInterceptor(CacheEnforcingInterceptor(cacheableUrlPattern))
20+
.addNetworkInterceptor(buildCacheEnforcingInterceptor())
1821
.build()
1922
.apply {
2023
dispatcher.maxRequests = maxConcurrentRequests
2124
dispatcher.maxRequestsPerHost = maxConcurrentRequests
2225
}
2326
}
27+
28+
private fun buildCacheEnforcingInterceptor() = CacheEnforcingInterceptor(
29+
longTermCacheUrlPattern = longTermCacheUrlPattern,
30+
longTermCacheMaxAge = longTermCacheMaxAge,
31+
shortTermCacheUrlPattern = shortTermCacheUrlPattern,
32+
shortTermCacheMaxAge = shortTermCacheMaxAge,
33+
)

src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/internal/caching/CacheEnforcingInterceptor.kt

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@ package com.gabrielfeo.gradle.enterprise.api.internal.caching
33
import okhttp3.Interceptor
44
import okhttp3.Request
55
import okhttp3.Response
6-
import kotlin.time.Duration.Companion.days
76

87
internal class CacheEnforcingInterceptor(
9-
private val cacheableUrlPattern: Regex,
8+
private val longTermCacheUrlPattern: Regex,
9+
private val longTermCacheMaxAge: Long,
10+
private val shortTermCacheUrlPattern: Regex,
11+
private val shortTermCacheMaxAge: Long,
1012
) : Interceptor {
1113

12-
private val maxAge = 365.days.inWholeMilliseconds
13-
1414
override fun intercept(chain: Interceptor.Chain): Response {
1515
val response = chain.proceed(chain.request())
16-
if (!isCacheable(response.request)) {
16+
val maxAge = maxAgeFor(response.request)
17+
if (maxAge <= 0) {
1718
return response
1819
}
1920
return response.newBuilder()
@@ -24,6 +25,12 @@ internal class CacheEnforcingInterceptor(
2425
.build()
2526
}
2627

27-
private fun isCacheable(request: Request) =
28-
cacheableUrlPattern.matches(request.url.toString())
28+
private fun maxAgeFor(request: Request): Long {
29+
val url = request.url.toString()
30+
return when {
31+
longTermCacheUrlPattern.matches(url) -> longTermCacheMaxAge
32+
shortTermCacheUrlPattern.matches(url) -> shortTermCacheMaxAge
33+
else -> 0
34+
}
35+
}
2936
}

0 commit comments

Comments
 (0)