Skip to content

Commit 9fa69ca

Browse files
committed
Add cacheEnabled option and re-organize Options
1 parent 771733f commit 9fa69ca

File tree

8 files changed

+200
-120
lines changed

8 files changed

+200
-120
lines changed

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Gradle Enterprise API Kotlin
22

3-
[![Release](https://jitpack.io/v/gabrielfeo/gradle-enterprise-api-kotlin.svg)](https://jitpack.io/#gabrielfeo/gradle-enterprise-api-kotlin)
4-
[![Javadoc](https://img.shields.io/badge/javadoc-0.9-orange)](https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/)
3+
[![Release](https://jitpack.io/v/gabrielfeo/gradle-enterprise-api-kotlin.svg)][14]
4+
[![Javadoc](https://img.shields.io/badge/javadoc-latest-orange)][15]
55

66
A Kotlin library to access the [Gradle Enterprise API][1], easy to use from Kotlin
77
scripts:
@@ -32,7 +32,9 @@ api.getBuild(id = "hy5nxbzfjxe5k")
3232
```
3333

3434
For configuring base URL and token via code and other available options, see the
35-
[`Options` object][8].
35+
[`Options` object][8]. HTTP caching is available, which can speed up queries significantly, but is
36+
off by default. Enable with [`GRADLE_ENTERPRISE_API_CACHE_ENABLED`][12]. See [`Options.Cache`][13]
37+
for caveats.
3638

3739
<details>
3840
<summary>Setup in full projects (non-scripts)</summary>
@@ -73,7 +75,7 @@ initialized and ready-to-use as the global `api` instance:
7375
api.getBuild(id = "hy5nxbzfjxe5k")
7476
```
7577

76-
The library also provides a few extension functions on top of the regular API, such as paged
78+
The library also provides a few extension functions on top of the regular API, such as paged
7779
requests and joining. See [`GradleEnterpriseApi` extensions][10].
7880

7981
```kotlin
@@ -83,7 +85,7 @@ api.getBuilds(since = lastMonth)
8385
api.getBuildsFlow(since = lastMonth)
8486
```
8587

86-
It's recommended to call [`shutdown()`][11] at the end of scripts to release resources and let the
88+
It's recommended to call [`shutdown()`][11] at the end of scripts to release resources and let the
8789
program exit. Otherwise, it'll keep running for an extra ~60s after code finishes, as an [expected
8890
behavior of OkHttp][4].
8991

@@ -98,7 +100,7 @@ shutdown()
98100
- Currently built for Gradle Enterprise `2022.4`, but should work fine with previous versions.
99101
- Use JDK 8 or 14+ to run, if you want to avoid the ["illegal reflective access" warning about
100102
Retrofit][3]
101-
- All classes live in these two packages. If you need to make small edits to scripts where
103+
- All classes live in these two packages. If you need to make small edits to scripts where
102104
there's no auto-complete, wildcard imports can be used:
103105

104106
```kotlin
@@ -122,3 +124,7 @@ API classes such as `GradleEnterpriseApi` and response models are generated from
122124
[9]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/gradle-enterprise-api-kotlin/com.gabrielfeo.gradle.enterprise.api/-gradle-enterprise-api/
123125
[10]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/gradle-enterprise-api-kotlin/com.gabrielfeo.gradle.enterprise.api/-gradle-enterprise-api/index.html#373241164%2FExtensions%2F769193423
124126
[11]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/gradle-enterprise-api-kotlin/com.gabrielfeo.gradle.enterprise.api/shutdown.html
127+
[12]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/gradle-enterprise-api-kotlin/com.gabrielfeo.gradle.enterprise.api/-options/-cache/index.html#-1054137809%2FProperties%2F769193423
128+
[13]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/gradle-enterprise-api-kotlin/com.gabrielfeo.gradle.enterprise.api/-options/-cache/index.html
129+
[14]: https://jitpack.io/#gabrielfeo/gradle-enterprise-api-kotlin
130+
[15]: https://gabrielfeo.github.io/gradle-enterprise-api-kotlin/

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ plugins {
1010
}
1111

1212
group = "com.github.gabrielfeo"
13-
version = "0.9"
13+
version = "0.10.0"
1414

1515
val downloadApiSpec by tasks.registering {
1616
val geVersion = providers.gradleProperty("gradle.enterprise.version").get()
Lines changed: 153 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
@file:Suppress("MemberVisibilityCanBePrivate")
2+
13
package com.gabrielfeo.gradle.enterprise.api
24

5+
import com.gabrielfeo.gradle.enterprise.api.Options.Cache.clear
6+
import com.gabrielfeo.gradle.enterprise.api.Options.Cache.longTermCacheUrlPattern
7+
import com.gabrielfeo.gradle.enterprise.api.Options.Cache.shortTermCacheUrlPattern
8+
import com.gabrielfeo.gradle.enterprise.api.internal.buildCache
39
import com.gabrielfeo.gradle.enterprise.api.internal.requireBaseUrl
410
import com.gabrielfeo.gradle.enterprise.api.internal.requireToken
511
import java.io.File
@@ -12,101 +18,169 @@ import kotlin.time.Duration.Companion.days
1218
object Options {
1319

1420
/**
15-
* Provides the URL of a Gradle Enterprise API instance. By default, uses environment variable
16-
* `GRADLE_ENTERPRISE_URL`.
21+
* Options about the GE instance, such as URL and API token.
1722
*/
18-
var baseUrl: () -> String = {
19-
requireBaseUrl(envName = "GRADLE_ENTERPRISE_URL")
23+
object GradleEnterpriseInstance {
24+
25+
/**
26+
* Provides the URL of a Gradle Enterprise API instance. By default, uses environment variable
27+
* `GRADLE_ENTERPRISE_URL`.
28+
*/
29+
var baseUrl: () -> String = {
30+
requireBaseUrl(envName = "GRADLE_ENTERPRISE_URL")
31+
}
32+
33+
/**
34+
* Provides the access token for a Gradle Enterprise API instance. By default, uses keychain entry
35+
* `gradle-enterprise-api-token` or environment variable `GRADLE_ENTERPRISE_URL`.
36+
*/
37+
var accessToken: () -> String = {
38+
requireToken(
39+
keychainName = "gradle-enterprise-api-token",
40+
envName = "GRADLE_ENTERPRISE_API_TOKEN",
41+
)
42+
}
2043
}
2144

2245
/**
23-
* Provides the access token for a Gradle Enterprise API instance. By default, uses keychain entry
24-
* `gradle-enterprise-api-token` or environment variable `GRADLE_ENTERPRISE_URL`.
46+
* Concurrency options.
2547
*/
26-
var accessToken: () -> String = {
27-
requireToken(
28-
keychainName = "gradle-enterprise-api-token",
29-
envName = "GRADLE_ENTERPRISE_API_TOKEN",
30-
)
48+
object Concurrency {
49+
50+
/**
51+
* Maximum amount of concurrent requests allowed. Further requests will be queued. By default,
52+
* uses environment variable `GRADLE_ENTERPRISE_API_MAX_CONCURRENT_REQUESTS` or 15.
53+
*
54+
* https://square.github.io/okhttp/4.x/okhttp/okhttp3/-dispatcher
55+
*/
56+
var maxConcurrentRequests =
57+
System.getenv("GRADLE_ENTERPRISE_API_MAX_CONCURRENT_REQUESTS")?.toInt()
58+
?: 15
3159
}
3260

3361
/**
34-
* Maximum amount of concurrent requests allowed. Further requests will be queued. By default,
35-
* uses environment variable `GRADLE_ENTERPRISE_API_MAX_CONCURRENT_REQUESTS` or 15.
62+
* HTTP cache is off by default, but can speed up requests significantly. The Gradle Enterprise
63+
* API disallows HTTP caching, but this library forcefully enables it by overwriting
64+
* cache-related headers in API responses. Enable with [cacheEnabled].
65+
*
66+
* Responses can be:
67+
*
68+
* - cached short-term: default max-age of 1 day
69+
* - `/api/builds`
70+
* - cached long-term: default max-age of 1 year
71+
* - `/api/builds/{id}/gradle-attributes`
72+
* - `/api/builds/{id}/maven-attributes`
73+
* - not cached
74+
* - all other paths
75+
*
76+
* Whether a response is cached short-term, long-term or not cached at
77+
* all depends on whether it was matched by [shortTermCacheUrlPattern] or
78+
* [longTermCacheUrlPattern].
79+
*
80+
* Whenever GE is upgraded, cache should be [clear]ed.
81+
*
82+
* ### Caveats
3683
*
37-
* https://square.github.io/okhttp/4.x/okhttp/okhttp3/-dispatcher
84+
* While not encouraged by the API, caching shouldn't have any major downsides other than a
85+
* time gap for certain queries, or having to reset cache when GE is upgraded.
86+
*
87+
* #### Time gap
88+
*
89+
* `/api/builds` responses always change as new builds are uploaded. Caching this path
90+
* short-term (default 1 day) means new builds uploaded after the cached response won't be
91+
* included in the query until the cache is invalidated 24h later. If that's a problem,
92+
* caching can be disabled for this `/api/builds` by changing [shortTermCacheUrlPattern].
93+
*
94+
* #### GE upgrades
95+
*
96+
* When GE is upgraded, any API response can change. New data might be available in API
97+
* endpoints such as `/api/build/{id}/gradle-attributes`. Thus, whenever the GE version
98+
* itself is upgraded, cache should be [clear]ed.
3899
*/
39-
var maxConcurrentRequests =
40-
System.getenv("GRADLE_ENTERPRISE_API_MAX_CONCURRENT_REQUESTS")?.toInt()
41-
?: 15
100+
object Cache {
42101

43-
/**
44-
* HTTP cache location. By default, uses environment variable `GRADLE_ENTERPRISE_API_CACHE_DIR`
45-
* or the system temporary folder (`java.io.tmpdir` / gradle-enterprise-api-kotlin-cache).
46-
*/
47-
var cacheDir =
48-
System.getenv("GRADLE_ENTERPRISE_API_CACHE_DIR")?.let(::File)
49-
?: File(System.getProperty("java.io.tmpdir"), "gradle-enterprise-api-kotlin-cache")
102+
/**
103+
* Whether caching is enabled. By default, uses environment variable
104+
* `GRADLE_ENTERPRISE_API_CACHE_ENABLED` or `false`.
105+
*/
106+
var cacheEnabled: Boolean =
107+
System.getenv("GRADLE_ENTERPRISE_API_CACHE_ENABLED").toBoolean()
50108

51-
/**
52-
* Max size of the HTTP cache. By default, uses environment variable
53-
* `GRADLE_ENTERPRISE_API_MAX_CACHE_SIZE` or ~1 GB.
54-
*/
55-
var maxCacheSize =
56-
System.getenv("GRADLE_ENTERPRISE_API_MAX_CACHE_SIZE")?.toLong()
57-
?: 1_000_000_000L
109+
/**
110+
* Clears [cacheDir] including files that weren't created by the cache.
111+
*/
112+
fun clear() {
113+
buildCache().delete()
114+
}
58115

59-
/**
60-
* Regex pattern to match API URLs that are OK to store long-term in the HTTP cache, up to
61-
* [longTermCacheMaxAge] (1y by default, max value). By default, uses environment variable
62-
* `GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_URL_PATTERN` or a pattern matching:
63-
* - {host}/api/builds/{id}/gradle-attributes
64-
* - {host}/api/builds/{id}/maven-attributes
65-
*
66-
* Gradle Enterprise API disallows HTTP caching, but this library forcefully removes such
67-
* restriction.
68-
*
69-
* Use `|` to define multiple patterns in one, e.g. `.*gradle-attributes|.*test-distribution`.
70-
*/
71-
var longTermCacheUrlPattern: Regex =
72-
System.getenv("GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_URL_PATTERN")?.toRegex()
73-
?: """.*/api/builds/[\d\w]+/(?:gradle|maven)-attributes""".toRegex()
116+
/**
117+
* HTTP cache location. By default, uses environment variable `GRADLE_ENTERPRISE_API_CACHE_DIR`
118+
* or the system temporary folder (`java.io.tmpdir` / gradle-enterprise-api-kotlin-cache).
119+
*/
120+
var cacheDir =
121+
System.getenv("GRADLE_ENTERPRISE_API_CACHE_DIR")?.let(::File)
122+
?: File(System.getProperty("java.io.tmpdir"), "gradle-enterprise-api-kotlin-cache")
74123

75-
/**
76-
* Max age in seconds for URLs to be cached long-term (matched by [longTermCacheUrlPattern]).
77-
* By default, uses environment variable `GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_MAX_AGE` or 1 year.
78-
*/
79-
var longTermCacheMaxAge: Long =
80-
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE")?.toLong()
81-
?: 365.days.inWholeSeconds
124+
/**
125+
* Max size of the HTTP cache. By default, uses environment variable
126+
* `GRADLE_ENTERPRISE_API_MAX_CACHE_SIZE` or ~1 GB.
127+
*/
128+
var maxCacheSize =
129+
System.getenv("GRADLE_ENTERPRISE_API_MAX_CACHE_SIZE")?.toLong()
130+
?: 1_000_000_000L
82131

83-
/**
84-
* Regex pattern to match API URLs that are OK to store short-term in the HTTP cache, up to
85-
* [shortTermCacheMaxAge] (1d by default). By default, uses environment variable
86-
* `GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_URL_PATTERN` or a pattern matching:
87-
* - {host}/api/builds
88-
*
89-
* Gradle Enterprise API disallows HTTP caching, but this library forcefully removes such
90-
* restriction.
91-
*
92-
* Use `|` to define multiple patterns in one, e.g. `.*gradle-attributes|.*test-distribution`.
93-
*/
94-
var shortTermCacheUrlPattern: Regex =
95-
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_URL_PATTERN")?.toRegex()
96-
?: """.*/builds(?:\?.*|\Z)""".toRegex()
132+
/**
133+
* Regex pattern to match API URLs that are OK to store long-term in the HTTP cache, up to
134+
* [longTermCacheMaxAge] (1y by default, max value). By default, uses environment variable
135+
* `GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_URL_PATTERN` or a pattern matching:
136+
* - {host}/api/builds/{id}/gradle-attributes
137+
* - {host}/api/builds/{id}/maven-attributes
138+
*
139+
* Use `|` to define multiple patterns in one, e.g. `.*gradle-attributes|.*test-distribution`.
140+
*/
141+
var longTermCacheUrlPattern: Regex =
142+
System.getenv("GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_URL_PATTERN")?.toRegex()
143+
?: """.*/api/builds/[\d\w]+/(?:gradle|maven)-attributes""".toRegex()
97144

98-
/**
99-
* Max age in seconds for URLs to be cached short-term (matched by [shortTermCacheUrlPattern]).
100-
* By default, uses environment variable `GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE` or 1 day.
101-
*/
102-
var shortTermCacheMaxAge: Long =
103-
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE")?.toLong()
104-
?: 1.days.inWholeSeconds
145+
/**
146+
* Max age in seconds for URLs to be cached long-term (matched by [longTermCacheUrlPattern]).
147+
* By default, uses environment variable `GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_MAX_AGE` or 1 year.
148+
*/
149+
var longTermCacheMaxAge: Long =
150+
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE")?.toLong()
151+
?: 365.days.inWholeSeconds
152+
153+
/**
154+
* Regex pattern to match API URLs that are OK to store short-term in the HTTP cache, up to
155+
* [shortTermCacheMaxAge] (1d by default). By default, uses environment variable
156+
* `GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_URL_PATTERN` or a pattern matching:
157+
* - {host}/api/builds
158+
*
159+
* Use `|` to define multiple patterns in one, e.g. `.*gradle-attributes|.*test-distribution`.
160+
*/
161+
var shortTermCacheUrlPattern: Regex =
162+
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_URL_PATTERN")?.toRegex()
163+
?: """.*/builds(?:\?.*|\Z)""".toRegex()
164+
165+
/**
166+
* Max age in seconds for URLs to be cached short-term (matched by [shortTermCacheUrlPattern]).
167+
* By default, uses environment variable `GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE` or 1 day.
168+
*/
169+
var shortTermCacheMaxAge: Long =
170+
System.getenv("GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE")?.toLong()
171+
?: 1.days.inWholeSeconds
172+
}
105173

106174
/**
107-
* Enables debug logging from the library. All logging is output to stderr. By default, uses
108-
* environment variable `GRADLE_ENTERPRISE_API_DEBUG_LOGGING` or `false`.
175+
* Library debugging options.
109176
*/
110-
var debugLoggingEnabled =
111-
System.getenv("GRADLE_ENTERPRISE_API_DEBUG_LOGGING").toBoolean()
112-
}
177+
object Debugging {
178+
179+
/**
180+
* Enables debug logging from the library. All logging is output to stderr. By default, uses
181+
* environment variable `GRADLE_ENTERPRISE_API_DEBUG_LOGGING` or `false`.
182+
*/
183+
var debugLoggingEnabled =
184+
System.getenv("GRADLE_ENTERPRISE_API_DEBUG_LOGGING").toBoolean()
185+
}
186+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ internal fun requireToken(
2020

2121
private fun tokenFromEnv(varName: String): String? {
2222
return System.getenv(varName).also {
23-
if (Options.debugLoggingEnabled && it.isNullOrBlank()) {
23+
if (Options.Debugging.debugLoggingEnabled && it.isNullOrBlank()) {
2424
Logger.getGlobal().log(INFO, "Env var $varName=$it")
2525
}
2626
}
@@ -36,7 +36,7 @@ private fun tokenFromKeychain(keyName: String): String? {
3636
return process.inputStream.bufferedReader().use {
3737
it.readText().trim()
3838
}
39-
} else if (Options.debugLoggingEnabled) {
39+
} else if (Options.Debugging.debugLoggingEnabled) {
4040
Logger.getGlobal().log(INFO, "Failed to get key from keychain (exit $status)")
4141
}
4242
return null

0 commit comments

Comments
 (0)