Skip to content

Commit d2360b9

Browse files
authored
Improve javadoc and rename withOptions (#67)
- Add missing docs to `GradleEnterpriseApi` - Fix obsolete references to the old `GradleEnterpriseApi` replacing with `BuildsApi` - Move javadoc comments that were on the `GradleEnterpriseApi` impl by mistake - Name the companion instance so that it's clearer in the javadoc that it's a default instance - Rename `GradleEnterpriseApi.withOptions` to `newInstance`, which also fits and is more conventional - Minimize the number of symbols in the root javadoc page to the most important ones, by making `CacheOptions` a nested class, moving extensions to a new package, etc.
1 parent 3cb79cf commit d2360b9

File tree

12 files changed

+186
-146
lines changed

12 files changed

+186
-146
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ shutdown()
106106
```kotlin
107107
import com.gabrielfeo.gradle.enterprise.api.*
108108
import com.gabrielfeo.gradle.enterprise.api.model.*
109+
import com.gabrielfeo.gradle.enterprise.api.model.extension.*
109110
```
110111

111112
### Internals

examples/example-project/app/src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/example/Main.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ suspend fun main() {
1616
val newOptions = GradleEnterpriseApi.options.copy(
1717
clientBuilder = clientBuilder,
1818
)
19-
val gradleEnterpriseApi = GradleEnterpriseApi.withOptions(newOptions)
19+
val gradleEnterpriseApi = GradleEnterpriseApi.newInstance(newOptions)
2020
runAllAnalysis(gradleEnterpriseApi)
2121
gradleEnterpriseApi.shutdown()
2222
}

examples/example-project/app/src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/example/analysis/MostFrequentBuilds.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.gabrielfeo.gradle.enterprise.api.example.analysis
22

33
import com.gabrielfeo.gradle.enterprise.api.*
4+
import com.gabrielfeo.gradle.enterprise.api.extension.*
45
import com.gabrielfeo.gradle.enterprise.api.model.*
56
import kotlinx.coroutines.*
67
import kotlinx.coroutines.flow.*

library/src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/CacheOptions.kt

Lines changed: 0 additions & 121 deletions
This file was deleted.

library/src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/GradleEnterpriseApi.kt

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,65 @@ import com.gabrielfeo.gradle.enterprise.api.internal.infrastructure.Serializer
66
import retrofit2.Retrofit
77
import retrofit2.create
88

9+
/**
10+
* Gradle Enterprise API client. API endpoints are grouped exactly as in the
11+
* [Gradle Enterprise API Manual](https://docs.gradle.com/enterprise/api-manual/#reference_documentation):
12+
*
13+
* - [buildsApi]
14+
* - [buildCacheApi]
15+
* - [metaApi]
16+
* - [testDistributionApi]
17+
*
18+
* For simple use cases, you may use the companion instance ([DefaultInstance]) directly, as if
19+
* calling static methods:
20+
*
21+
* ```kotlin
22+
* GradleEnterpriseApi.buildsApi.getBuilds(...)
23+
* ```
24+
*
25+
* However, if you need to change [options] at runtime or own the instance's lifecycle (e.g.
26+
* with an IoC container like Dagger), create a new instance:
27+
*
28+
* ```kotlin
29+
* val options = Options(clientBuilder = myOwnOkHttpClient.newBuilder())
30+
* val api = GradleEnterpriseApi.newInstance(options)
31+
* api.buildsApi.getBuilds(...)
32+
* ```
33+
*/
934
interface GradleEnterpriseApi {
1035

1136
val buildsApi: BuildsApi
1237
val buildCacheApi: BuildCacheApi
1338
val metaApi: MetaApi
1439
val testDistributionApi: TestDistributionApi
1540

41+
/**
42+
* Library configuration options.
43+
*/
1644
val options: Options
17-
fun withOptions(options: Options): GradleEnterpriseApi
45+
46+
/**
47+
* Release resources allowing the program to finish before the internal client's idle timeout.
48+
*/
1849
fun shutdown()
1950

20-
companion object : GradleEnterpriseApi by DefaultGradleEnterpriseApi()
51+
/**
52+
* The default, companion instance of the Gradle Enterprise API client. See
53+
* [GradleEnterpriseApi].
54+
*/
55+
companion object DefaultInstance : GradleEnterpriseApi by RealGradleEnterpriseApi() {
56+
57+
/**
58+
* Create a new instance of `GradleEnterpriseApi` with new options.
59+
*/
60+
fun newInstance(options: Options): GradleEnterpriseApi {
61+
return RealGradleEnterpriseApi(options)
62+
}
63+
}
2164

2265
}
2366

24-
private class DefaultGradleEnterpriseApi(
67+
private class RealGradleEnterpriseApi(
2568
override val options: Options = Options(),
2669
) : GradleEnterpriseApi {
2770

@@ -42,12 +85,6 @@ private class DefaultGradleEnterpriseApi(
4285
override val metaApi: MetaApi by lazy(retrofit::create)
4386
override val testDistributionApi: TestDistributionApi by lazy(retrofit::create)
4487

45-
override fun withOptions(options: Options) = DefaultGradleEnterpriseApi(options)
46-
47-
48-
/**
49-
* Release resources allowing the program to finish before the internal client's idle timeout.
50-
*/
5188
override fun shutdown() {
5289
okHttpClient.run {
5390
dispatcher.executorService.shutdown()

library/src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/Options.kt

Lines changed: 120 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ package com.gabrielfeo.gradle.enterprise.api
33
import com.gabrielfeo.gradle.enterprise.api.internal.*
44
import okhttp3.Dispatcher
55
import okhttp3.OkHttpClient
6+
import java.io.File
67
import java.util.logging.Logger
8+
import kotlin.time.Duration.Companion.days
79

810
/**
9-
* Library configuration options. Should not be changed after accessing the [gradleEnterpriseApi]
10-
* object for the first time.
11+
* Library configuration options.
1112
*/
1213
@Suppress("MemberVisibilityCanBePrivate", "unused")
1314
data class Options(
@@ -73,9 +74,124 @@ data class Options(
7374
*/
7475
val cacheOptions: CacheOptions =
7576
CacheOptions(),
76-
)
77+
) {
7778

78-
fun requireEnvOrKeychainToken(debugLoggingEnabled: Boolean): String {
79+
/**
80+
* HTTP cache is off by default, but can speed up requests significantly. The Gradle Enterprise
81+
* API disallows HTTP caching, but this library forcefully enables it by overwriting
82+
* cache-related headers in API responses. Enable with [cacheEnabled].
83+
*
84+
* Responses can be:
85+
*
86+
* - cached short-term: default max-age of 1 day
87+
* - `/api/builds`
88+
* - cached long-term: default max-age of 1 year
89+
* - `/api/builds/{id}/gradle-attributes`
90+
* - `/api/builds/{id}/maven-attributes`
91+
* - `/api/builds/{id}/gradle-build-cache-performance`
92+
* - `/api/builds/{id}/maven-build-cache-performance`
93+
* - not cached
94+
* - all other paths
95+
*
96+
* Whether a response is cached short-term, long-term or not cached at
97+
* all depends on whether it was matched by [shortTermCacheUrlPattern] or
98+
* [longTermCacheUrlPattern].
99+
*
100+
* Whenever GE is upgraded, cache should be [clear]ed.
101+
*
102+
* ### Caveats
103+
*
104+
* While not encouraged by the API, caching shouldn't have any major downsides other than a
105+
* time gap for certain queries, or having to reset cache when GE is upgraded.
106+
*
107+
* #### Time gap
108+
*
109+
* `/api/builds` responses always change as new builds are uploaded. Caching this path
110+
* short-term (default 1 day) means new builds uploaded after the cached response won't be
111+
* included in the query until the cache is invalidated 24h later. If that's a problem,
112+
* caching can be disabled for this `/api/builds` by changing [shortTermCacheUrlPattern].
113+
*
114+
* #### GE upgrades
115+
*
116+
* When GE is upgraded, any API response can change. New data might be available in API
117+
* endpoints such as `/api/build/{id}/gradle-attributes`. Thus, whenever the GE version
118+
* itself is upgraded, cache should be [clear]ed.
119+
*/
120+
@Suppress("MemberVisibilityCanBePrivate")
121+
data class CacheOptions(
122+
123+
/**
124+
* Whether caching is enabled. By default, uses environment variable
125+
* `GRADLE_ENTERPRISE_API_CACHE_ENABLED` or `false`.
126+
*/
127+
val cacheEnabled: Boolean =
128+
env["GRADLE_ENTERPRISE_API_CACHE_ENABLED"].toBoolean(),
129+
130+
/**
131+
* HTTP cache location. By default, uses environment variable `GRADLE_ENTERPRISE_API_CACHE_DIR`
132+
* or the system temporary folder (`java.io.tmpdir` / gradle-enterprise-api-kotlin-cache).
133+
*/
134+
val cacheDir: File =
135+
env["GRADLE_ENTERPRISE_API_CACHE_DIR"]?.let(::File)
136+
?: File(System.getProperty("java.io.tmpdir"), "gradle-enterprise-api-kotlin-cache"),
137+
138+
/**
139+
* Max size of the HTTP cache. By default, uses environment variable
140+
* `GRADLE_ENTERPRISE_API_MAX_CACHE_SIZE` or ~1 GB.
141+
*/
142+
val maxCacheSize: Long = env["GRADLE_ENTERPRISE_API_MAX_CACHE_SIZE"]?.toLong()
143+
?: 1_000_000_000L,
144+
145+
/**
146+
* Regex pattern to match API URLs that are OK to store long-term in the HTTP cache, up to
147+
* [longTermCacheMaxAge] (1y by default, max value). By default, uses environment variable
148+
* `GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_URL_PATTERN` or a pattern matching:
149+
* - {host}/api/builds/{id}/gradle-attributes
150+
* - {host}/api/builds/{id}/maven-attributes
151+
* - {host}/api/builds/{id}/gradle-build-cache-performance
152+
* - {host}/api/builds/{id}/maven-build-cache-performance
153+
*
154+
* Use `|` to define multiple patterns in one, e.g. `.*gradle-attributes|.*test-distribution`.
155+
*/
156+
val longTermCacheUrlPattern: Regex =
157+
env["GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_URL_PATTERN"]?.toRegex()
158+
?: Regex(
159+
"""
160+
.*/api/builds/[\d\w]+/(?:gradle|maven)-(?:attributes|build-cache-performance)
161+
""".trimIndent()
162+
),
163+
164+
/**
165+
* Max age in seconds for URLs to be cached long-term (matched by [longTermCacheUrlPattern]).
166+
* By default, uses environment variable `GRADLE_ENTERPRISE_API_LONG_TERM_CACHE_MAX_AGE` or 1 year.
167+
*/
168+
val longTermCacheMaxAge: Long =
169+
env["GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE"]?.toLong()
170+
?: 365.days.inWholeSeconds,
171+
172+
/**
173+
* Regex pattern to match API URLs that are OK to store short-term in the HTTP cache, up to
174+
* [shortTermCacheMaxAge] (1d by default). By default, uses environment variable
175+
* `GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_URL_PATTERN` or a pattern matching:
176+
* - {host}/api/builds
177+
*
178+
* Use `|` to define multiple patterns in one, e.g. `.*gradle-attributes|.*test-distribution`.
179+
*/
180+
val shortTermCacheUrlPattern: Regex =
181+
env["GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_URL_PATTERN"]?.toRegex()
182+
?: """.*/builds(?:\?.*|\Z)""".toRegex(),
183+
184+
/**
185+
* Max age in seconds for URLs to be cached short-term (matched by [shortTermCacheUrlPattern]).
186+
* By default, uses environment variable `GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE` or 1 day.
187+
*/
188+
val shortTermCacheMaxAge: Long =
189+
env["GRADLE_ENTERPRISE_API_SHORT_TERM_CACHE_MAX_AGE"]?.toLong()
190+
?: 1.days.inWholeSeconds,
191+
)
192+
}
193+
194+
internal fun requireEnvOrKeychainToken(debugLoggingEnabled: Boolean): String {
79195
if (systemProperties["os.name"] == "Mac OS X") {
80196
when (val result = keychain.get("gradle-enterprise-api-token")) {
81197
is KeychainResult.Success -> return result.token
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
package com.gabrielfeo.gradle.enterprise.api.model
1+
package com.gabrielfeo.gradle.enterprise.api.extension
2+
3+
import com.gabrielfeo.gradle.enterprise.api.model.BuildAttributesValue
24

35
operator fun List<BuildAttributesValue>.get(name: String): String? {
46
return find { it.name == name }?.value

0 commit comments

Comments
 (0)