11package datadog.gradle.plugin.config
22
3- import com.github.javaparser.ParserConfiguration
4- import com.github.javaparser.StaticJavaParser
5- import com.github.javaparser.ast.CompilationUnit
63import com.github.javaparser.ast.Modifier
7- import com.github.javaparser.ast.body.FieldDeclaration
8- import com.github.javaparser.ast.body.VariableDeclarator
9- import com.github.javaparser.ast.expr.StringLiteralExpr
104import com.github.javaparser.ast.nodeTypes.NodeWithModifiers
115import org.gradle.api.GradleException
126import org.gradle.api.Plugin
137import org.gradle.api.Project
8+ import org.gradle.api.Task
9+ import org.gradle.api.tasks.TaskProvider
1410import org.gradle.api.tasks.SourceSet
1511import org.gradle.api.tasks.SourceSetContainer
1612import org.gradle.kotlin.dsl.getByType
@@ -20,23 +16,29 @@ import java.nio.file.Path
2016class ConfigInversionLinter : Plugin <Project > {
2117 override fun apply (target : Project ) {
2218 val extension = target.extensions.create(" supportedTracerConfigurations" , SupportedTracerConfigurations ::class .java)
23- registerLogEnvVarUsages(target, extension)
24- registerCheckEnvironmentVariablesUsage(target)
25- registerCheckConfigStringsTask(target, extension)
19+ val logEnvVarUsages = registerLogEnvVarUsages(target, extension)
20+ val checkEnvVarUsage = registerCheckEnvironmentVariablesUsage(target)
21+ val checkConfigStrings = registerCheckConfigStringsTask(target, extension)
22+
23+ target.tasks.register(" checkConfigurations" ) {
24+ group = " verification"
25+ description = " Runs all config inversion validation checks"
26+ dependsOn(logEnvVarUsages, checkEnvVarUsage, checkConfigStrings)
27+ }
2628 }
2729}
2830
2931// Data class for fields from generated class
30- private data class LoadedConfigFields (
32+ internal data class LoadedConfigFields (
3133 val supported : Set <String >,
3234 val aliasMapping : Map <String , String > = emptyMap()
3335)
3436
3537// Cache for fields from generated class
36- private var cachedConfigFields: LoadedConfigFields ? = null
38+ internal var cachedConfigFields: LoadedConfigFields ? = null
3739
3840// Helper function to load fields from the generated class
39- private fun loadConfigFields (
41+ internal fun loadConfigFields (
4042 mainSourceSetOutput : org.gradle.api.file.FileCollection ,
4143 generatedClassName : String
4244): LoadedConfigFields {
@@ -61,12 +63,12 @@ private fun loadConfigFields(
6163}
6264
6365/* * Registers `logEnvVarUsages` (scan for DD_/OTEL_ tokens and fail if unsupported). */
64- private fun registerLogEnvVarUsages (target : Project , extension : SupportedTracerConfigurations ) {
66+ private fun registerLogEnvVarUsages (target : Project , extension : SupportedTracerConfigurations ): TaskProvider < Task > {
6567 val ownerPath = extension.configOwnerPath
6668 val generatedFile = extension.className
6769
6870 // token check that uses the generated class instead of JSON
69- target.tasks.register(" logEnvVarUsages" ) {
71+ return target.tasks.register(" logEnvVarUsages" ) {
7072 group = " verification"
7173 description = " Scan Java files for DD_/OTEL_ tokens and fail if unsupported (using generated constants)"
7274
@@ -127,8 +129,8 @@ private fun registerLogEnvVarUsages(target: Project, extension: SupportedTracerC
127129}
128130
129131/* * Registers `checkEnvironmentVariablesUsage` (forbid EnvironmentVariables.get(...)). */
130- private fun registerCheckEnvironmentVariablesUsage (project : Project ) {
131- project.tasks.register(" checkEnvironmentVariablesUsage" ) {
132+ private fun registerCheckEnvironmentVariablesUsage (project : Project ): TaskProvider < Task > {
133+ return project.tasks.register(" checkEnvironmentVariablesUsage" ) {
132134 group = " verification"
133135 description = " Scans src/main/java for direct usages of EnvironmentVariables.get(...)"
134136
@@ -166,19 +168,19 @@ private fun registerCheckEnvironmentVariablesUsage(project: Project) {
166168}
167169
168170// Helper functions for checking Config Strings
169- private fun normalize (configValue : String ) =
171+ internal fun normalize (configValue : String ) =
170172 " DD_" + configValue.uppercase().replace(" -" , " _" ).replace(" ." , " _" )
171173
172174// Checking "public" "static" "final"
173- private fun NodeWithModifiers <* >.hasModifiers (vararg mods : Modifier .Keyword ) =
175+ internal fun NodeWithModifiers <* >.hasModifiers (vararg mods : Modifier .Keyword ) =
174176 mods.all { hasModifier(it) }
175177
176178/* * Registers `checkConfigStrings` to validate config definitions against documented supported configurations. */
177- private fun registerCheckConfigStringsTask (project : Project , extension : SupportedTracerConfigurations ) {
179+ private fun registerCheckConfigStringsTask (project : Project , extension : SupportedTracerConfigurations ): TaskProvider < Task > {
178180 val ownerPath = extension.configOwnerPath
179181 val generatedFile = extension.className
180182
181- project.tasks.register(" checkConfigStrings" ) {
183+ return project.tasks.register(" checkConfigStrings" ) {
182184 group = " verification"
183185 description = " Validates that all config definitions in `dd-trace-api/src/main/java/datadog/trace/api/config` exist in `metadata/supported-configurations.json`"
184186
@@ -190,61 +192,8 @@ private fun registerCheckConfigStringsTask(project: Project, extension: Supporte
190192 }
191193 inputs.files(mainSourceSetOutput)
192194
193- doLast {
194- val repoRoot: Path = project.rootProject.projectDir.toPath()
195- val configDir = repoRoot.resolve(" dd-trace-api/src/main/java/datadog/trace/api/config" ).toFile()
196-
197- if (! configDir.exists()) {
198- throw GradleException (" Config directory not found: ${configDir.absolutePath} " )
199- }
200-
201- val configFields = loadConfigFields(mainSourceSetOutput.get().get(), generatedFile.get())
202- val supported = configFields.supported
203- val aliasMapping = configFields.aliasMapping
204-
205- var parserConfig = ParserConfiguration ()
206- parserConfig.setLanguageLevel(ParserConfiguration .LanguageLevel .JAVA_8 )
207-
208- StaticJavaParser .setConfiguration(parserConfig)
209-
210- val violations = buildList {
211- configDir.listFiles()?.forEach { file ->
212- val fileName = file.name
213- val cu: CompilationUnit = StaticJavaParser .parse(file)
214-
215- cu.findAll(VariableDeclarator ::class .java).forEach { varDecl ->
216- varDecl.parentNode
217- .map { it as ? FieldDeclaration }
218- .ifPresent { field ->
219- if (field.hasModifiers(Modifier .Keyword .PUBLIC , Modifier .Keyword .STATIC , Modifier .Keyword .FINAL ) &&
220- varDecl.typeAsString == " String" ) {
221-
222- val fieldName = varDecl.nameAsString
223- if (fieldName.endsWith(" _DEFAULT" )) return @ifPresent
224- val init = varDecl.initializer.orElse(null ) ? : return @ifPresent
225-
226- if (init !is StringLiteralExpr ) return @ifPresent
227- val rawValue = init .value
228-
229- val normalized = normalize(rawValue)
230- if (normalized !in supported && normalized !in aliasMapping) {
231- val line = varDecl.range.map { it.begin.line }.orElse(1 )
232- add(" $fileName :$line -> Config '$rawValue ' normalizes to '$normalized ' " +
233- " which is missing from '${extension.jsonFile.get()} '" )
234- }
235- }
236- }
237- }
238- }
239- }
240-
241- if (violations.isNotEmpty()) {
242- logger.error(" \n Found config definitions not in '${extension.jsonFile.get()} ':" )
243- violations.forEach { logger.lifecycle(it) }
244- throw GradleException (" Undocumented Environment Variables found. Please add the above Environment Variables to '${extension.jsonFile.get()} '." )
245- } else {
246- logger.info(" All config strings are present in '${extension.jsonFile.get()} '." )
247- }
248- }
195+ doLast(" regular-config-check" , RegularConfigCheckAction (mainSourceSetOutput, generatedFile, extension))
196+ doLast(" profiling-config-check" , ProfilingConfigCheckAction (mainSourceSetOutput, generatedFile, extension))
249197 }
250198}
199+
0 commit comments