Skip to content

Commit ad930f4

Browse files
authored
Deprecate 'Result' enum and replace with 'MetricResult' due to conflict with Kotlin stdlib (#808)
## Problem The `Result` name presents an ergonomic issue due to the inherent conflict with the `kotlin.Result` type ## Solution Replace with `MetricResult` and automatically prepend `Metric` on any enum output that conflicts with the `kotlin` package namespace ## License By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 3e73ebf commit ad930f4

File tree

8 files changed

+109
-41
lines changed

8 files changed

+109
-41
lines changed

telemetry/jetbrains/build.gradle.kts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ dependencies {
4545

4646
tasks {
4747
withType<KotlinCompile> {
48-
compilerOptions.jvmTarget = JvmTarget.JVM_17
48+
compilerOptions {
49+
jvmTarget = JvmTarget.JVM_17
50+
freeCompilerArgs.add("-Xcontext-receivers")
51+
}
4952
}
5053

5154
val validatePackagedSchema by registering {

telemetry/jetbrains/src/main/kotlin/software/aws/toolkits/telemetry/generator/TelemetryGenerator.kt

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ import com.squareup.kotlinpoet.DOUBLE
1010
import com.squareup.kotlinpoet.FileSpec
1111
import com.squareup.kotlinpoet.FunSpec
1212
import com.squareup.kotlinpoet.KModifier
13-
import com.squareup.kotlinpoet.MemberName
1413
import com.squareup.kotlinpoet.ParameterSpec
1514
import com.squareup.kotlinpoet.PropertySpec
1615
import com.squareup.kotlinpoet.STRING
16+
import com.squareup.kotlinpoet.TypeAliasSpec
1717
import com.squareup.kotlinpoet.TypeSpec
18+
import com.squareup.kotlinpoet.TypeVariableName
1819
import java.io.File
1920
import java.time.Instant
2021

@@ -28,6 +29,7 @@ val CONNECTION_SETTINGS = ClassName("software.aws.toolkits.core", "ConnectionSet
2829

2930
const val RESULT = "result"
3031
const val SUCCESS = "success"
32+
const val SANITIZED_RESULT_TYPE_FORMAT = "MetricResult"
3133

3234
fun String.filterInvalidCharacters() = this.replace(".", "")
3335

@@ -118,8 +120,18 @@ private fun FileSpec.Builder.generateTelemetryEnumTypes(items: List<TelemetryMet
118120
}
119121

120122
private fun FileSpec.Builder.generateTelemetryEnumType(item: TelemetryMetricType): FileSpec.Builder {
123+
val clazz = item.name.toTypeFormat()
124+
val existsInKotlinStdlib =
125+
try {
126+
Class.forName("kotlin.$clazz")
127+
true
128+
} catch (_: ClassNotFoundException) {
129+
false
130+
}
131+
132+
val typeName = if (existsInKotlinStdlib) "Metric$clazz" else clazz
121133
val enum =
122-
TypeSpec.enumBuilder(item.name.toTypeFormat())
134+
TypeSpec.enumBuilder(typeName)
123135
.primaryConstructor(
124136
FunSpec.constructorBuilder()
125137
.addParameter("value", String::class)
@@ -152,7 +164,7 @@ private fun FileSpec.Builder.generateTelemetryEnumType(item: TelemetryMetricType
152164
TypeSpec.companionObjectBuilder()
153165
.addFunction(
154166
FunSpec.builder("from")
155-
.returns(ClassName("", item.name.toTypeFormat()))
167+
.returns(ClassName("", typeName))
156168
.addParameter("type", String::class)
157169
.addStatement("return values().firstOrNull·{·it.value·==·type·} ?:·$unknownType")
158170
.build(),
@@ -166,6 +178,33 @@ private fun FileSpec.Builder.generateTelemetryEnumType(item: TelemetryMetricType
166178
return this
167179
}
168180

181+
private fun FileSpec.Builder.generateDeprecatedOverloads(name: String): FileSpec.Builder {
182+
val oldName = name.toTypeFormat()
183+
val replacementType = TypeVariableName("Metric$oldName")
184+
val replacementFqn = TypeVariableName("$PACKAGE_NAME.$replacementType")
185+
val alias =
186+
TypeAliasSpec.builder(oldName, replacementType)
187+
.addAnnotation(
188+
AnnotationSpec.builder(Deprecated::class)
189+
.addMember("message = %S", "Name conflicts with the Kotlin standard library")
190+
.addMember("replaceWith = ReplaceWith(%S, %S)", replacementType, replacementFqn)
191+
.build(),
192+
)
193+
.build()
194+
195+
addTypeAlias(alias)
196+
197+
return this
198+
}
199+
200+
private fun FileSpec.Builder.generateTelemetryObjects(schema: List<MetricSchema>): FileSpec.Builder {
201+
schema.groupBy { it.namespace() }
202+
.toSortedMap()
203+
.forEach { (namespace, metrics) -> generateNamespaces(namespace, metrics) }
204+
205+
return this
206+
}
207+
169208
private fun FileSpec.Builder.generateNamespaces(
170209
namespace: String,
171210
metrics: List<MetricSchema>,
@@ -181,6 +220,7 @@ private fun FileSpec.Builder.generateNamespaces(
181220
return this
182221
}
183222

223+
context(FileSpec.Builder)
184224
private fun TypeSpec.Builder.generateRecordFunctions(metric: MetricSchema) {
185225
// metric.name.split("_")[1] is guaranteed to work at this point because the schema requires the metric name to have at least 1 underscore
186226
val functionName = metric.name.split("_")[1]
@@ -193,6 +233,7 @@ private fun TypeSpec.Builder.generateRecordFunctions(metric: MetricSchema) {
193233
if (metric.metadata.none { it.type.name == RESULT }) {
194234
return
195235
}
236+
generateDeprecatedOverloads(RESULT)
196237

197238
addFunction(buildProjectOverloadFunction(functionName, metric))
198239
addFunction(buildConnectionSettingsOverloadFunction(functionName, metric))
@@ -257,7 +298,7 @@ private fun MetadataSchema.metadataToParameter(): ParameterSpec {
257298
// Allowed values indicates an enum
258299
val typeName =
259300
if (type.allowedValues != null) {
260-
ClassName(PACKAGE_NAME, type.name.toTypeFormat())
301+
ClassName(PACKAGE_NAME, type.name.toTypeFormat().replace("Result", SANITIZED_RESULT_TYPE_FORMAT))
261302
} else {
262303
type.type.kotlinType()
263304
}.copy(nullable = required == false)
@@ -273,11 +314,11 @@ private fun FunSpec.Builder.generateFunctionBody(
273314
metadataParameter: ParameterSpec,
274315
metric: MetricSchema,
275316
): FunSpec.Builder {
276-
val metricUnit = MemberName("software.amazon.awssdk.services.toolkittelemetry.model", "Unit")
317+
val metricUnit = ClassName("software.amazon.awssdk.services.toolkittelemetry.model", "Unit")
277318
beginControlFlow("%T.getInstance().record(${metadataParameter.name})", TELEMETRY_SERVICE)
278319
beginControlFlow("datum(%S)", metric.name)
279320
addStatement("createTime(createTime)")
280-
addStatement("unit(%M.${(metric.unit ?: MetricUnit.NONE).name})", metricUnit)
321+
addStatement("unit(%T.${(metric.unit ?: MetricUnit.NONE).name})", metricUnit)
281322
addStatement("value(value)")
282323
addStatement("passive(passive)")
283324
metric.metadata.forEach {
@@ -351,7 +392,7 @@ private fun FunSpec.Builder.generateResultOverloadFunctionBody(
351392
if (it.name != SUCCESS) {
352393
it.name
353394
} else {
354-
"if($SUCCESS) Result.Succeeded else Result.Failed"
395+
"if($SUCCESS) $SANITIZED_RESULT_TYPE_FORMAT.Succeeded else $SANITIZED_RESULT_TYPE_FORMAT.Failed"
355396
}
356397
},
357398
)

telemetry/jetbrains/src/test/resources/generateOverrides/output/software/aws/toolkits/telemetry/MetadataTelemetry.kt

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,27 @@ package software.aws.toolkits.telemetry
88
import com.intellij.openapi.project.Project
99
import java.time.Instant
1010
import kotlin.Boolean
11+
import kotlin.Deprecated
1112
import kotlin.Double
1213
import kotlin.Suppress
1314
import software.amazon.awssdk.services.toolkittelemetry.model.Unit
1415
import software.aws.toolkits.core.ConnectionSettings
1516
import software.aws.toolkits.jetbrains.services.telemetry.MetricEventMetadata
1617
import software.aws.toolkits.jetbrains.services.telemetry.TelemetryService
1718

19+
@Deprecated(
20+
message = "Name conflicts with the Kotlin standard library",
21+
replaceWith = ReplaceWith("MetricResult", "software.aws.toolkits.telemetry.MetricResult"),
22+
)
23+
public typealias Result = MetricResult
24+
1825
public object MetadataTelemetry {
1926
/**
2027
* It does not actually have a result, yep
2128
*/
2229
public fun hasResult(
2330
project: Project?,
24-
result: Result? = null,
31+
result: MetricResult? = null,
2532
passive: Boolean = false,
2633
`value`: Double = 1.0,
2734
createTime: Instant = Instant.now(),
@@ -44,7 +51,7 @@ public object MetadataTelemetry {
4451
*/
4552
public fun hasResult(
4653
connectionSettings: ConnectionSettings? = null,
47-
result: Result? = null,
54+
result: MetricResult? = null,
4855
passive: Boolean = false,
4956
`value`: Double = 1.0,
5057
createTime: Instant = Instant.now(),
@@ -67,7 +74,7 @@ public object MetadataTelemetry {
6774
*/
6875
public fun hasResult(
6976
metadata: MetricEventMetadata,
70-
result: Result? = null,
77+
result: MetricResult? = null,
7178
passive: Boolean = false,
7279
`value`: Double = 1.0,
7380
createTime: Instant = Instant.now(),
@@ -95,8 +102,8 @@ public object MetadataTelemetry {
95102
`value`: Double = 1.0,
96103
createTime: Instant = Instant.now(),
97104
) {
98-
hasResult(project, if(success) Result.Succeeded else Result.Failed, passive, value,
99-
createTime)
105+
hasResult(project, if(success) MetricResult.Succeeded else MetricResult.Failed, passive,
106+
value, createTime)
100107
}
101108

102109
/**
@@ -109,8 +116,8 @@ public object MetadataTelemetry {
109116
`value`: Double = 1.0,
110117
createTime: Instant = Instant.now(),
111118
) {
112-
hasResult(connectionSettings, if(success) Result.Succeeded else Result.Failed, passive,
113-
value, createTime)
119+
hasResult(connectionSettings, if(success) MetricResult.Succeeded else MetricResult.Failed,
120+
passive, value, createTime)
114121
}
115122

116123
/**
@@ -123,7 +130,7 @@ public object MetadataTelemetry {
123130
`value`: Double = 1.0,
124131
createTime: Instant = Instant.now(),
125132
) {
126-
hasResult(metadata, if(success) Result.Succeeded else Result.Failed, passive, value,
127-
createTime)
133+
hasResult(metadata, if(success) MetricResult.Succeeded else MetricResult.Failed, passive,
134+
value, createTime)
128135
}
129136
}

telemetry/jetbrains/src/test/resources/generateOverrides/output/software/aws/toolkits/telemetry/TelemetryEnums.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import kotlin.Suppress
1111
/**
1212
* The result of the operation
1313
*/
14-
public enum class Result(
14+
public enum class MetricResult(
1515
private val `value`: String,
1616
) {
1717
Succeeded("Succeeded"),
@@ -21,6 +21,7 @@ public enum class Result(
2121
override fun toString(): String = value
2222

2323
public companion object {
24-
public fun from(type: String): Result = values().firstOrNull { it.value == type } ?: Unknown
24+
public fun from(type: String): MetricResult = values().firstOrNull { it.value == type }
25+
?: Unknown
2526
}
2627
}

telemetry/jetbrains/src/test/resources/generateWithGlobalMetadata/output/software/aws/toolkits/telemetry/TelemetryEnums.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import kotlin.Suppress
1111
/**
1212
* The result of the operation
1313
*/
14-
public enum class Result(
14+
public enum class MetricResult(
1515
private val `value`: String,
1616
) {
1717
Succeeded("Succeeded"),
@@ -23,6 +23,7 @@ public enum class Result(
2323
override fun toString(): String = value
2424

2525
public companion object {
26-
public fun from(type: String): Result = values().firstOrNull { it.value == type } ?: Unknown
26+
public fun from(type: String): MetricResult = values().firstOrNull { it.value == type }
27+
?: Unknown
2728
}
2829
}

telemetry/jetbrains/src/test/resources/generateWithGlobalMetadata/output/software/aws/toolkits/telemetry/TestTelemetry.kt

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package software.aws.toolkits.telemetry
88
import com.intellij.openapi.project.Project
99
import java.time.Instant
1010
import kotlin.Boolean
11+
import kotlin.Deprecated
1112
import kotlin.Double
1213
import kotlin.String
1314
import kotlin.Suppress
@@ -16,6 +17,12 @@ import software.aws.toolkits.core.ConnectionSettings
1617
import software.aws.toolkits.jetbrains.services.telemetry.MetricEventMetadata
1718
import software.aws.toolkits.jetbrains.services.telemetry.TelemetryService
1819

20+
@Deprecated(
21+
message = "Name conflicts with the Kotlin standard library",
22+
replaceWith = ReplaceWith("MetricResult", "software.aws.toolkits.telemetry.MetricResult"),
23+
)
24+
public typealias Result = MetricResult
25+
1926
public object TestTelemetry {
2027
/**
2128
* Testing metric with global metadata fields
@@ -28,7 +35,7 @@ public object TestTelemetry {
2835
reasonDesc: String? = null,
2936
requestId: String? = null,
3037
requestServiceType: String? = null,
31-
result: Result? = null,
38+
result: MetricResult? = null,
3239
traceId: String? = null,
3340
metricId: String? = null,
3441
parentId: String? = null,
@@ -87,7 +94,7 @@ public object TestTelemetry {
8794
reasonDesc: String? = null,
8895
requestId: String? = null,
8996
requestServiceType: String? = null,
90-
result: Result? = null,
97+
result: MetricResult? = null,
9198
traceId: String? = null,
9299
metricId: String? = null,
93100
parentId: String? = null,
@@ -146,7 +153,7 @@ public object TestTelemetry {
146153
reasonDesc: String? = null,
147154
requestId: String? = null,
148155
requestServiceType: String? = null,
149-
result: Result? = null,
156+
result: MetricResult? = null,
150157
traceId: String? = null,
151158
metricId: String? = null,
152159
parentId: String? = null,
@@ -214,8 +221,8 @@ public object TestTelemetry {
214221
createTime: Instant = Instant.now(),
215222
) {
216223
metric(project, duration, httpStatusCode, reason, reasonDesc, requestId, requestServiceType,
217-
if(success) Result.Succeeded else Result.Failed, traceId, metricId, parentId,
218-
passive, value, createTime)
224+
if(success) MetricResult.Succeeded else MetricResult.Failed, traceId, metricId,
225+
parentId, passive, value, createTime)
219226
}
220227

221228
/**
@@ -238,8 +245,8 @@ public object TestTelemetry {
238245
createTime: Instant = Instant.now(),
239246
) {
240247
metric(connectionSettings, duration, httpStatusCode, reason, reasonDesc, requestId,
241-
requestServiceType, if(success) Result.Succeeded else Result.Failed, traceId,
242-
metricId, parentId, passive, value, createTime)
248+
requestServiceType, if(success) MetricResult.Succeeded else MetricResult.Failed,
249+
traceId, metricId, parentId, passive, value, createTime)
243250
}
244251

245252
/**
@@ -262,7 +269,7 @@ public object TestTelemetry {
262269
createTime: Instant = Instant.now(),
263270
) {
264271
metric(metadata, duration, httpStatusCode, reason, reasonDesc, requestId,
265-
requestServiceType, if(success) Result.Succeeded else Result.Failed, traceId,
266-
metricId, parentId, passive, value, createTime)
272+
requestServiceType, if(success) MetricResult.Succeeded else MetricResult.Failed,
273+
traceId, metricId, parentId, passive, value, createTime)
267274
}
268275
}

0 commit comments

Comments
 (0)