Skip to content

Commit f9e4231

Browse files
committed
Allow short-term caching of /builds
1 parent 7f8f96c commit f9e4231

File tree

3 files changed

+65
-17
lines changed

3 files changed

+65
-17
lines changed

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

Lines changed: 38 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,49 @@ 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). The default pattern matches:
4648
* - {host}/api/builds/{id}/gradle-attributes
4749
* - {host}/api/builds/{id}/maven-attributes
4850
*
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.
51+
* Gradle Enterprise API disallows HTTP caching, but this library forcefully removes such
52+
* restriction.
5253
*
5354
* Use `|` to define multiple patterns in one, e.g. `.*gradle-attributes|.*test-distribution`.
55+
*/
56+
var longTermCacheUrlPattern: Regex =
57+
System.getenv("GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_URL_PATTERN")?.toRegex()
58+
?: """.*/api/builds/[\d\w]+/(?:gradle|maven)-attributes""".toRegex()
59+
60+
/**
61+
* Max age in seconds for URLs to be cached long-term (matched by [longTermCacheUrlPattern]).
62+
* Defaults to 1 year.
63+
*/
64+
var longTermCacheMaxAge: Long =
65+
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE")?.toLong()
66+
?: 365.days.inWholeSeconds
67+
68+
/**
69+
* Regex pattern to match API URLs that are OK to store short-term in the HTTP cache, up to
70+
* [shortTermCacheMaxAge] (1d by default). The default pattern matches:
71+
* - {host}/api/builds
72+
*
73+
* Gradle Enterprise API disallows HTTP caching, but this library forcefully removes such
74+
* restriction.
75+
*
76+
* Use `|` to define multiple patterns in one, e.g. `.*gradle-attributes|.*test-distribution`.
77+
*/
78+
var shortTermCacheUrlPattern: Regex =
79+
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_URL_PATTERN")?.toRegex()
80+
?: """.*/builds(?:\?.*|\Z)""".toRegex()
81+
82+
/**
83+
* Max age in seconds for URLs to be cached short-term (matched by [shortTermCacheUrlPattern]).
84+
* Defaults to 1 day.
5485
*/
55-
val cacheableUrlPattern: Regex = System.getenv("GRADLE_ENTERPRISE_API_CACHEABLE_URL_PATTERN")
56-
?.toRegex()
57-
?: """.*/api/builds/[\d\w]+/(?:gradle|maven)-attributes""".toRegex()
86+
var shortTermCacheMaxAge: Long =
87+
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE")?.toLong()
88+
?: 1.days.inWholeSeconds
5889

5990
/**
6091
* 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)