Skip to content

Commit 5cd61bb

Browse files
authored
Update Config Inversion Linter to Handle V2 supported-configurations.json Format (#10061)
1 parent 2d28a85 commit 5cd61bb

File tree

1 file changed

+54
-31
lines changed

1 file changed

+54
-31
lines changed

buildSrc/src/main/kotlin/datadog/gradle/plugin/config/ConfigInversionLinter.kt

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,40 @@ class ConfigInversionLinter : Plugin<Project> {
2626
}
2727
}
2828

29+
// Data class for fields from generated class
30+
private data class LoadedConfigFields(
31+
val supported: Set<String>,
32+
val aliasMapping: Map<String, String> = emptyMap()
33+
)
34+
35+
// Cache for fields from generated class
36+
private var cachedConfigFields: LoadedConfigFields? = null
37+
38+
// Helper function to load fields from the generated class
39+
private fun loadConfigFields(
40+
mainSourceSetOutput: org.gradle.api.file.FileCollection,
41+
generatedClassName: String
42+
): LoadedConfigFields {
43+
return cachedConfigFields ?: run {
44+
val urls = mainSourceSetOutput.files.map { it.toURI().toURL() }.toTypedArray()
45+
URLClassLoader(urls, LoadedConfigFields::class.java.classLoader).use { cl ->
46+
val clazz = Class.forName(generatedClassName, true, cl)
47+
48+
val supportedField = clazz.getField("SUPPORTED").get(null)
49+
@Suppress("UNCHECKED_CAST")
50+
val supportedSet = when (supportedField) {
51+
is Set<*> -> supportedField as Set<String>
52+
is Map<*, *> -> supportedField.keys as Set<String>
53+
else -> throw IllegalStateException("SUPPORTED field must be either Set<String> or Map<String, Any>, but was ${supportedField?.javaClass}")
54+
}
55+
56+
@Suppress("UNCHECKED_CAST")
57+
val aliasMappingMap = clazz.getField("ALIAS_MAPPING").get(null) as Map<String, String>
58+
LoadedConfigFields(supportedSet, aliasMappingMap)
59+
}.also { cachedConfigFields = it }
60+
}
61+
}
62+
2963
/** Registers `logEnvVarUsages` (scan for DD_/OTEL_ tokens and fail if unsupported). */
3064
private fun registerLogEnvVarUsages(target: Project, extension: SupportedTracerConfigurations) {
3165
val ownerPath = extension.configOwnerPath
@@ -52,16 +86,11 @@ private fun registerLogEnvVarUsages(target: Project, extension: SupportedTracerC
5286
inputs.files(javaFiles)
5387
outputs.upToDateWhen { true }
5488
doLast {
55-
// 1) Build classloader from the owner project’s runtime classpath
56-
val urls = mainSourceSetOutput.get().get().files.map { it.toURI().toURL() }.toTypedArray()
57-
val supported: Set<String> = URLClassLoader(urls, javaClass.classLoader).use { cl ->
58-
// 2) Load the generated class + read static field
59-
val clazz = Class.forName(generatedFile.get(), true, cl)
60-
@Suppress("UNCHECKED_CAST")
61-
clazz.getField("SUPPORTED").get(null) as Set<String>
62-
}
89+
// 1) Load configuration fields from the generated class
90+
val configFields = loadConfigFields(mainSourceSetOutput.get().get(), generatedFile.get())
91+
val supported = configFields.supported
6392

64-
// 3) Scan our sources and compare
93+
// 2) Scan our sources and compare
6594
val repoRoot = target.projectDir.toPath()
6695
val tokenRegex = Regex("\"(?:DD_|OTEL_)[A-Za-z0-9_]+\"")
6796

@@ -79,7 +108,7 @@ private fun registerLogEnvVarUsages(target: Project, extension: SupportedTracerC
79108
}
80109
tokenRegex.findAll(raw).forEach { m ->
81110
val token = m.value.trim('"')
82-
if (token !in supported) add("$rel:${i + 1} -> Unsupported token'$token'")
111+
if (token !in supported) add("$rel:${i + 1} -> Unsupported token '$token'")
83112
}
84113
}
85114
}
@@ -167,15 +196,9 @@ private fun registerCheckConfigStringsTask(project: Project, extension: Supporte
167196
throw GradleException("Config directory not found: ${configDir.absolutePath}")
168197
}
169198

170-
val urls = mainSourceSetOutput.get().get().files.map { it.toURI().toURL() }.toTypedArray()
171-
val (supported, aliasMapping) = URLClassLoader(urls, javaClass.classLoader).use { cl ->
172-
val clazz = Class.forName(generatedFile.get(), true, cl)
173-
@Suppress("UNCHECKED_CAST")
174-
val supportedSet = clazz.getField("SUPPORTED").get(null) as Set<String>
175-
@Suppress("UNCHECKED_CAST")
176-
val aliasMappingMap = clazz.getField("ALIAS_MAPPING").get(null) as Map<String, String>
177-
Pair(supportedSet, aliasMappingMap)
178-
}
199+
val configFields = loadConfigFields(mainSourceSetOutput.get().get(), generatedFile.get())
200+
val supported = configFields.supported
201+
val aliasMapping = configFields.aliasMapping
179202

180203
var parserConfig = ParserConfiguration()
181204
parserConfig.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8)
@@ -192,23 +215,23 @@ private fun registerCheckConfigStringsTask(project: Project, extension: Supporte
192215
.map { it as? FieldDeclaration }
193216
.ifPresent { field ->
194217
if (field.hasModifiers(Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC, Modifier.Keyword.FINAL) &&
195-
varDecl.typeAsString == "String") {
218+
varDecl.typeAsString == "String") {
196219

197-
val fieldName = varDecl.nameAsString
198-
if (fieldName.endsWith("_DEFAULT")) return@ifPresent
199-
val init = varDecl.initializer.orElse(null) ?: return@ifPresent
220+
val fieldName = varDecl.nameAsString
221+
if (fieldName.endsWith("_DEFAULT")) return@ifPresent
222+
val init = varDecl.initializer.orElse(null) ?: return@ifPresent
200223

201-
if (init !is StringLiteralExpr) return@ifPresent
202-
val rawValue = init.value
224+
if (init !is StringLiteralExpr) return@ifPresent
225+
val rawValue = init.value
203226

204-
val normalized = normalize(rawValue)
205-
if (normalized !in supported && normalized !in aliasMapping) {
206-
val line = varDecl.range.map { it.begin.line }.orElse(1)
207-
add("$fileName:$line -> Config '$rawValue' normalizes to '$normalized' " +
208-
"which is missing from '${extension.jsonFile.get()}'")
227+
val normalized = normalize(rawValue)
228+
if (normalized !in supported && normalized !in aliasMapping) {
229+
val line = varDecl.range.map { it.begin.line }.orElse(1)
230+
add("$fileName:$line -> Config '$rawValue' normalizes to '$normalized' " +
231+
"which is missing from '${extension.jsonFile.get()}'")
232+
}
209233
}
210234
}
211-
}
212235
}
213236
}
214237
}

0 commit comments

Comments
 (0)