From 84345fe7d3bcb4ad7a80504ea5c5025e7c891fd1 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Tue, 16 Dec 2025 14:59:45 +0100 Subject: [PATCH 01/14] Create a gradle plugin to check instrumenation names --- buildSrc/build.gradle.kts | 5 + .../naming/InstrumentationNamingExtension.kt | 34 ++++ .../naming/InstrumentationNamingPlugin.kt | 184 ++++++++++++++++++ .../datadog/gradle/plugin/naming/README.md | 77 ++++++++ dd-java-agent/instrumentation/build.gradle | 1 + 5 files changed, 301 insertions(+) create mode 100644 buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt create mode 100644 buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt create mode 100644 buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 7e2a8f1e61a..170bf43cca6 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -47,6 +47,11 @@ gradlePlugin { id = "dd-trace-java.config-inversion-linter" implementationClass = "datadog.gradle.plugin.config.ConfigInversionLinter" } + + create("instrumentation-naming") { + id = "dd-trace-java.instrumentation-naming" + implementationClass = "datadog.gradle.plugin.naming.InstrumentationNamingPlugin" + } } } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt new file mode 100644 index 00000000000..b79a289dbe7 --- /dev/null +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt @@ -0,0 +1,34 @@ +package datadog.gradle.plugin.naming + +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property + +/** + * Extension for configuring instrumentation naming convention checks. + * + * Example usage: + * ``` + * instrumentationNaming { + * instrumentationsDir.set(file("dd-java-agent/instrumentation")) + * exclusions.set(listOf("http-url-connection", "sslsocket")) + * } + * ``` + */ +abstract class InstrumentationNamingExtension { + /** + * The directory containing instrumentation modules. + * Defaults to "dd-java-agent/instrumentation". + */ + abstract val instrumentationsDir: Property + + /** + * List of module names to exclude from naming convention checks. + * These modules will not be validated against the naming rules. + */ + abstract val exclusions: ListProperty + + init { + instrumentationsDir.convention("dd-java-agent/instrumentation") + exclusions.convention(emptyList()) + } +} diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt new file mode 100644 index 00000000000..11b8c34a971 --- /dev/null +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -0,0 +1,184 @@ +package datadog.gradle.plugin.naming + +import org.gradle.api.GradleException +import org.gradle.api.Plugin +import org.gradle.api.Project +import java.io.File + +/** + * Plugin that validates naming conventions for instrumentation modules. + * + * Rules: + * 1. Module name must end with a version (e.g., "2.0", "3.1") OR end with "-common" + * 2. Module name must include the parent directory name + * (e.g., "couchbase-2.0" must contain "couchbase" which is the parent directory name) + * + * Apply this plugin: + * ``` + * plugins { + * id("dd-trace-java.instrumentation-naming") + * } + * ``` + */ +class InstrumentationNamingPlugin : Plugin { + override fun apply(target: Project) { + val extension = target.extensions.create( + "instrumentationNaming", + InstrumentationNamingExtension::class.java + ) + + target.tasks.register("checkInstrumentationNaming") { + group = "verification" + description = "Validates naming conventions for instrumentation modules" + + doLast { + val instrumentationsDir = target.rootProject.file(extension.instrumentationsDir.get()) + val exclusions = extension.exclusions.get().toSet() + + if (!instrumentationsDir.exists() || !instrumentationsDir.isDirectory) { + throw GradleException( + "Instrumentations directory not found: ${instrumentationsDir.absolutePath}" + ) + } + + val violations = validateInstrumentations(instrumentationsDir, exclusions) + + if (violations.isNotEmpty()) { + val errorMessage = buildString { + appendLine("\nInstrumentation naming convention violations found:") + appendLine() + violations.forEach { violation -> + appendLine(" • ${violation.path}") + appendLine(" ${violation.message}") + appendLine() + } + appendLine("Naming rules:") + appendLine(" 1. Module name must end with a version (e.g., '2.0', '3.1') OR end with '-common'") + appendLine(" 2. Module name must include the parent directory name") + appendLine(" Example: 'couchbase/couchbase-2.0' ✓ (contains 'couchbase')") + appendLine() + appendLine("To exclude specific modules, configure the plugin:") + appendLine(" instrumentationNaming {") + appendLine(" exclusions.set(listOf(\"module-name\"))") + appendLine(" }") + } + throw GradleException(errorMessage) + } else { + target.logger.lifecycle("✓ All instrumentation modules follow naming conventions") + } + } + } + } + + private fun validateInstrumentations( + instrumentationsDir: File, + exclusions: Set + ): List { + val violations = mutableListOf() + + // Get all subdirectories in the instrumentations directory + instrumentationsDir.listFiles { file -> file.isDirectory }?.forEach parentLoop@{ parentDir -> + val parentName = parentDir.name + + // Skip build directories and other non-instrumentation directories + if (parentName in setOf("build", "src", ".gradle")) { + return@parentLoop + } + + // Check if this directory has a build.gradle file + // If it does, it's a leaf instrumentation module + val hasBuildFile = parentDir.listFiles()?.any { + it.name == "build.gradle" || it.name == "build.gradle.kts" + } ?: false + + if (hasBuildFile) { + // This is a leaf module, validate only the version/common suffix requirement + if (parentName !in exclusions) { + validateLeafModuleName(parentName, parentDir.relativeTo(instrumentationsDir).path)?.let { + violations.add(it) + } + } + } else { + // This directory contains sub-modules, check each one + parentDir.listFiles { file -> file.isDirectory }?.forEach moduleLoop@{ moduleDir -> + val moduleName = moduleDir.name + + // Skip build and other non-module directories + if (moduleName in setOf("build", "src", ".gradle")) { + return@moduleLoop + } + + // Check if this is actually a module (has build.gradle) + val hasModuleBuildFile = moduleDir.listFiles()?.any { + it.name == "build.gradle" || it.name == "build.gradle.kts" + } ?: false + + if (hasModuleBuildFile && moduleName !in exclusions) { + validateModuleName(moduleName, parentName, moduleDir.relativeTo(instrumentationsDir).path)?.let { + violations.add(it) + } + } + } + } + } + + return violations + } + + private fun validateModuleName( + moduleName: String, + parentName: String, + relativePath: String + ): NamingViolation? { + // Rule 1: Module name must end with version pattern (X.Y, X.Y.Z, etc.) or "-common" + val versionPattern = Regex("""\d+\.\d+(\.\d+)?$""") + val endsWithCommon = moduleName.endsWith("-common") + val endsWithVersion = versionPattern.containsMatchIn(moduleName) + + if (!endsWithVersion && !endsWithCommon) { + return NamingViolation( + relativePath, + "Module name '$moduleName' must end with a version (e.g., '2.0', '3.1.0') or '-common'" + ) + } + + // Rule 2: Module name must contain parent directory name + // Extract the base name (without version or -common suffix) + if (!moduleName.contains(parentName, ignoreCase = true)) { + return NamingViolation( + relativePath, + "Module name '$moduleName' should contain parent directory name '$parentName'" + ) + } + + return null + } + + /** + * Validates naming for leaf modules (modules at the top level with no parent grouping). + * These only need to check the version/common suffix requirement. + */ + private fun validateLeafModuleName( + moduleName: String, + relativePath: String + ): NamingViolation? { + // Rule: Module name must end with version pattern (X.Y, X.Y.Z, etc.) or "-common" + val versionPattern = Regex("""\d+\.\d+(\.\d+)?$""") + val endsWithCommon = moduleName.endsWith("-common") + val endsWithVersion = versionPattern.containsMatchIn(moduleName) + + if (!endsWithVersion && !endsWithCommon) { + return NamingViolation( + relativePath, + "Module name '$moduleName' must end with a version (e.g., '2.0', '3.1.0') or '-common'" + ) + } + + return null + } + + private data class NamingViolation( + val path: String, + val message: String + ) +} diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md new file mode 100644 index 00000000000..3da0268da93 --- /dev/null +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md @@ -0,0 +1,77 @@ +# Instrumentation Naming Convention Plugin + +A Gradle plugin that validates naming conventions for instrumentation modules under `dd-java-agent/instrumentation`. + +## Naming Rules + +The plugin enforces the following rules: + +1. **Version or Common suffix**: Module names must end with either: + - A version number (e.g., `2.0`, `3.1`, `4.0.5`) + - The suffix `-common` + +2. **Parent directory inclusion**: Module names must include the parent directory name + - Example: `couchbase/couchbase-2.0` ✓ (module name contains "couchbase") + - Example: `couchbase/foo-2.0` ✗ (module name doesn't contain "couchbase") + +## Usage + +### Apply the plugin + +In your root `build.gradle` or `build.gradle.kts`: + +```kotlin +plugins { + id("dd-trace-java.instrumentation-naming") +} +``` + +### Run the validation + +```bash +./gradlew checkInstrumentationNaming +``` + +### Configuration + +You can configure the plugin with custom settings: + +```kotlin +instrumentationNaming { + // Optional: specify a different instrumentations directory + instrumentationsDir.set("path/to/instrumentations") + + // Optional: exclude specific modules from validation + exclusions.set(listOf( + "http-url-connection", + "sslsocket", + "classloading" + )) +} +``` + +## Examples + +### Valid module names: +- `couchbase/couchbase-2.0` ✓ +- `couchbase/couchbase-2.6` ✓ +- `couchbase/couchbase-3.1` ✓ +- `kafka/kafka-common` ✓ +- `apache-httpclient/apache-httpclient-4.0` ✓ + +### Invalid module names: +- `couchbase/foo-2.0` ✗ (doesn't contain parent name "couchbase") +- `kafka/kafka` ✗ (missing version or -common suffix) +- `kafka/kafka-latest` ✗ (not a valid version number) + +## Integration with CI + +Add the task to your verification pipeline: + +```kotlin +tasks.named("check") { + dependsOn("checkInstrumentationNaming") +} +``` + +This ensures naming conventions are validated on every build. diff --git a/dd-java-agent/instrumentation/build.gradle b/dd-java-agent/instrumentation/build.gradle index 454c70fb083..6f757d3faae 100644 --- a/dd-java-agent/instrumentation/build.gradle +++ b/dd-java-agent/instrumentation/build.gradle @@ -2,6 +2,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { id 'com.gradleup.shadow' + id("dd-trace-java.instrumentation-naming") } apply from: "$rootDir/gradle/java.gradle" From 89bad8e12b8bb8082322d354fa63498f99e1d506 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Tue, 16 Dec 2025 15:19:45 +0100 Subject: [PATCH 02/14] Factorise the regexp --- .../gradle/plugin/naming/InstrumentationNamingPlugin.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index 11b8c34a971..f662bb5dad6 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -21,6 +21,8 @@ import java.io.File * ``` */ class InstrumentationNamingPlugin : Plugin { + val versionPattern : Regex = Regex("""\d+\.\d+(\.\d+)?$""") + override fun apply(target: Project) { val extension = target.extensions.create( "instrumentationNaming", @@ -131,7 +133,6 @@ class InstrumentationNamingPlugin : Plugin { relativePath: String ): NamingViolation? { // Rule 1: Module name must end with version pattern (X.Y, X.Y.Z, etc.) or "-common" - val versionPattern = Regex("""\d+\.\d+(\.\d+)?$""") val endsWithCommon = moduleName.endsWith("-common") val endsWithVersion = versionPattern.containsMatchIn(moduleName) @@ -163,7 +164,6 @@ class InstrumentationNamingPlugin : Plugin { relativePath: String ): NamingViolation? { // Rule: Module name must end with version pattern (X.Y, X.Y.Z, etc.) or "-common" - val versionPattern = Regex("""\d+\.\d+(\.\d+)?$""") val endsWithCommon = moduleName.endsWith("-common") val endsWithVersion = versionPattern.containsMatchIn(moduleName) From d1c4e5e6619e41e8b82635b23ad9c210b1a55966 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Tue, 16 Dec 2025 15:38:24 +0100 Subject: [PATCH 03/14] make suffixes configurable --- .../naming/InstrumentationNamingExtension.kt | 9 +++ .../naming/InstrumentationNamingPlugin.kt | 56 +++++++++++-------- .../datadog/gradle/plugin/naming/README.md | 25 ++++++--- 3 files changed, 57 insertions(+), 33 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt index b79a289dbe7..d0ee2343fd1 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt @@ -11,6 +11,7 @@ import org.gradle.api.provider.Property * instrumentationNaming { * instrumentationsDir.set(file("dd-java-agent/instrumentation")) * exclusions.set(listOf("http-url-connection", "sslsocket")) + * suffixes.set(listOf("-common", "-stubs"")) * } * ``` */ @@ -27,8 +28,16 @@ abstract class InstrumentationNamingExtension { */ abstract val exclusions: ListProperty + /** + * List of allowed suffixes for module names (e.g., "-common", "-stubs"). + * Module names must end with either one of these suffixes or a version number. + * Defaults to ["-common", "-stubs"]. + */ + abstract val suffixes: ListProperty + init { instrumentationsDir.convention("dd-java-agent/instrumentation") exclusions.convention(emptyList()) + suffixes.convention(listOf("-common", "-stubs")) } } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index f662bb5dad6..20dbd3a2511 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -36,6 +36,7 @@ class InstrumentationNamingPlugin : Plugin { doLast { val instrumentationsDir = target.rootProject.file(extension.instrumentationsDir.get()) val exclusions = extension.exclusions.get().toSet() + val suffixes = extension.suffixes.get() if (!instrumentationsDir.exists() || !instrumentationsDir.isDirectory) { throw GradleException( @@ -43,9 +44,10 @@ class InstrumentationNamingPlugin : Plugin { ) } - val violations = validateInstrumentations(instrumentationsDir, exclusions) + val violations = validateInstrumentations(instrumentationsDir, exclusions, suffixes) if (violations.isNotEmpty()) { + val suffixesStr = suffixes.joinToString("', '", "'", "'") val errorMessage = buildString { appendLine("\nInstrumentation naming convention violations found:") appendLine() @@ -55,13 +57,14 @@ class InstrumentationNamingPlugin : Plugin { appendLine() } appendLine("Naming rules:") - appendLine(" 1. Module name must end with a version (e.g., '2.0', '3.1') OR end with '-common'") + appendLine(" 1. Module name must end with a version (e.g., '2.0', '3.1') OR one of: $suffixesStr") appendLine(" 2. Module name must include the parent directory name") appendLine(" Example: 'couchbase/couchbase-2.0' ✓ (contains 'couchbase')") appendLine() - appendLine("To exclude specific modules, configure the plugin:") + appendLine("To exclude specific modules or customize suffixes, configure the plugin:") appendLine(" instrumentationNaming {") appendLine(" exclusions.set(listOf(\"module-name\"))") + appendLine(" suffixes.set(listOf(\"-common\", \"-stubs\"))") appendLine(" }") } throw GradleException(errorMessage) @@ -74,7 +77,8 @@ class InstrumentationNamingPlugin : Plugin { private fun validateInstrumentations( instrumentationsDir: File, - exclusions: Set + exclusions: Set, + suffixes: List ): List { val violations = mutableListOf() @@ -96,7 +100,7 @@ class InstrumentationNamingPlugin : Plugin { if (hasBuildFile) { // This is a leaf module, validate only the version/common suffix requirement if (parentName !in exclusions) { - validateLeafModuleName(parentName, parentDir.relativeTo(instrumentationsDir).path)?.let { + validateLeafModuleName(parentName, parentDir.relativeTo(instrumentationsDir).path, suffixes)?.let { violations.add(it) } } @@ -116,7 +120,7 @@ class InstrumentationNamingPlugin : Plugin { } ?: false if (hasModuleBuildFile && moduleName !in exclusions) { - validateModuleName(moduleName, parentName, moduleDir.relativeTo(instrumentationsDir).path)?.let { + validateModuleName(moduleName, parentName, moduleDir.relativeTo(instrumentationsDir).path, suffixes)?.let { violations.add(it) } } @@ -130,21 +134,13 @@ class InstrumentationNamingPlugin : Plugin { private fun validateModuleName( moduleName: String, parentName: String, - relativePath: String + relativePath: String, + suffixes: List ): NamingViolation? { - // Rule 1: Module name must end with version pattern (X.Y, X.Y.Z, etc.) or "-common" - val endsWithCommon = moduleName.endsWith("-common") - val endsWithVersion = versionPattern.containsMatchIn(moduleName) - - if (!endsWithVersion && !endsWithCommon) { - return NamingViolation( - relativePath, - "Module name '$moduleName' must end with a version (e.g., '2.0', '3.1.0') or '-common'" - ) - } + // Rule 1: Module name must end with version pattern or one of the configured suffixes + validateVersionOrSuffix(moduleName, relativePath, suffixes)?.let { return it } // Rule 2: Module name must contain parent directory name - // Extract the base name (without version or -common suffix) if (!moduleName.contains(parentName, ignoreCase = true)) { return NamingViolation( relativePath, @@ -157,20 +153,32 @@ class InstrumentationNamingPlugin : Plugin { /** * Validates naming for leaf modules (modules at the top level with no parent grouping). - * These only need to check the version/common suffix requirement. + * These only need to check the version/suffix requirement. */ private fun validateLeafModuleName( moduleName: String, - relativePath: String + relativePath: String, + suffixes: List + ): NamingViolation? { + return validateVersionOrSuffix(moduleName, relativePath, suffixes) + } + + /** + * Validates that a module name ends with either a version or one of the configured suffixes. + */ + private fun validateVersionOrSuffix( + moduleName: String, + relativePath: String, + suffixes: List ): NamingViolation? { - // Rule: Module name must end with version pattern (X.Y, X.Y.Z, etc.) or "-common" - val endsWithCommon = moduleName.endsWith("-common") + val endsWithSuffix = suffixes.any { moduleName.endsWith(it) } val endsWithVersion = versionPattern.containsMatchIn(moduleName) - if (!endsWithVersion && !endsWithCommon) { + if (!endsWithVersion && !endsWithSuffix) { + val suffixesStr = suffixes.joinToString("', '", "'", "'") return NamingViolation( relativePath, - "Module name '$moduleName' must end with a version (e.g., '2.0', '3.1.0') or '-common'" + "Module name '$moduleName' must end with a version (e.g., '2.0', '3.1.0') or one of: $suffixesStr" ) } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md index 3da0268da93..502b8c0b8f1 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md @@ -6,9 +6,9 @@ A Gradle plugin that validates naming conventions for instrumentation modules un The plugin enforces the following rules: -1. **Version or Common suffix**: Module names must end with either: +1. **Version or suffix**: Module names must end with either: - A version number (e.g., `2.0`, `3.1`, `4.0.5`) - - The suffix `-common` + - One of the configured suffixes (default: `-common`, `-stubs`) 2. **Parent directory inclusion**: Module names must include the parent directory name - Example: `couchbase/couchbase-2.0` ✓ (module name contains "couchbase") @@ -47,22 +47,29 @@ instrumentationNaming { "sslsocket", "classloading" )) + + // Optional: configure allowed suffixes (default: ["-common", "-stubs"]) + suffixes.set(listOf( + "-common", + "-stubs", + "-utils" + )) } ``` ## Examples ### Valid module names: -- `couchbase/couchbase-2.0` ✓ -- `couchbase/couchbase-2.6` ✓ -- `couchbase/couchbase-3.1` ✓ -- `kafka/kafka-common` ✓ -- `apache-httpclient/apache-httpclient-4.0` ✓ +- `couchbase/couchbase-2.0` ✓ (ends with version) +- `couchbase/couchbase-2.6` ✓ (ends with version) +- `couchbase/couchbase-3.1` ✓ (ends with version) +- `kafka/kafka-common` ✓ (ends with -common suffix) +- `apache-httpclient/apache-httpclient-4.0` ✓ (ends with version) ### Invalid module names: - `couchbase/foo-2.0` ✗ (doesn't contain parent name "couchbase") -- `kafka/kafka` ✗ (missing version or -common suffix) -- `kafka/kafka-latest` ✗ (not a valid version number) +- `kafka/kafka` ✗ (missing version or allowed suffix) +- `kafka/kafka-latest` ✗ (not a valid version number or allowed suffix) ## Integration with CI From 4a86a6f35637c6c72d385fa316bdd60f2d5810f2 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Wed, 17 Dec 2025 11:33:34 +0100 Subject: [PATCH 04/14] Fix module recursion --- .../naming/InstrumentationNamingPlugin.kt | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index 20dbd3a2511..3c0e8201891 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -91,35 +91,32 @@ class InstrumentationNamingPlugin : Plugin { return@parentLoop } - // Check if this directory has a build.gradle file - // If it does, it's a leaf instrumentation module val hasBuildFile = parentDir.listFiles()?.any { it.name == "build.gradle" || it.name == "build.gradle.kts" } ?: false - if (hasBuildFile) { - // This is a leaf module, validate only the version/common suffix requirement - if (parentName !in exclusions) { + // Check for subdirectories that are modules + val subModules = parentDir.listFiles { file -> file.isDirectory } + ?.filter { subDir -> + val name = subDir.name + // Skip build and other non-module directories + name !in setOf("build", "src", ".gradle") && + // Check if it has a build file + subDir.listFiles()?.any { it.name == "build.gradle" || it.name == "build.gradle.kts" } == true + } ?: emptyList() + + if (subModules.isEmpty()) { + // No submodules, this is a leaf module + if (hasBuildFile && parentName !in exclusions) { validateLeafModuleName(parentName, parentDir.relativeTo(instrumentationsDir).path, suffixes)?.let { violations.add(it) } } } else { - // This directory contains sub-modules, check each one - parentDir.listFiles { file -> file.isDirectory }?.forEach moduleLoop@{ moduleDir -> + // Has submodules, validate each one + subModules.forEach { moduleDir -> val moduleName = moduleDir.name - - // Skip build and other non-module directories - if (moduleName in setOf("build", "src", ".gradle")) { - return@moduleLoop - } - - // Check if this is actually a module (has build.gradle) - val hasModuleBuildFile = moduleDir.listFiles()?.any { - it.name == "build.gradle" || it.name == "build.gradle.kts" - } ?: false - - if (hasModuleBuildFile && moduleName !in exclusions) { + if (moduleName !in exclusions) { validateModuleName(moduleName, parentName, moduleDir.relativeTo(instrumentationsDir).path, suffixes)?.let { violations.add(it) } From f5a750078af3b166a60adf5afa5c5ca67728a0fe Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Wed, 17 Dec 2025 12:31:19 +0100 Subject: [PATCH 05/14] Ensure instrumentation naming validation recurses into nested modules --- .../naming/InstrumentationNamingPlugin.kt | 61 ++++++++----------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index 3c0e8201891..f8c6b1563dd 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -82,49 +82,40 @@ class InstrumentationNamingPlugin : Plugin { ): List { val violations = mutableListOf() - // Get all subdirectories in the instrumentations directory - instrumentationsDir.listFiles { file -> file.isDirectory }?.forEach parentLoop@{ parentDir -> - val parentName = parentDir.name + fun hasBuildFile(dir: File): Boolean = dir.listFiles()?.any { + it.name == "build.gradle" || it.name == "build.gradle.kts" + } ?: false - // Skip build directories and other non-instrumentation directories - if (parentName in setOf("build", "src", ".gradle")) { - return@parentLoop - } + fun traverseModules(currentDir: File, parentName: String?) { + currentDir.listFiles { file -> file.isDirectory }?.forEach childLoop@{ childDir -> + val moduleName = childDir.name - val hasBuildFile = parentDir.listFiles()?.any { - it.name == "build.gradle" || it.name == "build.gradle.kts" - } ?: false - - // Check for subdirectories that are modules - val subModules = parentDir.listFiles { file -> file.isDirectory } - ?.filter { subDir -> - val name = subDir.name - // Skip build and other non-module directories - name !in setOf("build", "src", ".gradle") && - // Check if it has a build file - subDir.listFiles()?.any { it.name == "build.gradle" || it.name == "build.gradle.kts" } == true - } ?: emptyList() - - if (subModules.isEmpty()) { - // No submodules, this is a leaf module - if (hasBuildFile && parentName !in exclusions) { - validateLeafModuleName(parentName, parentDir.relativeTo(instrumentationsDir).path, suffixes)?.let { - violations.add(it) - } + // Skip build directories and other non-instrumentation directories + if (moduleName in setOf("build", "src", ".gradle")) { + return@childLoop } - } else { - // Has submodules, validate each one - subModules.forEach { moduleDir -> - val moduleName = moduleDir.name - if (moduleName !in exclusions) { - validateModuleName(moduleName, parentName, moduleDir.relativeTo(instrumentationsDir).path, suffixes)?.let { - violations.add(it) - } + + val childHasBuildFile = hasBuildFile(childDir) + val nestedModules = childDir.listFiles { file -> file.isDirectory }?.filter { hasBuildFile(it) } ?: emptyList() + + if (childHasBuildFile && moduleName !in exclusions) { + val relativePath = childDir.relativeTo(instrumentationsDir).path + if (parentName == null && nestedModules.isEmpty()) { + validateLeafModuleName(moduleName, relativePath, suffixes)?.let { violations.add(it) } + } else if (parentName != null) { + validateModuleName(moduleName, parentName, relativePath, suffixes)?.let { violations.add(it) } } } + + // Continue traversing to validate deeply nested modules + if (nestedModules.isNotEmpty() || !childHasBuildFile) { + traverseModules(childDir, moduleName) + } } } + traverseModules(instrumentationsDir, null) + return violations } From 3895823e2e1b72f4ca2d06b67b97ffa11c47cdf7 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 18 Dec 2025 08:46:49 +0100 Subject: [PATCH 06/14] Update buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt Co-authored-by: Brice Dutheil --- .../datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index f8c6b1563dd..c99e4d4103d 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -21,7 +21,7 @@ import java.io.File * ``` */ class InstrumentationNamingPlugin : Plugin { - val versionPattern : Regex = Regex("""\d+\.\d+(\.\d+)?$""") + private val versionPattern : Regex = Regex("""\d+\.\d+(\.\d+)?$""") override fun apply(target: Project) { val extension = target.extensions.create( From 18479e63a23b4a1e0366fa683e39ed47c1ac558c Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 18 Dec 2025 08:51:32 +0100 Subject: [PATCH 07/14] Update buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt Co-authored-by: Brice Dutheil --- .../gradle/plugin/naming/InstrumentationNamingPlugin.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index c99e4d4103d..451c6b18c68 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -24,10 +24,7 @@ class InstrumentationNamingPlugin : Plugin { private val versionPattern : Regex = Regex("""\d+\.\d+(\.\d+)?$""") override fun apply(target: Project) { - val extension = target.extensions.create( - "instrumentationNaming", - InstrumentationNamingExtension::class.java - ) + val extension = target.extensions.create("instrumentationNaming") target.tasks.register("checkInstrumentationNaming") { group = "verification" From 6f57bb343126c4007bffc22752e4dc14b64a8667 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 18 Dec 2025 08:51:47 +0100 Subject: [PATCH 08/14] Update buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt Co-authored-by: Alexey Kuznetsov --- .../gradle/plugin/naming/InstrumentationNamingPlugin.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index 451c6b18c68..a1db1248440 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -121,19 +121,19 @@ class InstrumentationNamingPlugin : Plugin { parentName: String, relativePath: String, suffixes: List - ): NamingViolation? { + ): List { // Rule 1: Module name must end with version pattern or one of the configured suffixes validateVersionOrSuffix(moduleName, relativePath, suffixes)?.let { return it } // Rule 2: Module name must contain parent directory name if (!moduleName.contains(parentName, ignoreCase = true)) { - return NamingViolation( + return listOf(NamingViolation( relativePath, "Module name '$moduleName' should contain parent directory name '$parentName'" - ) + )) } - return null + return emptyList() } /** From 54bae8300e5941786b3dc8378ec878b88b2b7235 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 18 Dec 2025 08:52:55 +0100 Subject: [PATCH 09/14] Update buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt Co-authored-by: Brice Dutheil --- .../datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index a1db1248440..040a0e2dfc0 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -31,7 +31,7 @@ class InstrumentationNamingPlugin : Plugin { description = "Validates naming conventions for instrumentation modules" doLast { - val instrumentationsDir = target.rootProject.file(extension.instrumentationsDir.get()) + val instrumentationsDir = target.rootProject.file(extension.instrumentationsDir) val exclusions = extension.exclusions.get().toSet() val suffixes = extension.suffixes.get() From 2c473994c1dc10e75793b66a28596f0607ab2add Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 18 Dec 2025 08:58:43 +0100 Subject: [PATCH 10/14] Fix build after suggestions --- .../gradle/plugin/naming/InstrumentationNamingPlugin.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index 040a0e2dfc0..1ff3388bbe8 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -3,6 +3,7 @@ package datadog.gradle.plugin.naming import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.kotlin.dsl.create import java.io.File /** @@ -100,7 +101,7 @@ class InstrumentationNamingPlugin : Plugin { if (parentName == null && nestedModules.isEmpty()) { validateLeafModuleName(moduleName, relativePath, suffixes)?.let { violations.add(it) } } else if (parentName != null) { - validateModuleName(moduleName, parentName, relativePath, suffixes)?.let { violations.add(it) } + violations.addAll(validateModuleName(moduleName, parentName, relativePath, suffixes)) } } @@ -123,7 +124,7 @@ class InstrumentationNamingPlugin : Plugin { suffixes: List ): List { // Rule 1: Module name must end with version pattern or one of the configured suffixes - validateVersionOrSuffix(moduleName, relativePath, suffixes)?.let { return it } + validateVersionOrSuffix(moduleName, relativePath, suffixes)?.let { return listOf(it) } // Rule 2: Module name must contain parent directory name if (!moduleName.contains(parentName, ignoreCase = true)) { From 6a6e0e9529bb7ad8fd05f0f696a3e4e470250fb7 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 18 Dec 2025 08:59:07 +0100 Subject: [PATCH 11/14] use raw strings --- .../naming/InstrumentationNamingPlugin.kt | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index 1ff3388bbe8..c999c815206 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -54,16 +54,18 @@ class InstrumentationNamingPlugin : Plugin { appendLine(" ${violation.message}") appendLine() } - appendLine("Naming rules:") - appendLine(" 1. Module name must end with a version (e.g., '2.0', '3.1') OR one of: $suffixesStr") - appendLine(" 2. Module name must include the parent directory name") - appendLine(" Example: 'couchbase/couchbase-2.0' ✓ (contains 'couchbase')") - appendLine() - appendLine("To exclude specific modules or customize suffixes, configure the plugin:") - appendLine(" instrumentationNaming {") - appendLine(" exclusions.set(listOf(\"module-name\"))") - appendLine(" suffixes.set(listOf(\"-common\", \"-stubs\"))") - appendLine(" }") + append(""" + Naming rules: + 1. Module name must end with a version (e.g., '2.0', '3.1') OR one of: $suffixesStr + 2. Module name must include the parent directory name + Example: 'couchbase/couchbase-2.0' ✓ (contains 'couchbase') + + To exclude specific modules or customize suffixes, configure the plugin: + instrumentationNaming { + exclusions.set(listOf("module-name")) + suffixes.set(listOf("-common", "-stubs")) + } + """.trimIndent()) } throw GradleException(errorMessage) } else { From 99761526c2c1e38847c8496c94d7219f63d5ed6a Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 18 Dec 2025 09:08:25 +0100 Subject: [PATCH 12/14] convert suffixes and exclusions to SetProperty --- .../naming/InstrumentationNamingExtension.kt | 18 +++++++++--------- .../naming/InstrumentationNamingPlugin.kt | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt index d0ee2343fd1..24d11e1020e 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingExtension.kt @@ -1,7 +1,7 @@ package datadog.gradle.plugin.naming -import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property +import org.gradle.api.provider.SetProperty /** * Extension for configuring instrumentation naming convention checks. @@ -10,8 +10,8 @@ import org.gradle.api.provider.Property * ``` * instrumentationNaming { * instrumentationsDir.set(file("dd-java-agent/instrumentation")) - * exclusions.set(listOf("http-url-connection", "sslsocket")) - * suffixes.set(listOf("-common", "-stubs"")) + * exclusions.set(setOf("http-url-connection", "sslsocket")) + * suffixes.set(setOf("-common", "-stubs")) * } * ``` */ @@ -23,21 +23,21 @@ abstract class InstrumentationNamingExtension { abstract val instrumentationsDir: Property /** - * List of module names to exclude from naming convention checks. + * Set of module names to exclude from naming convention checks. * These modules will not be validated against the naming rules. */ - abstract val exclusions: ListProperty + abstract val exclusions: SetProperty /** - * List of allowed suffixes for module names (e.g., "-common", "-stubs"). + * Set of allowed suffixes for module names (e.g., "-common", "-stubs"). * Module names must end with either one of these suffixes or a version number. * Defaults to ["-common", "-stubs"]. */ - abstract val suffixes: ListProperty + abstract val suffixes: SetProperty init { instrumentationsDir.convention("dd-java-agent/instrumentation") - exclusions.convention(emptyList()) - suffixes.convention(listOf("-common", "-stubs")) + exclusions.convention(emptySet()) + suffixes.convention(setOf("-common", "-stubs")) } } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index c999c815206..82af7773017 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -33,7 +33,7 @@ class InstrumentationNamingPlugin : Plugin { doLast { val instrumentationsDir = target.rootProject.file(extension.instrumentationsDir) - val exclusions = extension.exclusions.get().toSet() + val exclusions = extension.exclusions.get() val suffixes = extension.suffixes.get() if (!instrumentationsDir.exists() || !instrumentationsDir.isDirectory) { @@ -62,8 +62,8 @@ class InstrumentationNamingPlugin : Plugin { To exclude specific modules or customize suffixes, configure the plugin: instrumentationNaming { - exclusions.set(listOf("module-name")) - suffixes.set(listOf("-common", "-stubs")) + exclusions.set(setOf("module-name")) + suffixes.set(setOf("-common", "-stubs")) } """.trimIndent()) } @@ -78,7 +78,7 @@ class InstrumentationNamingPlugin : Plugin { private fun validateInstrumentations( instrumentationsDir: File, exclusions: Set, - suffixes: List + suffixes: Set ): List { val violations = mutableListOf() @@ -123,7 +123,7 @@ class InstrumentationNamingPlugin : Plugin { moduleName: String, parentName: String, relativePath: String, - suffixes: List + suffixes: Set ): List { // Rule 1: Module name must end with version pattern or one of the configured suffixes validateVersionOrSuffix(moduleName, relativePath, suffixes)?.let { return listOf(it) } @@ -146,7 +146,7 @@ class InstrumentationNamingPlugin : Plugin { private fun validateLeafModuleName( moduleName: String, relativePath: String, - suffixes: List + suffixes: Set ): NamingViolation? { return validateVersionOrSuffix(moduleName, relativePath, suffixes) } @@ -157,7 +157,7 @@ class InstrumentationNamingPlugin : Plugin { private fun validateVersionOrSuffix( moduleName: String, relativePath: String, - suffixes: List + suffixes: Set ): NamingViolation? { val endsWithSuffix = suffixes.any { moduleName.endsWith(it) } val endsWithVersion = versionPattern.containsMatchIn(moduleName) From 59782ecb6242470411e2e43021d54539ffb17885 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 18 Dec 2025 10:41:06 +0100 Subject: [PATCH 13/14] Update buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt Co-authored-by: Brice Dutheil --- .../plugin/naming/InstrumentationNamingPlugin.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index 82af7773017..b8d5442d10d 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -47,12 +47,16 @@ class InstrumentationNamingPlugin : Plugin { if (violations.isNotEmpty()) { val suffixesStr = suffixes.joinToString("', '", "'", "'") val errorMessage = buildString { - appendLine("\nInstrumentation naming convention violations found:") - appendLine() + appendLine(""" + + Instrumentation naming convention violations found: + + """.trimIndent()) violations.forEach { violation -> - appendLine(" • ${violation.path}") - appendLine(" ${violation.message}") - appendLine() + appendLine(""" + • ${violation.path} + ${violation.message} + """.trimEndent()) } append(""" Naming rules: From 680fc577f9fbd81d6beb2dc8548331d85ad6a7c0 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Thu, 18 Dec 2025 10:45:49 +0100 Subject: [PATCH 14/14] fix the typo + remove the readme --- .../naming/InstrumentationNamingPlugin.kt | 2 +- .../datadog/gradle/plugin/naming/README.md | 84 ------------------- 2 files changed, 1 insertion(+), 85 deletions(-) delete mode 100644 buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt index b8d5442d10d..2a41f796161 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/InstrumentationNamingPlugin.kt @@ -56,7 +56,7 @@ class InstrumentationNamingPlugin : Plugin { appendLine(""" • ${violation.path} ${violation.message} - """.trimEndent()) + """.trimIndent()) } append(""" Naming rules: diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md b/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md deleted file mode 100644 index 502b8c0b8f1..00000000000 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/naming/README.md +++ /dev/null @@ -1,84 +0,0 @@ -# Instrumentation Naming Convention Plugin - -A Gradle plugin that validates naming conventions for instrumentation modules under `dd-java-agent/instrumentation`. - -## Naming Rules - -The plugin enforces the following rules: - -1. **Version or suffix**: Module names must end with either: - - A version number (e.g., `2.0`, `3.1`, `4.0.5`) - - One of the configured suffixes (default: `-common`, `-stubs`) - -2. **Parent directory inclusion**: Module names must include the parent directory name - - Example: `couchbase/couchbase-2.0` ✓ (module name contains "couchbase") - - Example: `couchbase/foo-2.0` ✗ (module name doesn't contain "couchbase") - -## Usage - -### Apply the plugin - -In your root `build.gradle` or `build.gradle.kts`: - -```kotlin -plugins { - id("dd-trace-java.instrumentation-naming") -} -``` - -### Run the validation - -```bash -./gradlew checkInstrumentationNaming -``` - -### Configuration - -You can configure the plugin with custom settings: - -```kotlin -instrumentationNaming { - // Optional: specify a different instrumentations directory - instrumentationsDir.set("path/to/instrumentations") - - // Optional: exclude specific modules from validation - exclusions.set(listOf( - "http-url-connection", - "sslsocket", - "classloading" - )) - - // Optional: configure allowed suffixes (default: ["-common", "-stubs"]) - suffixes.set(listOf( - "-common", - "-stubs", - "-utils" - )) -} -``` - -## Examples - -### Valid module names: -- `couchbase/couchbase-2.0` ✓ (ends with version) -- `couchbase/couchbase-2.6` ✓ (ends with version) -- `couchbase/couchbase-3.1` ✓ (ends with version) -- `kafka/kafka-common` ✓ (ends with -common suffix) -- `apache-httpclient/apache-httpclient-4.0` ✓ (ends with version) - -### Invalid module names: -- `couchbase/foo-2.0` ✗ (doesn't contain parent name "couchbase") -- `kafka/kafka` ✗ (missing version or allowed suffix) -- `kafka/kafka-latest` ✗ (not a valid version number or allowed suffix) - -## Integration with CI - -Add the task to your verification pipeline: - -```kotlin -tasks.named("check") { - dependsOn("checkInstrumentationNaming") -} -``` - -This ensures naming conventions are validated on every build.