Skip to content

Commit dc35d41

Browse files
authored
Fix wildcards in Retrofit services and increase read timeout (#40)
Fix issues found using the feature preview spec: - Add `@JvmSuppressWildcards` to avoid runtime Retrofit errors. When specs generate strongly typed code, such as `kotlin.collections.List<ApiType>`, for Java interop this is `java.util.List<? extends ApiType>` which is not allowed by Retrofit. - Increase default read timeout and support overriding it, as some endpoints would timeout with default 10s - Also add full request logging if debugLoggingEnabled and fix overriding `-Pversion`, which was always overwritten by the buildscipt
1 parent d129900 commit dc35d41

File tree

6 files changed

+68
-8
lines changed

6 files changed

+68
-8
lines changed

build.gradle.kts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ plugins {
1111
}
1212

1313
group = "com.github.gabrielfeo"
14-
version = "SNAPSHOT"
1514
val repoUrl = "https://github.com/gabrielfeo/gradle-enterprise-api-kotlin"
1615

1716
val localSpecPath = providers.gradleProperty("localSpecPath")
@@ -73,6 +72,24 @@ tasks.openApiGenerate.configure {
7372
)
7473
}
7574
}
75+
// Add @JvmSuppressWildcards to avoid square/retrofit#3275
76+
doLast {
77+
val apiFile = File(
78+
outputDir.get(),
79+
"src/main/kotlin/com/gabrielfeo/gradle/enterprise/api/GradleEnterpriseApi.kt",
80+
)
81+
ant.withGroovyBuilder {
82+
"replaceregexp"(
83+
"file" to apiFile,
84+
"match" to "interface GradleEnterpriseApi",
85+
"replace" to """
86+
@JvmSuppressWildcards
87+
interface GradleEnterpriseApi
88+
""".trimIndent(),
89+
"flags" to "m",
90+
)
91+
}
92+
}
7693
// Workaround for properties generated with `arrayListOf(null,null)` as default value
7794
doLast {
7895
val srcDir = File(outputDir.get(), "src/main/kotlin")
@@ -177,6 +194,7 @@ dependencies {
177194
api("com.squareup.moshi:moshi:1.14.0")
178195
implementation("com.squareup.moshi:moshi-kotlin:1.14.0")
179196
api("com.squareup.okhttp3:okhttp:4.10.0")
197+
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
180198
api("com.squareup.retrofit2:retrofit:2.9.0")
181199
implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
182200
implementation("com.squareup.retrofit2:converter-scalars:2.9.0")

gradle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
org.gradle.jvmargs=-Xmx5g
22
org.gradle.caching=true
3+
version=SNAPSHOT
34
# Must be later than 2022.1
45
gradle.enterprise.version=2022.4

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,15 @@ class Options internal constructor(
9191
*/
9292
var maxConcurrentRequests =
9393
env["GRADLE_ENTERPRISE_API_MAX_CONCURRENT_REQUESTS"]?.toInt()
94+
95+
/**
96+
* Timeout for reading an API response, used for [OkHttpClient.readTimeoutMillis].
97+
* By default, uses environment variable `GRADLE_ENTERPRISE_API_READ_TIMEOUT_MILLIS`
98+
* or 60_000. Keep in mind that GE API responses can be big and slow to send depending on
99+
* the endpoint.
100+
*/
101+
var readTimeoutMillis: Long = env["GRADLE_ENTERPRISE_API_READ_TIMEOUT_MILLIS"]?.toLong()
102+
?: 60_000L
94103
}
95104

96105
/**

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import com.gabrielfeo.gradle.enterprise.api.internal.auth.HttpBearerAuth
55
import com.gabrielfeo.gradle.enterprise.api.internal.caching.CacheEnforcingInterceptor
66
import com.gabrielfeo.gradle.enterprise.api.internal.caching.CacheHitLoggingInterceptor
77
import okhttp3.Cache
8+
import okhttp3.OkHttpClient
9+
import okhttp3.logging.HttpLoggingInterceptor
10+
import okhttp3.logging.HttpLoggingInterceptor.Level.BODY
11+
import java.time.Duration
812
import java.util.logging.Level
913
import java.util.logging.Logger
1014

@@ -15,22 +19,34 @@ internal val okHttpClient by lazy {
1519
internal fun buildOkHttpClient(
1620
options: Options,
1721
) = with(options.httpClient.clientBuilder()) {
22+
readTimeout(Duration.ofMillis(options.httpClient.readTimeoutMillis))
1823
if (options.cache.cacheEnabled) {
1924
cache(buildCache(options))
2025
}
26+
addInterceptors(options)
27+
addNetworkInterceptors(options)
28+
build().apply {
29+
options.httpClient.maxConcurrentRequests?.let {
30+
dispatcher.maxRequests = it
31+
dispatcher.maxRequestsPerHost = it
32+
}
33+
}
34+
}
35+
36+
private fun OkHttpClient.Builder.addInterceptors(options: Options) {
2137
if (options.debugging.debugLoggingEnabled && options.cache.cacheEnabled) {
2238
addInterceptor(CacheHitLoggingInterceptor())
2339
}
24-
addInterceptor(HttpBearerAuth("bearer", options.gradleEnterpriseInstance.token()))
40+
}
41+
42+
private fun OkHttpClient.Builder.addNetworkInterceptors(options: Options) {
2543
if (options.cache.cacheEnabled) {
2644
addNetworkInterceptor(buildCacheEnforcingInterceptor(options))
2745
}
28-
build().apply {
29-
options.httpClient.maxConcurrentRequests?.let {
30-
dispatcher.maxRequests = it
31-
dispatcher.maxRequestsPerHost = it
32-
}
46+
if (options.debugging.debugLoggingEnabled) {
47+
addNetworkInterceptor(HttpLoggingInterceptor().apply { level = BODY })
3348
}
49+
addNetworkInterceptor(HttpBearerAuth("bearer", options.gradleEnterpriseInstance.token()))
3450
}
3551

3652
internal fun buildCache(

src/test/kotlin/com/gabrielfeo/gradle/enterprise/api/OkHttpClientTest.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class OkHttpClientTest {
1515
@Test
1616
fun `Adds authentication`() {
1717
val client = buildClient()
18-
assertTrue(client.interceptors.any { it is HttpBearerAuth })
18+
assertTrue(client.networkInterceptors.any { it is HttpBearerAuth })
1919
}
2020

2121
@Test
@@ -74,6 +74,13 @@ class OkHttpClientTest {
7474
assertNull(client.cache)
7575
}
7676

77+
@Test
78+
fun `Increases read timeout`() {
79+
val client = buildClient()
80+
val defaultTimeout = OkHttpClient.Builder().build().readTimeoutMillis
81+
assertTrue(client.readTimeoutMillis > defaultTimeout)
82+
}
83+
7784
private fun buildClient(
7885
vararg envVars: Pair<String, String?>,
7986
clientBuilder: OkHttpClient.Builder? = null,

src/test/kotlin/com/gabrielfeo/gradle/enterprise/api/OptionsTest.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ class OptionsTest {
9595
)
9696
}
9797

98+
@Test
99+
fun `Given timeout set in env, readTimeoutMillis returns env value`() {
100+
val options = Options(
101+
FakeEnv("GRADLE_ENTERPRISE_API_READ_TIMEOUT_MILLIS" to "100000"),
102+
FakeKeychain(),
103+
)
104+
assertEquals(100_000L, options.httpClient.readTimeoutMillis)
105+
}
106+
98107
private fun Regex.assertMatches(vararg values: String) {
99108
values.forEach {
100109
assertTrue(matches(it), "/$pattern/ doesn't match '$it'")

0 commit comments

Comments
 (0)