Skip to content

Commit adced87

Browse files
Merge remote-tracking branch 'origin/master' into alexeyk/groovy-4
2 parents 15d93d0 + 6ccbc06 commit adced87

File tree

896 files changed

+1458
-1417
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

896 files changed

+1458
-1417
lines changed

.github/CODEOWNERS

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@
5151
/dd-java-agent/appsec/appsec-test-fixtures/ @DataDog/asm-java
5252
/dd-java-agent/instrumentation/*iast* @DataDog/asm-java
5353
/dd-java-agent/instrumentation/*appsec* @DataDog/asm-java
54-
/dd-java-agent/instrumentation/json/ @DataDog/asm-java
55-
/dd-java-agent/instrumentation/snakeyaml/ @DataDog/asm-java
56-
/dd-java-agent/instrumentation/velocity/ @DataDog/asm-java
54+
/dd-java-agent/instrumentation/org-json-20230227/ @DataDog/asm-java
55+
/dd-java-agent/instrumentation/snakeyaml-1.33/ @DataDog/asm-java
56+
/dd-java-agent/instrumentation/velocity-1.5/ @DataDog/asm-java
5757
/dd-java-agent/instrumentation/freemarker/ @DataDog/asm-java
5858
/dd-smoke-tests/iast-util/ @DataDog/asm-java
5959
/dd-smoke-tests/spring-security/ @DataDog/asm-java
@@ -77,18 +77,17 @@
7777

7878
# @DataDog/ci-app-libraries-java
7979
/dd-java-agent/agent-ci-visibility/ @DataDog/ci-app-libraries-java
80-
/dd-java-agent/instrumentation/cucumber/ @DataDog/ci-app-libraries-java
81-
/dd-java-agent/instrumentation/jacoco/ @DataDog/ci-app-libraries-java
80+
/dd-java-agent/instrumentation/cucumber-5.4/ @DataDog/ci-app-libraries-java
81+
/dd-java-agent/instrumentation/jacoco-0.8.9/ @DataDog/ci-app-libraries-java
8282
/dd-java-agent/instrumentation/junit @DataDog/ci-app-libraries-java
8383
/dd-java-agent/instrumentation/karate/ @DataDog/ci-app-libraries-java
84-
/dd-java-agent/instrumentation/scalatest/ @DataDog/ci-app-libraries-java
84+
/dd-java-agent/instrumentation/scalatest-3.0.8/ @DataDog/ci-app-libraries-java
8585
/dd-java-agent/instrumentation/selenium/ @DataDog/ci-app-libraries-java
8686
/dd-java-agent/instrumentation/testng/ @DataDog/ci-app-libraries-java
8787
/dd-java-agent/instrumentation/gradle/ @DataDog/ci-app-libraries-java
8888
/dd-java-agent/instrumentation/gradle-testing/ @DataDog/ci-app-libraries-java
8989
/dd-java-agent/instrumentation/maven @DataDog/ci-app-libraries-java
90-
/dd-java-agent/instrumentation/maven-surefire/ @DataDog/ci-app-libraries-java
91-
/dd-java-agent/instrumentation/weaver/ @DataDog/ci-app-libraries-java
90+
/dd-java-agent/instrumentation/weaver-0.9/ @DataDog/ci-app-libraries-java
9291
/dd-smoke-tests/gradle/ @DataDog/ci-app-libraries-java
9392
/dd-smoke-tests/junit-console/ @DataDog/ci-app-libraries-java
9493
/dd-smoke-tests/maven/ @DataDog/ci-app-libraries-java

.gitlab-ci.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,21 @@ default:
117117
- .gitlab/cgroup-info.sh
118118
- gitlab_section_end "cgroup-info"
119119

120+
.container_info: &container_info
121+
- |
122+
# Containers and processes are limited to a 1-hour window, and expire after 36 hours
123+
if [ -n "$CI_JOB_STARTED_AT" ]; then
124+
FROM_EPOCH_MS=$(date -d "$CI_JOB_STARTED_AT" +%s)000
125+
TO_EPOCH_MS=$((FROM_EPOCH_MS + 3600000))
126+
TIME_PARAMS="from_ts=${FROM_EPOCH_MS}&to_ts=${TO_EPOCH_MS}&"
127+
else
128+
TIME_PARAMS=""
129+
fi
130+
131+
echo -e "${TEXT_BOLD}${TEXT_YELLOW}Runner dashboard, these are live (limited to a 1-hour window, and expire after 36 hours)${TEXT_CLEAR}"
132+
echo -e "${TEXT_BOLD}${TEXT_YELLOW} Containers:${TEXT_CLEAR} https://app.datadoghq.com/containers?${TIME_PARAMS}query=image_name%3A%2A%2Fdatadog%2Fdd-trace-java-docker-build%20AND%20pod_name%3A${POD_NAME}&live=false"
133+
echo -e "${TEXT_BOLD}${TEXT_YELLOW} Processes:${TEXT_CLEAR} https://app.datadoghq.com/process?${TIME_PARAMS}query=image_name%3A%2A%2Fdatadog%2Fdd-trace-java-docker-build%20AND%20pod_name%3A${POD_NAME}&live=false"
134+
120135
.gitlab_base_ref_params: &gitlab_base_ref_params
121136
- |
122137
export GIT_BASE_REF=$(.gitlab/find-gh-base-ref.sh)
@@ -165,6 +180,7 @@ default:
165180
unprotect: true
166181
before_script:
167182
- source .gitlab/gitlab-utils.sh
183+
- *container_info
168184
# Akka token added to SSM from https://account.akka.io/token
169185
- export ORG_GRADLE_PROJECT_akkaRepositoryToken=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.akka_repo_token --with-decryption --query "Parameter.Value" --out text)
170186
- export ORG_GRADLE_PROJECT_mavenRepositoryProxy=$MAVEN_REPOSITORY_PROXY
@@ -195,6 +211,7 @@ default:
195211
- gitlab_section_end "gradle-dance"
196212
after_script:
197213
- *cgroup_info
214+
- *container_info
198215

199216
# Check and fail early if maven central credentials are incorrect. When a new token is generated
200217
# on the central publisher portal, it invalidates the old one. This check prevents going further.
@@ -419,6 +436,7 @@ test_published_artifacts:
419436
- ./gradlew --version
420437
- ./gradlew $GRADLE_TARGET -x spotlessCheck $GRADLE_PARAMS -PskipTests -PrunBuildSrcTests -Pslot=$CI_NODE_INDEX/$CI_NODE_TOTAL $GRADLE_ARGS
421438
after_script:
439+
- *container_info
422440
- *cgroup_info
423441
- source .gitlab/gitlab-utils.sh
424442
- gitlab_section_start "collect-reports" "Collecting reports"
@@ -487,6 +505,7 @@ muzzle:
487505
- ./gradlew --version
488506
- ./gradlew :runMuzzle -Pslot=$CI_NODE_INDEX/$CI_NODE_TOTAL $GRADLE_ARGS
489507
after_script:
508+
- *container_info
490509
- *cgroup_info
491510
- source .gitlab/gitlab-utils.sh
492511
- gitlab_section_start "collect-reports" "Collecting reports"
@@ -509,6 +528,7 @@ muzzle-dep-report:
509528
- ./gradlew --version
510529
- ./gradlew generateMuzzleReport muzzleInstrumentationReport $GRADLE_ARGS
511530
after_script:
531+
- *container_info
512532
- *cgroup_info
513533
- .gitlab/collect_muzzle_deps.sh
514534
artifacts:
@@ -571,6 +591,7 @@ muzzle-dep-report:
571591
after_script:
572592
- *restore_pretest_env
573593
- *set_datadog_api_keys
594+
- *container_info
574595
- *cgroup_info
575596
- source .gitlab/gitlab-utils.sh
576597
- gitlab_section_start "collect-reports" "Collecting reports"

build.gradle.kts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ plugins {
1212
id("dd-trace-java.ci-jobs")
1313

1414
id("com.diffplug.spotless") version "8.1.0"
15+
id("me.champeau.gradle.japicmp") version "0.4.3"
1516
id("com.github.spotbugs") version "6.4.7"
1617
id("de.thetaphi.forbiddenapis") version "3.10"
1718
id("io.github.gradle-nexus.publish-plugin") version "2.0.0"
@@ -156,3 +157,29 @@ testAggregate(
156157
":dd-java-agent:agent-debugger"
157158
)
158159
)
160+
161+
// JApiCmp configuration example
162+
// Usage: ./gradlew japicmp -Partifact=groupId:artifactId -Pbaseline=1.0.0 -Ptarget=2.0.0
163+
tasks.register<me.champeau.gradle.japicmp.JapicmpTask>("japicmp") {
164+
val artifact = providers.gradleProperty("artifact").orNull
165+
val baseline = providers.gradleProperty("baseline").orNull
166+
val target = providers.gradleProperty("target").orNull
167+
168+
if (artifact != null && baseline != null && target != null) {
169+
oldClasspath.from(
170+
configurations.detachedConfiguration(
171+
dependencies.create("$artifact:$baseline")
172+
)
173+
)
174+
newClasspath.from(
175+
configurations.detachedConfiguration(
176+
dependencies.create("$artifact:$target")
177+
)
178+
)
179+
onlyModified.set(true)
180+
failOnModification.set(false)
181+
ignoreMissingClasses.set(true)
182+
txtOutputFile.set(layout.buildDirectory.file("reports/japicmp.txt"))
183+
htmlOutputFile.set(layout.buildDirectory.file("reports/japicmp.html"))
184+
}
185+
}

buildSrc/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ gradlePlugin {
4747
id = "dd-trace-java.config-inversion-linter"
4848
implementationClass = "datadog.gradle.plugin.config.ConfigInversionLinter"
4949
}
50+
51+
create("instrumentation-naming") {
52+
id = "dd-trace-java.instrumentation-naming"
53+
implementationClass = "datadog.gradle.plugin.naming.InstrumentationNamingPlugin"
54+
}
5055
}
5156
}
5257

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ private fun registerLogEnvVarUsages(target: Project, extension: SupportedTracerC
8383
include("**/src/main/java/**/*.java")
8484
exclude("**/build/**", "**/dd-smoke-tests/**")
8585
// Undertow uses DD_UNDERTOW_CONTINUATION as a legacy key to store an AgentScope. It is not related to an environment variable
86-
exclude("dd-java-agent/instrumentation/undertow/src/main/java/datadog/trace/instrumentation/undertow/UndertowDecorator.java")
86+
exclude("dd-java-agent/instrumentation/undertow/undertow-common/src/main/java/datadog/trace/instrumentation/undertow/UndertowDecorator.java")
8787
}
8888
inputs.files(javaFiles)
8989
outputs.upToDateWhen { true }
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package datadog.gradle.plugin.naming
2+
3+
import org.gradle.api.provider.Property
4+
import org.gradle.api.provider.SetProperty
5+
6+
/**
7+
* Extension for configuring instrumentation naming convention checks.
8+
*
9+
* Example usage:
10+
* ```
11+
* instrumentationNaming {
12+
* instrumentationsDir.set(file("dd-java-agent/instrumentation"))
13+
* exclusions.set(setOf("http-url-connection", "sslsocket"))
14+
* suffixes.set(setOf("-common", "-stubs"))
15+
* }
16+
* ```
17+
*/
18+
abstract class InstrumentationNamingExtension {
19+
/**
20+
* The directory containing instrumentation modules.
21+
* Defaults to "dd-java-agent/instrumentation".
22+
*/
23+
abstract val instrumentationsDir: Property<String>
24+
25+
/**
26+
* Set of module names to exclude from naming convention checks.
27+
* These modules will not be validated against the naming rules.
28+
*/
29+
abstract val exclusions: SetProperty<String>
30+
31+
/**
32+
* Set of allowed suffixes for module names (e.g., "-common", "-stubs").
33+
* Module names must end with either one of these suffixes or a version number.
34+
* Defaults to ["-common", "-stubs"].
35+
*/
36+
abstract val suffixes: SetProperty<String>
37+
38+
init {
39+
instrumentationsDir.convention("dd-java-agent/instrumentation")
40+
exclusions.convention(emptySet())
41+
suffixes.convention(setOf("-common", "-stubs"))
42+
}
43+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package datadog.gradle.plugin.naming
2+
3+
import org.gradle.api.GradleException
4+
import org.gradle.api.Plugin
5+
import org.gradle.api.Project
6+
import org.gradle.kotlin.dsl.create
7+
import java.io.File
8+
9+
/**
10+
* Plugin that validates naming conventions for instrumentation modules.
11+
*
12+
* Rules:
13+
* 1. Module name must end with a version (e.g., "2.0", "3.1") OR end with "-common"
14+
* 2. Module name must include the parent directory name
15+
* (e.g., "couchbase-2.0" must contain "couchbase" which is the parent directory name)
16+
*
17+
* Apply this plugin:
18+
* ```
19+
* plugins {
20+
* id("dd-trace-java.instrumentation-naming")
21+
* }
22+
* ```
23+
*/
24+
class InstrumentationNamingPlugin : Plugin<Project> {
25+
private val versionPattern : Regex = Regex("""\d+\.\d+(\.\d+)?$""")
26+
27+
override fun apply(target: Project) {
28+
val extension = target.extensions.create<InstrumentationNamingExtension>("instrumentationNaming")
29+
30+
target.tasks.register("checkInstrumentationNaming") {
31+
group = "verification"
32+
description = "Validates naming conventions for instrumentation modules"
33+
34+
doLast {
35+
val instrumentationsDir = target.rootProject.file(extension.instrumentationsDir)
36+
val exclusions = extension.exclusions.get()
37+
val suffixes = extension.suffixes.get()
38+
39+
if (!instrumentationsDir.exists() || !instrumentationsDir.isDirectory) {
40+
throw GradleException(
41+
"Instrumentations directory not found: ${instrumentationsDir.absolutePath}"
42+
)
43+
}
44+
45+
val violations = validateInstrumentations(instrumentationsDir, exclusions, suffixes)
46+
47+
if (violations.isNotEmpty()) {
48+
val suffixesStr = suffixes.joinToString("', '", "'", "'")
49+
val errorMessage = buildString {
50+
appendLine("""
51+
52+
Instrumentation naming convention violations found:
53+
54+
""".trimIndent())
55+
violations.forEach { violation ->
56+
appendLine("""
57+
${violation.path}
58+
${violation.message}
59+
""".trimIndent())
60+
}
61+
append("""
62+
Naming rules:
63+
1. Module name must end with a version (e.g., '2.0', '3.1') OR one of: $suffixesStr
64+
2. Module name must include the parent directory name
65+
Example: 'couchbase/couchbase-2.0' ✓ (contains 'couchbase')
66+
67+
To exclude specific modules or customize suffixes, configure the plugin:
68+
instrumentationNaming {
69+
exclusions.set(setOf("module-name"))
70+
suffixes.set(setOf("-common", "-stubs"))
71+
}
72+
""".trimIndent())
73+
}
74+
throw GradleException(errorMessage)
75+
} else {
76+
target.logger.lifecycle("✓ All instrumentation modules follow naming conventions")
77+
}
78+
}
79+
}
80+
}
81+
82+
private fun validateInstrumentations(
83+
instrumentationsDir: File,
84+
exclusions: Set<String>,
85+
suffixes: Set<String>
86+
): List<NamingViolation> {
87+
val violations = mutableListOf<NamingViolation>()
88+
89+
fun hasBuildFile(dir: File): Boolean = dir.listFiles()?.any {
90+
it.name == "build.gradle" || it.name == "build.gradle.kts"
91+
} ?: false
92+
93+
fun traverseModules(currentDir: File, parentName: String?) {
94+
currentDir.listFiles { file -> file.isDirectory }?.forEach childLoop@{ childDir ->
95+
val moduleName = childDir.name
96+
97+
// Skip build directories and other non-instrumentation directories
98+
if (moduleName in setOf("build", "src", ".gradle")) {
99+
return@childLoop
100+
}
101+
102+
val childHasBuildFile = hasBuildFile(childDir)
103+
val nestedModules = childDir.listFiles { file -> file.isDirectory }?.filter { hasBuildFile(it) } ?: emptyList()
104+
105+
if (childHasBuildFile && moduleName !in exclusions) {
106+
val relativePath = childDir.relativeTo(instrumentationsDir).path
107+
if (parentName == null && nestedModules.isEmpty()) {
108+
validateLeafModuleName(moduleName, relativePath, suffixes)?.let { violations.add(it) }
109+
} else if (parentName != null) {
110+
violations.addAll(validateModuleName(moduleName, parentName, relativePath, suffixes))
111+
}
112+
}
113+
114+
// Continue traversing to validate deeply nested modules
115+
if (nestedModules.isNotEmpty() || !childHasBuildFile) {
116+
traverseModules(childDir, moduleName)
117+
}
118+
}
119+
}
120+
121+
traverseModules(instrumentationsDir, null)
122+
123+
return violations
124+
}
125+
126+
private fun validateModuleName(
127+
moduleName: String,
128+
parentName: String,
129+
relativePath: String,
130+
suffixes: Set<String>
131+
): List<NamingViolation> {
132+
// Rule 1: Module name must end with version pattern or one of the configured suffixes
133+
validateVersionOrSuffix(moduleName, relativePath, suffixes)?.let { return listOf(it) }
134+
135+
// Rule 2: Module name must contain parent directory name
136+
if (!moduleName.contains(parentName, ignoreCase = true)) {
137+
return listOf(NamingViolation(
138+
relativePath,
139+
"Module name '$moduleName' should contain parent directory name '$parentName'"
140+
))
141+
}
142+
143+
return emptyList()
144+
}
145+
146+
/**
147+
* Validates naming for leaf modules (modules at the top level with no parent grouping).
148+
* These only need to check the version/suffix requirement.
149+
*/
150+
private fun validateLeafModuleName(
151+
moduleName: String,
152+
relativePath: String,
153+
suffixes: Set<String>
154+
): NamingViolation? {
155+
return validateVersionOrSuffix(moduleName, relativePath, suffixes)
156+
}
157+
158+
/**
159+
* Validates that a module name ends with either a version or one of the configured suffixes.
160+
*/
161+
private fun validateVersionOrSuffix(
162+
moduleName: String,
163+
relativePath: String,
164+
suffixes: Set<String>
165+
): NamingViolation? {
166+
val endsWithSuffix = suffixes.any { moduleName.endsWith(it) }
167+
val endsWithVersion = versionPattern.containsMatchIn(moduleName)
168+
169+
if (!endsWithVersion && !endsWithSuffix) {
170+
val suffixesStr = suffixes.joinToString("', '", "'", "'")
171+
return NamingViolation(
172+
relativePath,
173+
"Module name '$moduleName' must end with a version (e.g., '2.0', '3.1.0') or one of: $suffixesStr"
174+
)
175+
}
176+
177+
return null
178+
}
179+
180+
private data class NamingViolation(
181+
val path: String,
182+
val message: String
183+
)
184+
}

0 commit comments

Comments
 (0)