diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index b0ec91d7fe2..d65930895b3 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -6,6 +6,41 @@ plugins { id("com.diffplug.spotless") version "8.1.0" } +spotless { + java { + toggleOffOn() + target("**/*.java") + + googleJavaFormat("1.32.0") + } + + kotlin { + toggleOffOn() + target("**/*.kt") + + ktlint("1.8.0").editorConfigOverride( + // Disable trailing comma rules to minimize diff. + mapOf( + "ktlint_standard_trailing-comma-on-call-site" to "disabled", + "ktlint_standard_trailing-comma-on-declaration-site" to "disabled" + ) + ) + } + + kotlinGradle { + toggleOffOn() + target("**/*.gradle.kts") + + ktlint("1.8.0").editorConfigOverride( + // Disable trailing comma rules to minimize diff. + mapOf( + "ktlint_standard_trailing-comma-on-call-site" to "disabled", + "ktlint_standard_trailing-comma-on-declaration-site" to "disabled" + ) + ) + } +} + java { toolchain { languageVersion = JavaLanguageVersion.of(8) diff --git a/buildSrc/call-site-instrumentation-plugin/build.gradle.kts b/buildSrc/call-site-instrumentation-plugin/build.gradle.kts index a668a17ce99..a17235c0519 100644 --- a/buildSrc/call-site-instrumentation-plugin/build.gradle.kts +++ b/buildSrc/call-site-instrumentation-plugin/build.gradle.kts @@ -1,7 +1,6 @@ plugins { java groovy - id("com.diffplug.spotless") version "8.1.0" id("com.gradleup.shadow") version "8.3.6" } @@ -10,17 +9,6 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } -spotless { - java { - toggleOffOn() - // set explicit target to workaround https://github.com/diffplug/spotless/issues/1163 - target("src/**/*.java") - // ignore embedded test projects - targetExclude("src/test/resources/**") - googleJavaFormat("1.32.0") - } -} - apply { from("$rootDir/../gradle/repositories.gradle") } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/ci/CIJobsExtensions.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/ci/CIJobsExtensions.kt index 3f837f27f6b..2f039de7fab 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/ci/CIJobsExtensions.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/ci/CIJobsExtensions.kt @@ -7,17 +7,20 @@ import org.gradle.kotlin.dsl.extra /** * Returns the task's path, given affected projects, if this task or its dependencies are affected by git changes. */ -internal fun findAffectedTaskPath(baseTask: Task, affectedProjects: Map>): String? { +internal fun findAffectedTaskPath( + baseTask: Task, + affectedProjects: Map> +): String? { val visited = mutableSetOf() val queue = mutableListOf(baseTask) - + while (queue.isNotEmpty()) { val t = queue.removeAt(0) if (visited.contains(t)) { continue } visited.add(t) - + val affectedTasks = affectedProjects[t.project] if (affectedTasks != null) { if (affectedTasks.contains("all")) { @@ -27,7 +30,7 @@ internal fun findAffectedTaskPath(baseTask: Task, affectedProjects: Map +): LoadedConfigFields = cachedConfigFields ?: run { + val urls = mainSourceSetOutput.files.map { it.toURI().toURL() }.toTypedArray() + URLClassLoader(urls, LoadedConfigFields::class.java.classLoader) + .use { cl -> val clazz = Class.forName(generatedClassName, true, cl) val supportedField = clazz.getField("SUPPORTED").get(null) + @Suppress("UNCHECKED_CAST") - val supportedSet = when (supportedField) { - is Set<*> -> supportedField as Set - is Map<*, *> -> supportedField.keys as Set - else -> throw IllegalStateException("SUPPORTED field must be either Set or Map, but was ${supportedField?.javaClass}") - } + val supportedSet = + when (supportedField) { + is Set<*> -> supportedField as Set + + is Map<*, *> -> supportedField.keys as Set + + else -> throw IllegalStateException( + "SUPPORTED field must be either Set or Map, but was ${supportedField?.javaClass}", + ) + } @Suppress("UNCHECKED_CAST") val aliasMappingMap = clazz.getField("ALIAS_MAPPING").get(null) as Map LoadedConfigFields(supportedSet, aliasMappingMap) }.also { cachedConfigFields = it } - } } /** Registers `logEnvVarUsages` (scan for DD_/OTEL_ tokens and fail if unsupported). */ -private fun registerLogEnvVarUsages(target: Project, extension: SupportedTracerConfigurations) { +private fun registerLogEnvVarUsages( + target: Project, + extension: SupportedTracerConfigurations +) { val ownerPath = extension.configOwnerPath val generatedFile = extension.className @@ -70,19 +78,23 @@ private fun registerLogEnvVarUsages(target: Project, extension: SupportedTracerC group = "verification" description = "Scan Java files for DD_/OTEL_ tokens and fail if unsupported (using generated constants)" - val mainSourceSetOutput = ownerPath.map { - target.project(it) - .extensions.getByType() - .named(SourceSet.MAIN_SOURCE_SET_NAME) - .map { main -> main.output } - } + val mainSourceSetOutput = + ownerPath.map { + target + .project(it) + .extensions + .getByType() + .named(SourceSet.MAIN_SOURCE_SET_NAME) + .map { main -> main.output } + } inputs.files(mainSourceSetOutput) // inputs for incrementality (your own source files, not the owner’s) - val javaFiles = target.fileTree(target.projectDir) { - include("**/src/main/java/**/*.java") - exclude("**/build/**", "**/dd-smoke-tests/**") - } + val javaFiles = + target.fileTree(target.projectDir) { + include("**/src/main/java/**/*.java") + exclude("**/build/**", "**/dd-smoke-tests/**") + } inputs.files(javaFiles) outputs.upToDateWhen { true } doLast { @@ -94,25 +106,26 @@ private fun registerLogEnvVarUsages(target: Project, extension: SupportedTracerC val repoRoot = target.projectDir.toPath() val tokenRegex = Regex("\"(?:DD_|OTEL_)[A-Za-z0-9_]+\"") - val violations = buildList { - javaFiles.files.forEach { f -> - val rel = repoRoot.relativize(f.toPath()).toString() - var inBlock = false - f.readLines().forEachIndexed { i, raw -> - val trimmed = raw.trim() - if (trimmed.startsWith("//")) return@forEachIndexed - if (!inBlock && trimmed.contains("/*")) inBlock = true - if (inBlock) { - if (trimmed.contains("*/")) inBlock = false - return@forEachIndexed - } - tokenRegex.findAll(raw).forEach { m -> - val token = m.value.trim('"') - if (token !in supported) add("$rel:${i + 1} -> Unsupported token '$token'") + val violations = + buildList { + javaFiles.files.forEach { f -> + val rel = repoRoot.relativize(f.toPath()).toString() + var inBlock = false + f.readLines().forEachIndexed { i, raw -> + val trimmed = raw.trim() + if (trimmed.startsWith("//")) return@forEachIndexed + if (!inBlock && trimmed.contains("/*")) inBlock = true + if (inBlock) { + if (trimmed.contains("*/")) inBlock = false + return@forEachIndexed + } + tokenRegex.findAll(raw).forEach { m -> + val token = m.value.trim('"') + if (token !in supported) add("$rel:${i + 1} -> Unsupported token '$token'") + } } } } - } if (violations.isNotEmpty()) { violations.forEach { target.logger.error(it) } @@ -132,25 +145,27 @@ private fun registerCheckEnvironmentVariablesUsage(project: Project) { doLast { val repoRoot: Path = project.projectDir.toPath() - val javaFiles = project.fileTree(project.projectDir) { - include("**/src/main/java/**/*.java") - exclude("**/build/**") - exclude("utils/config-utils/src/main/java/datadog/trace/config/inversion/ConfigHelper.java") - exclude("dd-java-agent/agent-bootstrap/**") - exclude("dd-java-agent/src/main/java/datadog/trace/bootstrap/**") - } + val javaFiles = + project.fileTree(project.projectDir) { + include("**/src/main/java/**/*.java") + exclude("**/build/**") + exclude("utils/config-utils/src/main/java/datadog/trace/config/inversion/ConfigHelper.java") + exclude("dd-java-agent/agent-bootstrap/**") + exclude("dd-java-agent/src/main/java/datadog/trace/bootstrap/**") + } val pattern = Regex("""EnvironmentVariables\.get\s*\(""") - val matches = buildList { - javaFiles.forEach { f -> - val relative = repoRoot.relativize(f.toPath()) - f.readLines().forEachIndexed { idx, line -> - if (pattern.containsMatchIn(line)) { - add("$relative:${idx + 1} -> ${line.trim()}") + val matches = + buildList { + javaFiles.forEach { f -> + val relative = repoRoot.relativize(f.toPath()) + f.readLines().forEachIndexed { idx, line -> + if (pattern.containsMatchIn(line)) { + add("$relative:${idx + 1} -> ${line.trim()}") + } } } } - } if (matches.isNotEmpty()) { project.logger.lifecycle("\nFound forbidden usages of EnvironmentVariables.get(...):") @@ -164,28 +179,33 @@ private fun registerCheckEnvironmentVariablesUsage(project: Project) { } // Helper functions for checking Config Strings -private fun normalize(configValue: String) = - "DD_" + configValue.uppercase().replace("-", "_").replace(".", "_") +private fun normalize(configValue: String) = "DD_" + configValue.uppercase().replace("-", "_").replace(".", "_") // Checking "public" "static" "final" -private fun NodeWithModifiers<*>.hasModifiers(vararg mods: Modifier.Keyword) = - mods.all { hasModifier(it) } +private fun NodeWithModifiers<*>.hasModifiers(vararg mods: Modifier.Keyword) = mods.all { hasModifier(it) } /** Registers `checkConfigStrings` to validate config definitions against documented supported configurations. */ -private fun registerCheckConfigStringsTask(project: Project, extension: SupportedTracerConfigurations) { +private fun registerCheckConfigStringsTask( + project: Project, + extension: SupportedTracerConfigurations +) { val ownerPath = extension.configOwnerPath val generatedFile = extension.className project.tasks.register("checkConfigStrings") { group = "verification" - description = "Validates that all config definitions in `dd-trace-api/src/main/java/datadog/trace/api/config` exist in `metadata/supported-configurations.json`" - - val mainSourceSetOutput = ownerPath.map { - project.project(it) - .extensions.getByType() - .named(SourceSet.MAIN_SOURCE_SET_NAME) - .map { main -> main.output } - } + description = + "Validates that all config definitions in `dd-trace-api/src/main/java/datadog/trace/api/config` exist in `metadata/supported-configurations.json`" + + val mainSourceSetOutput = + ownerPath.map { + project + .project(it) + .extensions + .getByType() + .named(SourceSet.MAIN_SOURCE_SET_NAME) + .map { main -> main.output } + } inputs.files(mainSourceSetOutput) doLast { @@ -205,41 +225,46 @@ private fun registerCheckConfigStringsTask(project: Project, extension: Supporte StaticJavaParser.setConfiguration(parserConfig) - val violations = buildList { - configDir.listFiles()?.forEach { file -> - val fileName = file.name - val cu: CompilationUnit = StaticJavaParser.parse(file) - - cu.findAll(VariableDeclarator::class.java).forEach { varDecl -> - varDecl.parentNode - .map { it as? FieldDeclaration } - .ifPresent { field -> - if (field.hasModifiers(Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC, Modifier.Keyword.FINAL) && - varDecl.typeAsString == "String") { - - val fieldName = varDecl.nameAsString - if (fieldName.endsWith("_DEFAULT")) return@ifPresent - val init = varDecl.initializer.orElse(null) ?: return@ifPresent - - if (init !is StringLiteralExpr) return@ifPresent - val rawValue = init.value - - val normalized = normalize(rawValue) - if (normalized !in supported && normalized !in aliasMapping) { - val line = varDecl.range.map { it.begin.line }.orElse(1) - add("$fileName:$line -> Config '$rawValue' normalizes to '$normalized' " + - "which is missing from '${extension.jsonFile.get()}'") + val violations = + buildList { + configDir.listFiles()?.forEach { file -> + val fileName = file.name + val cu: CompilationUnit = StaticJavaParser.parse(file) + + cu.findAll(VariableDeclarator::class.java).forEach { varDecl -> + varDecl.parentNode + .map { it as? FieldDeclaration } + .ifPresent { field -> + if (field.hasModifiers(Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC, Modifier.Keyword.FINAL) && + varDecl.typeAsString == "String" + ) { + val fieldName = varDecl.nameAsString + if (fieldName.endsWith("_DEFAULT")) return@ifPresent + val init = varDecl.initializer.orElse(null) ?: return@ifPresent + + if (init !is StringLiteralExpr) return@ifPresent + val rawValue = init.value + + val normalized = normalize(rawValue) + if (normalized !in supported && normalized !in aliasMapping) { + val line = varDecl.range.map { it.begin.line }.orElse(1) + add( + "$fileName:$line -> Config '$rawValue' normalizes to '$normalized' " + + "which is missing from '${extension.jsonFile.get()}'", + ) + } } } - } + } } } - } if (violations.isNotEmpty()) { logger.error("\nFound config definitions not in '${extension.jsonFile.get()}':") violations.forEach { logger.lifecycle(it) } - throw GradleException("Undocumented Environment Variables found. Please add the above Environment Variables to '${extension.jsonFile.get()}'.") + throw GradleException( + "Undocumented Environment Variables found. Please add the above Environment Variables to '${extension.jsonFile.get()}'.", + ) } else { logger.info("All config strings are present in '${extension.jsonFile.get()}'.") } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/ParseSupportedConfigurationsTask.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/ParseSupportedConfigurationsTask.kt index 0864efbcbdc..e8639f0dae8 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/ParseSupportedConfigurationsTask.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/ParseSupportedConfigurationsTask.kt @@ -1,23 +1,25 @@ package datadog.gradle.plugin.config +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper import org.gradle.api.DefaultTask import org.gradle.api.model.ObjectFactory +import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.OutputDirectory -import org.gradle.api.tasks.TaskAction -import com.fasterxml.jackson.core.type.TypeReference -import com.fasterxml.jackson.databind.ObjectMapper -import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity +import org.gradle.api.tasks.TaskAction import java.io.File import java.io.FileInputStream import java.io.PrintWriter import javax.inject.Inject @CacheableTask -abstract class ParseSupportedConfigurationsTask @Inject constructor( +abstract class ParseSupportedConfigurationsTask +@Inject +constructor( private val objects: ObjectFactory ) : DefaultTask() { @InputFile @@ -39,14 +41,17 @@ abstract class ParseSupportedConfigurationsTask @Inject constructor( // Read JSON (directly from the file, not classpath) val mapper = ObjectMapper() - val fileData: Map = FileInputStream(input).use { inStream -> - mapper.readValue(inStream, object : TypeReference>() {}) - } + val fileData: Map = + FileInputStream(input).use { inStream -> + mapper.readValue(inStream, object : TypeReference>() {}) + } @Suppress("UNCHECKED_CAST") val supported = fileData["supportedConfigurations"] as Map> + @Suppress("UNCHECKED_CAST") val aliases = fileData["aliases"] as Map> + @Suppress("UNCHECKED_CAST") val deprecated = (fileData["deprecations"] as? Map) ?: emptyMap() @@ -149,9 +154,7 @@ abstract class ParseSupportedConfigurationsTask @Inject constructor( } } - private fun quoteList(list: List): String = - list.joinToString(", ") { "\"${esc(it)}\"" } + private fun quoteList(list: List): String = list.joinToString(", ") { "\"${esc(it)}\"" } - private fun esc(s: String): String = - s.replace("\\", "\\\\").replace("\"", "\\\"") + private fun esc(s: String): String = s.replace("\\", "\\\\").replace("\"", "\\\"") } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/SupportedConfigPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/SupportedConfigPlugin.kt index 2aad9ff564e..31bfcef2d64 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/SupportedConfigPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/SupportedConfigPlugin.kt @@ -11,7 +11,10 @@ class SupportedConfigPlugin : Plugin { generateSupportedConfigurations(targetProject, extension) } - private fun generateSupportedConfigurations(targetProject: Project, extension: SupportedTracerConfigurations) { + private fun generateSupportedConfigurations( + targetProject: Project, + extension: SupportedTracerConfigurations + ) { val generateTask = targetProject.tasks.register("generateSupportedConfigurations", ParseSupportedConfigurationsTask::class.java) { jsonFile.set(extension.jsonFile) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/SupportedTracerConfigurations.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/SupportedTracerConfigurations.kt index cb93cb1b84e..7a7acfdf5e3 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/SupportedTracerConfigurations.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/SupportedTracerConfigurations.kt @@ -5,11 +5,32 @@ import org.gradle.api.file.ProjectLayout import org.gradle.api.model.ObjectFactory import javax.inject.Inject -open class SupportedTracerConfigurations @Inject constructor(objects: ObjectFactory, layout: ProjectLayout, project: Project) { - val configOwnerPath = objects.property(String::class.java).convention(":utils:config-utils") - val className = objects.property(String::class.java).convention("datadog.trace.config.inversion.GeneratedSupportedConfigurations") +open class SupportedTracerConfigurations +@Inject +constructor( + objects: ObjectFactory, + layout: ProjectLayout, + project: Project +) { + val configOwnerPath = + objects + .property(String::class.java) + .convention(":utils:config-utils") - val jsonFile = objects.fileProperty().convention(project.rootProject.layout.projectDirectory.file("metadata/supported-configurations.json")) + val className = + objects + .property(String::class.java) + .convention("datadog.trace.config.inversion.GeneratedSupportedConfigurations") - val destinationDirectory = objects.directoryProperty().convention(layout.buildDirectory.dir("generated/supportedConfigurations")) + val jsonFile = + objects.fileProperty().convention( + project.rootProject.layout.projectDirectory + .file("metadata/supported-configurations.json"), + ) + + val destinationDirectory = + objects.directoryProperty().convention( + layout.buildDirectory + .dir("generated/supportedConfigurations"), + ) } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt index 7e176a65320..8a1f9d1ff26 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt @@ -12,11 +12,12 @@ import org.gradle.kotlin.dsl.property import java.io.File import javax.inject.Inject - /** * This extension allows to configure the Call Site Instrumenter plugin execution. */ -abstract class CallSiteInstrumentationExtension @Inject constructor( +abstract class CallSiteInstrumentationExtension +@Inject +constructor( objectFactory: ObjectFactory, layout: ProjectLayout ) { @@ -29,16 +30,21 @@ abstract class CallSiteInstrumentationExtension @Inject constructor( /** * The location of the source code to generate call site ({@code /src/main/java} by default). */ - val srcFolder: DirectoryProperty = objectFactory.directoryProperty().convention( - layout.projectDirectory.dir("src").dir("main").dir("java") - ) + val srcFolder: DirectoryProperty = + objectFactory.directoryProperty().convention( + layout.projectDirectory + .dir("src") + .dir("main") + .dir("java") + ) /** * The location to generate call site source code ({@code /build/generated/sources/csi} by default). */ - val targetFolder: DirectoryProperty = objectFactory.directoryProperty().convention( - layout.buildDirectory.dir("generated/sources/$CSI_SOURCE_SET") - ) + val targetFolder: DirectoryProperty = + objectFactory.directoryProperty().convention( + layout.buildDirectory.dir("generated/sources/$CSI_SOURCE_SET") + ) /** * The generated call site source file suffix (#CALL_SITE_CLASS_SUFFIX by default). @@ -48,12 +54,13 @@ abstract class CallSiteInstrumentationExtension @Inject constructor( /** * The reporters to use after call site instrumenter run (only #CALL_SITE_CONSOLE_REPORTER and #CALL_SITE_ERROR_CONSOLE_REPORTER supported for now). */ - val reporters: ListProperty = objectFactory.listProperty().convention( - listOf( - CALL_SITE_CONSOLE_REPORTER, - CALL_SITE_ERROR_CONSOLE_REPORTER + val reporters: ListProperty = + objectFactory.listProperty().convention( + listOf( + CALL_SITE_CONSOLE_REPORTER, + CALL_SITE_ERROR_CONSOLE_REPORTER + ) ) - ) /** * The location of the dd-trace-java project to look for the call site instrumenter (optional, current project root folder used if not set). diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 28d9480bb3f..7bdac715af6 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -17,7 +17,6 @@ import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME import org.gradle.api.tasks.SourceSetContainer import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.compile.AbstractCompile -import org.gradle.internal.configuration.problems.projectPathFrom import org.gradle.jvm.tasks.Jar import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.kotlin.dsl.apply @@ -51,15 +50,19 @@ abstract class CallSiteInstrumentationPlugin : Plugin { configureTestConfigurations(project, csiExtension) } - private fun configureSourceSets(project: Project, extension: CallSiteInstrumentationExtension) { + private fun configureSourceSets( + project: Project, + extension: CallSiteInstrumentationExtension + ) { // create a new source set for the csi files val sourceSets = project.sourceSets val mainSourceSet = sourceSets.named(MAIN_SOURCE_SET_NAME).get() - val csiSourceSet = sourceSets.create(CSI_SOURCE_SET) { - compileClasspath += mainSourceSet.output // mainly needed for the plugin tests - annotationProcessorPath += mainSourceSet.annotationProcessorPath - java.srcDir(extension.targetFolder) - } + val csiSourceSet = + sourceSets.create(CSI_SOURCE_SET) { + compileClasspath += mainSourceSet.output // mainly needed for the plugin tests + annotationProcessorPath += mainSourceSet.annotationProcessorPath + java.srcDir(extension.targetFolder) + } project.configurations.named(csiSourceSet.compileClasspathConfigurationName) { extendsFrom(project.configurations.named(mainSourceSet.compileClasspathConfigurationName).get()) @@ -92,7 +95,10 @@ abstract class CallSiteInstrumentationPlugin : Plugin { return file } - private fun configureTestConfigurations(project: Project, csiExtension: CallSiteInstrumentationExtension) { + private fun configureTestConfigurations( + project: Project, + csiExtension: CallSiteInstrumentationExtension + ) { project.pluginManager.withPlugin("jvm-test-suite") { project.extensions.getByType().suites.withType().configureEach { project.logger.info("Configuring jvm test suite '{}' to use csiExtension.targetFolder", name) @@ -110,82 +116,88 @@ abstract class CallSiteInstrumentationPlugin : Plugin { mainCompileTask: TaskProvider ) { val genTaskName = mainCompileTask.name.replace("compile", "generateCallSite") - val pluginJarFile = Paths.get( - csiExtension.rootFolder.getOrElse(project.rootDir).toString(), - "buildSrc", - "call-site-instrumentation-plugin", - "build", - "libs", - "call-site-instrumentation-plugin-all.jar" - ) - - val callSiteGeneratorTask = project.tasks.register(genTaskName) { - // Task description - group = "call site instrumentation" - description = "Generates call sites from ${mainCompileTask.name}" - - // Remote Debug - if (project.providers.gradleProperty("debugCsiJar").isPresent) { - jvmArgs("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:5005") - } - - // Task input & output - val output = csiExtension.targetFolder - val inputProvider = mainCompileTask.flatMap { it.destinationDirectory } - inputs.dir(inputProvider) - inputs.dir(csiExtension.srcFolder) - inputs.dir(csiExtension.rootFolder).optional() - inputs.file(pluginJarFile) - inputs.property("csi.suffix", csiExtension.suffix) - inputs.property("csi.javaVersion", csiExtension.javaVersion) - inputs.property("csi.jvmArgs", csiExtension.jvmArgs) - inputs.property("csi.reporters", csiExtension.reporters) - outputs.dir(output) - - // JavaExec configuration - javaLauncher.set(javaToolchains.launcherFor { - languageVersion.set(csiExtension.javaVersion) - }) - - jvmArgumentProviders.add({ csiExtension.jvmArgs.get() }) - classpath(pluginJarFile) - mainClass.set(CALL_SITE_INSTRUMENTER_MAIN_CLASS) - - // Write the call site instrumenter arguments into a temporary file - doFirst { - val callsitesClassPath = project.files( - project.sourceSets.named(MAIN_SOURCE_SET_NAME).map { it.output }, - project.defaultConfigurations, - csiExtension.additionalPaths, - ) - - if (logger.isInfoEnabled) { - logger.info( - "Aggregated CSI classpath:\n{}", - callsitesClassPath.toSet().sorted().joinToString("\n") { it.toString() } - ) + val pluginJarFile = + Paths.get( + csiExtension.rootFolder.getOrElse(project.rootDir).toString(), + "buildSrc", + "call-site-instrumentation-plugin", + "build", + "libs", + "call-site-instrumentation-plugin-all.jar" + ) + + val callSiteGeneratorTask = + project.tasks.register(genTaskName) { + // Task description + group = "call site instrumentation" + description = "Generates call sites from ${mainCompileTask.name}" + + // Remote Debug + if (project.providers.gradleProperty("debugCsiJar").isPresent) { + jvmArgs("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:5005") } - val argFile = buildList { - add(csiExtension.srcFolder.get().asFile.toString()) - add(inputProvider.get().asFile.toString()) - add(output.get().asFile.toString()) - add(csiExtension.suffix.get()) - add(csiExtension.reporters.get().joinToString(",")) + // Task input & output + val output = csiExtension.targetFolder + val inputProvider = mainCompileTask.flatMap { it.destinationDirectory } + inputs.dir(inputProvider) + inputs.dir(csiExtension.srcFolder) + inputs.dir(csiExtension.rootFolder).optional() + inputs.file(pluginJarFile) + inputs.property("csi.suffix", csiExtension.suffix) + inputs.property("csi.javaVersion", csiExtension.javaVersion) + inputs.property("csi.jvmArgs", csiExtension.jvmArgs) + inputs.property("csi.reporters", csiExtension.reporters) + outputs.dir(output) + + // JavaExec configuration + javaLauncher.set( + javaToolchains.launcherFor { + languageVersion.set(csiExtension.javaVersion) + } + ) - // module program classpath - addAll(callsitesClassPath.map { it.toString() }) + jvmArgumentProviders.add({ csiExtension.jvmArgs.get() }) + classpath(pluginJarFile) + mainClass.set(CALL_SITE_INSTRUMENTER_MAIN_CLASS) + + // Write the call site instrumenter arguments into a temporary file + doFirst { + val callSitesClassPath = + project.files( + project.sourceSets.named(MAIN_SOURCE_SET_NAME).map { it.output }, + project.defaultConfigurations, + csiExtension.additionalPaths, + ) + + if (logger.isInfoEnabled) { + logger.info( + "Aggregated CSI classpath:\n{}", + callSitesClassPath.toSet().sorted().joinToString("\n") { it.toString() } + ) + } + + val argFile = + buildList { + add(csiExtension.srcFolder.get().asFile.toString()) + add(inputProvider.get().asFile.toString()) + add(output.get().asFile.toString()) + add(csiExtension.suffix.get()) + add(csiExtension.reporters.get().joinToString(",")) + + // module program classpath + addAll(callSitesClassPath.map { it.toString() }) + } + + val argumentFile = newTempFile(temporaryDir, "call-site-arguments") + Files.write(argumentFile.toPath(), argFile) + args(argumentFile.toString()) } - val argumentFile = newTempFile(temporaryDir, "call-site-arguments") - Files.write(argumentFile.toPath(), argFile) - args(argumentFile.toString()) + // make task depends on compile + dependsOn(mainCompileTask) } - // make task depends on compile - dependsOn(mainCompileTask) - } - // Workaround for instrument plugin modifying compile tasks project.pluginManager.withPlugin("dd-trace-java.instrument") { callSiteGeneratorTask.configure { @@ -210,27 +222,30 @@ abstract class CallSiteInstrumentationPlugin : Plugin { } private val Project.defaultConfigurations: NamedDomainObjectSet - get() = project.configurations.matching { - // Includes all main* source sets, but only the test (as wee don;t want other ) - // * For main => runtimeClasspath, compileClasspath - // * For test => testRuntimeClasspath, testCompileClasspath - // * For other main* => "main_javaXXRuntimeClasspath", "main_javaXXCompileClasspath" - - when (it.name) { - // Regular main and test source sets - RUNTIME_CLASSPATH_CONFIGURATION_NAME, - COMPILE_CLASSPATH_CONFIGURATION_NAME, - TEST_SOURCE_SET_NAME + RUNTIME_CLASSPATH_CONFIGURATION_NAME.capitalize(), - TEST_SOURCE_SET_NAME + COMPILE_CLASSPATH_CONFIGURATION_NAME.capitalize() -> true - - else -> false + get() = + project.configurations.matching { + // Includes all main* source sets, but only the test (as wee don;t want other ) + // * For main => runtimeClasspath, compileClasspath + // * For test => testRuntimeClasspath, testCompileClasspath + // * For other main* => "main_javaXXRuntimeClasspath", "main_javaXXCompileClasspath" + + when (it.name) { + // Regular main and test source sets + RUNTIME_CLASSPATH_CONFIGURATION_NAME, + COMPILE_CLASSPATH_CONFIGURATION_NAME, + TEST_SOURCE_SET_NAME + RUNTIME_CLASSPATH_CONFIGURATION_NAME.capitalize(), + TEST_SOURCE_SET_NAME + COMPILE_CLASSPATH_CONFIGURATION_NAME.capitalize() -> true + + else -> false + } } - } private fun String.capitalize(): String = replaceFirstChar { - if (it.isLowerCase()) it.titlecase( - Locale.getDefault() - ) else it.toString() + if (it.isLowerCase()) { + it.titlecase(Locale.getDefault()) + } else { + it.toString() + } } private val Project.sourceSets: SourceSetContainer diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/dump/DumpHangedTestPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/dump/DumpHangedTestPlugin.kt index 41b15380b4a..b0fbb921b85 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/dump/DumpHangedTestPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/dump/DumpHangedTestPlugin.kt @@ -38,12 +38,13 @@ class DumpHangedTestPlugin : Plugin { } /** Executor wrapped with proper Gradle lifecycle. */ - abstract class DumpSchedulerService : BuildService, AutoCloseable { + abstract class DumpSchedulerService : + BuildService, + AutoCloseable { private val executor: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor { r -> Thread(r, "hanged-test-dump").apply { isDaemon = true } } - fun schedule(task: () -> Unit, delay: Duration): ScheduledFuture<*> = - executor.schedule(task, delay.toMillis(), TimeUnit.MILLISECONDS) + fun schedule(task: () -> Unit, delay: Duration): ScheduledFuture<*> = executor.schedule(task, delay.toMillis(), TimeUnit.MILLISECONDS) override fun close() { executor.shutdownNow() @@ -55,8 +56,9 @@ class DumpHangedTestPlugin : Plugin { return } - val scheduler = project.gradle.sharedServices - .registerIfAbsent("dumpHangedTestScheduler", DumpSchedulerService::class.java) + val scheduler = + project.gradle.sharedServices + .registerIfAbsent("dumpHangedTestScheduler", DumpSchedulerService::class.java) // Create plugin properties. val props = project.extensions.create("dumpHangedTest", DumpHangedTestProperties::class.java) @@ -89,11 +91,12 @@ class DumpHangedTestPlugin : Plugin { return } - val future = scheduler.get().schedule({ - t.logger.quiet("Taking dumps after ${delay.seconds} seconds delay for $taskName") + val future = + scheduler.get().schedule({ + t.logger.quiet("Taking dumps after ${delay.seconds} seconds delay for $taskName") - takeDump(t) - }, delay) + takeDump(t) + }, delay) t.extra.set(DUMP_FUTURE_KEY, future) } @@ -101,27 +104,26 @@ class DumpHangedTestPlugin : Plugin { private fun takeDump(t: Task) { try { // Use Gradle's build dir and adjust for CI artifacts collection if needed. - val dumpsDir: File = t.project.layout.buildDirectory - .dir("dumps") - .map { dir -> - if (t.project.providers.environmentVariable("CI").isPresent) { - // Move reports into the folder collected by the collect_reports.sh script. - File( - dir.asFile.absolutePath.replace( - "dd-trace-java/dd-java-agent", - "dd-trace-java/workspace/dd-java-agent" + val dumpsDir: File = + t.project.layout.buildDirectory + .dir("dumps") + .map { dir -> + if (t.project.providers.environmentVariable("CI").isPresent) { + // Move reports into the folder collected by the collect_reports.sh script. + File( + dir.asFile.absolutePath.replace( + "dd-trace-java/dd-java-agent", + "dd-trace-java/workspace/dd-java-agent" + ) ) - ) - } else { - dir.asFile - } - } - .get() + } else { + dir.asFile + } + }.get() dumpsDir.mkdirs() - fun file(name: String, ext: String = "log") = - File(dumpsDir, "$name-${System.currentTimeMillis()}.$ext") + fun file(name: String, ext: String = "log") = File(dumpsDir, "$name-${System.currentTimeMillis()}.$ext") // For simplicity, use `0` as the PID, which collects all thread dumps across JVMs. val allThreadsFile = file("all-thread-dumps") @@ -132,17 +134,19 @@ class DumpHangedTestPlugin : Plugin { runCmd(Redirect.to(allJavaProcessesFile), "jcmd", "-l") // Collect pids for 'Gradle Test Executor'. - val pids = allJavaProcessesFile.readLines() - .filter { it.contains("Gradle Test Executor") } - .map { it.substringBefore(' ') } + val pids = + allJavaProcessesFile + .readLines() + .filter { it.contains("Gradle Test Executor") } + .map { it.substringBefore(' ') } pids.forEach { pid -> // Collect heap dump by pid. - val heapDumpPath = file("${pid}-heap-dump", "hprof").absolutePath + val heapDumpPath = file("$pid-heap-dump", "hprof").absolutePath runCmd(Redirect.INHERIT, "jcmd", pid, "GC.heap_dump", heapDumpPath) // Collect thread dump by pid. - val threadDumpFile = file("${pid}-thread-dump") + val threadDumpFile = file("$pid-thread-dump") runCmd(Redirect.to(threadDumpFile), "jcmd", pid, "Thread.print", "-l") } } catch (e: Throwable) { @@ -151,9 +155,10 @@ class DumpHangedTestPlugin : Plugin { } private fun cleanup(t: Task) { - val future = t.extra - .takeIf { it.has(DUMP_FUTURE_KEY) } - ?.get(DUMP_FUTURE_KEY) as? ScheduledFuture<*> + val future = + t.extra + .takeIf { it.has(DUMP_FUTURE_KEY) } + ?.get(DUMP_FUTURE_KEY) as? ScheduledFuture<*> if (future != null && !future.isDone) { t.logger.info("Taking dump canceled with remaining delay of ${future.getDelay(TimeUnit.SECONDS)} seconds for ${t.path}") @@ -165,11 +170,12 @@ class DumpHangedTestPlugin : Plugin { redirectTo: Redirect, vararg args: String ) { - val exitCode = ProcessBuilder(*args) - .redirectErrorStream(true) - .redirectOutput(redirectTo) - .start() - .waitFor() + val exitCode = + ProcessBuilder(*args) + .redirectErrorStream(true) + .redirectOutput(redirectTo) + .start() + .waitFor() if (exitCode != 0) { throw IOException("Process failed: ${args.joinToString(" ")}, exit code: $exitCode") diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleAction.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleAction.kt index d9d1793ca55..0ddee717177 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleAction.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleAction.kt @@ -7,48 +7,57 @@ import java.lang.reflect.Method import java.net.URLClassLoader abstract class MuzzleAction : WorkAction { - companion object { - private val lock = Any() - private var bootCL: ClassLoader? = null - private var toolCL: ClassLoader? = null - @Volatile - private var lastBuildStamp: Long = 0 + companion object { + private val lock = Any() + private var bootCL: ClassLoader? = null + private var toolCL: ClassLoader? = null - fun createClassLoader(cp: FileCollection, parent: ClassLoader = ClassLoader.getSystemClassLoader()): ClassLoader { - val urls = cp.map { it.toURI().toURL() }.toTypedArray() - return URLClassLoader(urls, parent) - } + @Volatile + private var lastBuildStamp: Long = 0 + + fun createClassLoader(cp: FileCollection, parent: ClassLoader = ClassLoader.getSystemClassLoader()): ClassLoader { + val urls = cp.map { it.toURI().toURL() }.toTypedArray() + return URLClassLoader(urls, parent) } + } - override fun execute() { - val buildStamp = parameters.buildStartedTime.get() + override fun execute() { + val buildStamp = parameters.buildStartedTime.get() + if (bootCL == null || toolCL == null || lastBuildStamp < buildStamp) { + synchronized(lock) { if (bootCL == null || toolCL == null || lastBuildStamp < buildStamp) { - synchronized(lock) { - if (bootCL == null || toolCL == null || lastBuildStamp < buildStamp) { - bootCL = createClassLoader(parameters.bootstrapClassPath) - toolCL = createClassLoader(parameters.toolingClassPath, bootCL!!) - lastBuildStamp = buildStamp - } - } + bootCL = createClassLoader(parameters.bootstrapClassPath) + toolCL = createClassLoader(parameters.toolingClassPath, bootCL!!) + lastBuildStamp = buildStamp } - val instCL = createClassLoader(parameters.instrumentationClassPath, toolCL!!) - val testCL = createClassLoader(parameters.testApplicationClassPath, bootCL!!) - val assertPass = parameters.assertPass.get() - val muzzleDirective = parameters.muzzleDirective.orNull - val assertionMethod: Method = instCL.loadClass("datadog.trace.agent.tooling.muzzle.MuzzleVersionScanPlugin") - .getMethod( - "assertInstrumentationMuzzled", - ClassLoader::class.java, - ClassLoader::class.java, - Boolean::class.java, - String::class.java - ) - try { - assertionMethod.invoke(null, instCL, testCL, assertPass, muzzleDirective) - parameters.resultFile.get().asFile.writeText("PASSING") - } catch (e: Exception) { - parameters.resultFile.get().asFile.writeText(e.stackTraceToString()) - throw GradleException("Muzzle validation failed", e) } } + val instCL = createClassLoader(parameters.instrumentationClassPath, toolCL!!) + val testCL = createClassLoader(parameters.testApplicationClassPath, bootCL!!) + val assertPass = parameters.assertPass.get() + val muzzleDirective = parameters.muzzleDirective.orNull + val assertionMethod: Method = + instCL + .loadClass("datadog.trace.agent.tooling.muzzle.MuzzleVersionScanPlugin") + .getMethod( + "assertInstrumentationMuzzled", + ClassLoader::class.java, + ClassLoader::class.java, + Boolean::class.java, + String::class.java + ) + try { + assertionMethod.invoke(null, instCL, testCL, assertPass, muzzleDirective) + parameters.resultFile + .get() + .asFile + .writeText("PASSING") + } catch (e: Exception) { + parameters.resultFile + .get() + .asFile + .writeText(e.stackTraceToString()) + throw GradleException("Muzzle validation failed", e) + } + } } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleDirective.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleDirective.kt index d82e706e13d..e9e164a21a5 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleDirective.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleDirective.kt @@ -70,16 +70,16 @@ open class MuzzleDirective : Serializable { * @param defaults the default repositories * @return a list of the default repositories followed by any additional repositories */ - internal fun getRepositories(defaults: List): List { - return if (additionalRepositories.isEmpty()) { - defaults - } else { - ArrayList(defaults.size + additionalRepositories.size).apply { - addAll(defaults) - addAll(additionalRepositories.map { (id, type, url) -> + internal fun getRepositories(defaults: List): List = if (additionalRepositories.isEmpty()) { + defaults + } else { + ArrayList(defaults.size + additionalRepositories.size).apply { + addAll(defaults) + addAll( + additionalRepositories.map { (id, type, url) -> RemoteRepository.Builder(id, type, url).build() - }) - } + } + ) } } @@ -91,12 +91,9 @@ open class MuzzleDirective : Serializable { val nameSlug: String get() = name?.trim()?.replace(Regex("[^a-zA-Z0-9]+"), "-") ?: "" - override fun toString(): String { - return if (isCoreJdk) { - "${if (assertPass) "Pass" else "Fail"}-core-jdk" - } else { - "${if (assertPass) "pass" else "fail"} $group:$module:$versions" - } + override fun toString(): String = if (isCoreJdk) { + "${if (assertPass) "Pass" else "Fail"}-core-jdk" + } else { + "${if (assertPass) "pass" else "fail"} $group:$module:$versions" } } - diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleExtension.kt index 2bb88e8d69d..0fd1ac3f1f7 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleExtension.kt @@ -3,49 +3,49 @@ package datadog.gradle.plugin.muzzle import org.gradle.api.Action import org.gradle.api.model.ObjectFactory import org.gradle.kotlin.dsl.newInstance -import javax.inject.Inject import java.util.Locale +import javax.inject.Inject /** * Muzzle extension containing all pass and fail directives. */ abstract class MuzzleExtension @Inject constructor(private val objectFactory: ObjectFactory) { - val directives: MutableList = ArrayList() - private val additionalRepositories: MutableList> = ArrayList() + val directives: MutableList = ArrayList() + private val additionalRepositories: MutableList> = ArrayList() - fun pass(action: Action) { - val pass = objectFactory.newInstance() - action.execute(pass) - postConstruct(pass) - pass.assertPass = true - directives.add(pass) - } + fun pass(action: Action) { + val pass = objectFactory.newInstance() + action.execute(pass) + postConstruct(pass) + pass.assertPass = true + directives.add(pass) + } - fun fail(action: Action) { - val fail = objectFactory.newInstance() - action.execute(fail) - postConstruct(fail) - fail.assertPass = false - directives.add(fail) - } + fun fail(action: Action) { + val fail = objectFactory.newInstance() + action.execute(fail) + postConstruct(fail) + fail.assertPass = false + directives.add(fail) + } - /** - * Adds extra repositories to the current muzzle section. Repositories will only be added to directives - * created after this. - * - * @param id the repository id - * @param url the url of the repository - * @param type the type of repository, defaults to "default" - */ - @JvmOverloads - fun extraRepository(id: String, url: String, type: String = "default") { - additionalRepositories.add(Triple(id, type, url)) - } + /** + * Adds extra repositories to the current muzzle section. Repositories will only be added to directives + * created after this. + * + * @param id the repository id + * @param url the url of the repository + * @param type the type of repository, defaults to "default" + */ + @JvmOverloads + fun extraRepository(id: String, url: String, type: String = "default") { + additionalRepositories.add(Triple(id, type, url)) + } - private fun postConstruct(directive: MuzzleDirective) { - // Make skipVersions case insensitive. - directive.skipVersions = directive.skipVersions.map { it.lowercase(Locale.ROOT) }.toMutableSet() - // Add existing repositories - directive.additionalRepositories.addAll(additionalRepositories) - } + private fun postConstruct(directive: MuzzleDirective) { + // Make skipVersions case insensitive. + directive.skipVersions = directive.skipVersions.map { it.lowercase(Locale.ROOT) }.toMutableSet() + // Add existing repositories + directive.additionalRepositories.addAll(additionalRepositories) + } } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtils.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtils.kt index 13e8752cb27..7f3c1ad1aa7 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtils.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleMavenRepoUtils.kt @@ -38,10 +38,11 @@ internal object MuzzleMavenRepoUtils { */ @JvmStatic fun newRepositorySystem(): RepositorySystem { - val locator = MavenRepositorySystemUtils.newServiceLocator().apply { - addService(RepositoryConnectorFactory::class.java, BasicRepositoryConnectorFactory::class.java) - addService(TransporterFactory::class.java, HttpTransporterFactory::class.java) - } + val locator = + MavenRepositorySystemUtils.newServiceLocator().apply { + addService(RepositoryConnectorFactory::class.java, BasicRepositoryConnectorFactory::class.java) + addService(TransporterFactory::class.java, HttpTransporterFactory::class.java) + } return locator.getService(RepositorySystem::class.java) } @@ -50,13 +51,15 @@ internal object MuzzleMavenRepoUtils { */ @JvmStatic fun newRepositorySystemSession(system: RepositorySystem): RepositorySystemSession { - val session = MavenRepositorySystemUtils.newSession().apply { - val tmpDir = Files.createTempDirectory("muzzle-generated-tmpdir-").toFile().apply { - deleteOnExit() + val session = + MavenRepositorySystemUtils.newSession().apply { + val tmpDir = + Files.createTempDirectory("muzzle-generated-tmpdir-").toFile().apply { + deleteOnExit() + } + val localRepo = LocalRepository(tmpDir) + localRepositoryManager = system.newLocalRepositoryManager(this, localRepo) } - val localRepo = LocalRepository(tmpDir) - localRepositoryManager = system.newLocalRepositoryManager(this, localRepo) - } return session } @@ -68,48 +71,53 @@ internal object MuzzleMavenRepoUtils { system: RepositorySystem, session: RepositorySystemSession ): Set { - val allVersionsArtifact = DefaultArtifact( - muzzleDirective.group, - muzzleDirective.module, - "jar", - "[,)" - ) + val allVersionsArtifact = + DefaultArtifact( + muzzleDirective.group, + muzzleDirective.module, + "jar", + "[,)" + ) val repos = muzzleDirective.getRepositories(MUZZLE_REPOS) - val allRangeRequest = VersionRangeRequest().apply { - repositories = repos - artifact = allVersionsArtifact - } + val allRangeRequest = + VersionRangeRequest().apply { + repositories = repos + artifact = allVersionsArtifact + } val allRangeResult = system.resolveVersionRange(session, allRangeRequest) - val directiveArtifact = DefaultArtifact( - muzzleDirective.group, - muzzleDirective.module, - "jar", - muzzleDirective.versions - ) - val rangeRequest = VersionRangeRequest().apply { - repositories = repos - artifact = directiveArtifact - } + val directiveArtifact = + DefaultArtifact( + muzzleDirective.group, + muzzleDirective.module, + "jar", + muzzleDirective.versions + ) + val rangeRequest = + VersionRangeRequest().apply { + repositories = repos + artifact = directiveArtifact + } val rangeResult = system.resolveVersionRange(session, rangeRequest) val rangeResultVersions = rangeResult.versions.toSet() allRangeResult.versions.removeAll(rangeResultVersions) - return MuzzleVersionUtils.filterAndLimitVersions( - allRangeResult, - muzzleDirective.skipVersions, - muzzleDirective.includeSnapshots - ).map { version -> - MuzzleDirective().apply { - name = muzzleDirective.name - group = muzzleDirective.group - module = muzzleDirective.module - versions = version.toString() - assertPass = !muzzleDirective.assertPass - excludedDependencies = muzzleDirective.excludedDependencies - includeSnapshots = muzzleDirective.includeSnapshots - } - }.toSet() + return MuzzleVersionUtils + .filterAndLimitVersions( + allRangeResult, + muzzleDirective.skipVersions, + muzzleDirective.includeSnapshots + ).map { version -> + MuzzleDirective().apply { + name = muzzleDirective.name + group = muzzleDirective.group + module = muzzleDirective.module + versions = version.toString() + assertPass = !muzzleDirective.assertPass + excludedDependencies = muzzleDirective.excludedDependencies + includeSnapshots = muzzleDirective.includeSnapshots + } + }.toSet() } /** @@ -121,17 +129,19 @@ internal object MuzzleMavenRepoUtils { system: RepositorySystem, session: RepositorySystemSession ): VersionRangeResult { - val directiveArtifact: Artifact = DefaultArtifact( - muzzleDirective.group, - muzzleDirective.module, - muzzleDirective.classifier ?: "", - "jar", - muzzleDirective.versions - ) - val rangeRequest = VersionRangeRequest().apply { - repositories = muzzleDirective.getRepositories(MUZZLE_REPOS) - artifact = directiveArtifact - } + val directiveArtifact: Artifact = + DefaultArtifact( + muzzleDirective.group, + muzzleDirective.module, + muzzleDirective.classifier ?: "", + "jar", + muzzleDirective.versions + ) + val rangeRequest = + VersionRangeRequest().apply { + repositories = muzzleDirective.getRepositories(MUZZLE_REPOS) + artifact = directiveArtifact + } // In rare cases, the version resolution range silently failed with the maven proxy, // retries 3 times at most then suggest to restart the job later. @@ -176,13 +186,14 @@ internal object MuzzleMavenRepoUtils { for (n in names) { val testedArtifact = TestedArtifact(n, directive.group ?: "", directive.module ?: "", lowVersion, highVersion) val value = ret[testedArtifact.key()] ?: testedArtifact - ret[testedArtifact.key()] = TestedArtifact( - value.instrumentation, - value.group, - value.module, - lowest(lowVersion, value.lowVersion), - highest(highVersion, value.highVersion) - ) + ret[testedArtifact.key()] = + TestedArtifact( + value.instrumentation, + value.group, + value.module, + lowest(lowVersion, value.lowVersion), + highest(highVersion, value.highVersion) + ) } return ret } @@ -205,20 +216,23 @@ internal object MuzzleMavenRepoUtils { muzzleDirective: MuzzleDirective, rangeResult: VersionRangeResult ): Set { - val versions = MuzzleVersionUtils.filterAndLimitVersions( - rangeResult, - muzzleDirective.skipVersions, - muzzleDirective.includeSnapshots - ) - val allVersionArtifacts = versions.map { version -> - DefaultArtifact( - muzzleDirective.group, - muzzleDirective.module, - muzzleDirective.classifier ?: "", - "jar", - version.toString() + val versions = + MuzzleVersionUtils.filterAndLimitVersions( + rangeResult, + muzzleDirective.skipVersions, + muzzleDirective.includeSnapshots ) - }.toSet() + val allVersionArtifacts = + versions + .map { version -> + DefaultArtifact( + muzzleDirective.group, + muzzleDirective.module, + muzzleDirective.classifier ?: "", + "jar", + version.toString() + ) + }.toSet() if (allVersionArtifacts.isEmpty()) { throw GradleException("No muzzle artifacts found for ${muzzleDirective.group}:${muzzleDirective.module} ${muzzleDirective.versions} ${muzzleDirective.classifier}") } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzlePlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzlePlugin.kt index b791f1f9a45..8167777a69d 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzlePlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzlePlugin.kt @@ -5,8 +5,8 @@ import datadog.gradle.plugin.muzzle.MuzzleMavenRepoUtils.muzzleDirectiveToArtifa import datadog.gradle.plugin.muzzle.MuzzleMavenRepoUtils.resolveVersionRange import datadog.gradle.plugin.muzzle.tasks.MuzzleEndTask import datadog.gradle.plugin.muzzle.tasks.MuzzleGenerateReportTask -import datadog.gradle.plugin.muzzle.tasks.MuzzleMergeReportsTask import datadog.gradle.plugin.muzzle.tasks.MuzzleGetReferencesTask +import datadog.gradle.plugin.muzzle.tasks.MuzzleMergeReportsTask import datadog.gradle.plugin.muzzle.tasks.MuzzleTask import org.eclipse.aether.artifact.Artifact import org.gradle.api.NamedDomainObjectProvider @@ -52,19 +52,21 @@ class MuzzlePlugin : Plugin { val bootstrapProject = ddJavaAgent["agent-bootstrap"] ?: error(":dd-java-agent:agent-bootstrap project not found") val toolingProject = ddJavaAgent["agent-tooling"] ?: error(":dd-java-agent:agent-tooling project not found") - val muzzleBootstrap = project.configurations.register("muzzleBootstrap") { - isCanBeConsumed = false - isCanBeResolved = true + val muzzleBootstrap = + project.configurations.register("muzzleBootstrap") { + isCanBeConsumed = false + isCanBeResolved = true - dependencies.add(project.dependencies.project(bootstrapProject.path)) - } + dependencies.add(project.dependencies.project(bootstrapProject.path)) + } - val muzzleTooling = project.configurations.register("muzzleTooling") { - isCanBeConsumed = false - isCanBeResolved = true + val muzzleTooling = + project.configurations.register("muzzleTooling") { + isCanBeConsumed = false + isCanBeResolved = true - dependencies.add(project.dependencies.project(toolingProject.path)) - } + dependencies.add(project.dependencies.project(toolingProject.path)) + } project.evaluationDependsOn(bootstrapProject.path) project.evaluationDependsOn(toolingProject.path) @@ -72,29 +74,40 @@ class MuzzlePlugin : Plugin { // compileMuzzle compiles all projects required to run muzzle validation. // Not adding group and description to keep this task from showing in `gradle tasks`. @Suppress("UNCHECKED_CAST") - val compileMuzzle = project.tasks.register("compileMuzzle") { - dependsOn(project.tasks.withType(Class.forName("InstrumentTask") as Class)) // kotlin can't see groovy code - dependsOn(bootstrapProject.tasks.named("compileJava")) - dependsOn(bootstrapProject.tasks.named("compileMain_java11Java")) - dependsOn(toolingProject.tasks.named("compileJava")) - } + val compileMuzzle = + project.tasks.register("compileMuzzle") { + dependsOn(project.tasks.withType(Class.forName("InstrumentTask") as Class)) // kotlin can't see groovy code + dependsOn(bootstrapProject.tasks.named("compileJava")) + dependsOn(bootstrapProject.tasks.named("compileMain_java11Java")) + dependsOn(toolingProject.tasks.named("compileJava")) + } - val muzzleTask = project.tasks.register("muzzle") { - this.muzzleBootstrap.set(muzzleBootstrap) - this.muzzleTooling.set(muzzleTooling) - dependsOn(compileMuzzle) - } + val muzzleTask = + project.tasks.register("muzzle") { + this.muzzleBootstrap.set(muzzleBootstrap) + this.muzzleTooling.set(muzzleTooling) + dependsOn(compileMuzzle) + } - project.tasks.register("printReferences") { - dependsOn(compileMuzzle) - }.also { - val printReferencesTask = project.tasks.register("actuallyPrintReferences") { - doLast { - println(it.get().outputFile.get().asFile.readText()) - } + project.tasks + .register("printReferences") { + dependsOn(compileMuzzle) + }.also { + val printReferencesTask = + project.tasks.register("actuallyPrintReferences") { + doLast { + println( + it + .get() + .outputFile + .get() + .asFile + .readText() + ) + } + } + it.configure { finalizedBy(printReferencesTask) } } - it.configure { finalizedBy(printReferencesTask) } - } project.tasks.register("generateMuzzleReport") { dependsOn(compileMuzzle) @@ -102,12 +115,13 @@ class MuzzlePlugin : Plugin { project.tasks.register("mergeMuzzleReports") - val hasRelevantTask = project.gradle.startParameter.taskNames.any { taskName -> - // removing leading ':' if present - val muzzleTaskName = taskName.removePrefix(":") - val projectPath = project.path.removePrefix(":") - muzzleTaskName == "muzzle" || "$projectPath:muzzle" == muzzleTaskName - } + val hasRelevantTask = + project.gradle.startParameter.taskNames.any { taskName -> + // removing leading ':' if present + val muzzleTaskName = taskName.removePrefix(":") + val projectPath = project.path.removePrefix(":") + muzzleTaskName == "muzzle" || "$projectPath:muzzle" == muzzleTaskName + } if (!hasRelevantTask) { // Adding muzzle dependencies has a large config overhead. Stop unless muzzle is explicitly run. return @@ -147,9 +161,10 @@ class MuzzlePlugin : Plugin { project.logger.info("configured $directive") } - val timingTask = project.tasks.register("muzzle-end") { - startTimeMs.set(startTime) - } + val timingTask = + project.tasks.register("muzzle-end") { + startTimeMs.set(startTime) + } // last muzzle task to run runAfter.configure { finalizedBy(timingTask) @@ -178,14 +193,16 @@ class MuzzlePlugin : Plugin { instrumentationProject: Project, runAfterTask: TaskProvider, muzzleBootstrap: NamedDomainObjectProvider, - muzzleTooling: NamedDomainObjectProvider + muzzleTooling: NamedDomainObjectProvider, ): TaskProvider { - val muzzleTaskName = buildString { - append("muzzle-Assert") - when { + val muzzleTaskName = + buildString { + append("muzzle-Assert") + when { muzzleDirective.isCoreJdk -> { append(muzzleDirective) } + else -> { append(if (muzzleDirective.assertPass) "Pass" else "Fail") append("-") @@ -196,53 +213,57 @@ class MuzzlePlugin : Plugin { append(versionArtifact?.version) append(if (muzzleDirective.name != null) "-${muzzleDirective.nameSlug}" else "") } + } } - } instrumentationProject.configurations.register(muzzleTaskName) { if (!muzzleDirective.isCoreJdk && versionArtifact != null) { - val depId = buildString { - append("${versionArtifact.groupId}:${versionArtifact.artifactId}:${versionArtifact.version}") + val depId = + buildString { + append("${versionArtifact.groupId}:${versionArtifact.artifactId}:${versionArtifact.version}") - versionArtifact.classifier?.let { - append(":") - append(it) + versionArtifact.classifier?.let { + append(":") + append(it) + } } - } - val dep = instrumentationProject.dependencies.create(depId) { - isTransitive = true + val dep = + instrumentationProject.dependencies.create(depId) { + isTransitive = true - // The following optional transitive dependencies are brought in by some legacy module such as log4j 1.x but are no - // longer bundled with the JVM and have to be excluded for the muzzle tests to be able to run. - exclude(group = "com.sun.jdmk", module = "jmxtools") - exclude(group = "com.sun.jmx", module = "jmxri") + // The following optional transitive dependencies are brought in by some legacy module such as log4j 1.x but are no + // longer bundled with the JVM and have to be excluded for the muzzle tests to be able to run. + exclude(group = "com.sun.jdmk", module = "jmxtools") + exclude(group = "com.sun.jmx", module = "jmxri") - // Also exclude specifically excluded dependencies - muzzleDirective.excludedDependencies.forEach { - val parts = it.split(":") - exclude(group = parts[0], module = parts[1]) + // Also exclude specifically excluded dependencies + muzzleDirective.excludedDependencies.forEach { + val parts = it.split(":") + exclude(group = parts[0], module = parts[1]) + } } - } dependencies.add(dep) } muzzleDirective.additionalDependencies.forEach { - val dep = instrumentationProject.dependencies.create(it) { - isTransitive = true - for (excluded in muzzleDirective.excludedDependencies) { - val parts = excluded.split(":") - exclude(group = parts[0], module = parts[1]) + val dep = + instrumentationProject.dependencies.create(it) { + isTransitive = true + for (excluded in muzzleDirective.excludedDependencies) { + val parts = excluded.split(":") + exclude(group = parts[0], module = parts[1]) + } } - } dependencies.add(dep) } } - val muzzleTask = instrumentationProject.tasks.register(muzzleTaskName) { - this.muzzleDirective.set(muzzleDirective) - this.muzzleBootstrap.set(muzzleBootstrap) - this.muzzleTooling.set(muzzleTooling) - } + val muzzleTask = + instrumentationProject.tasks.register(muzzleTaskName) { + this.muzzleDirective.set(muzzleDirective) + this.muzzleBootstrap.set(muzzleBootstrap) + this.muzzleTooling.set(muzzleTooling) + } runAfterTask.configure { finalizedBy(muzzleTask) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzlePluginUtils.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzlePluginUtils.kt index ebab06b441c..209ea105c4d 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzlePluginUtils.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzlePluginUtils.kt @@ -7,14 +7,19 @@ import org.gradle.api.tasks.SourceSetContainer import org.gradle.kotlin.dsl.findByType internal val Project.mainSourceSet: SourceSet - get() = extensions.findByType() - ?.named(MAIN_SOURCE_SET_NAME)?.get() - ?: error("sourceSets not found, it means that java plugin was not applied") + get() = + extensions + .findByType() + ?.named(MAIN_SOURCE_SET_NAME) + ?.get() + ?: error("sourceSets not found, it means that java plugin was not applied") internal val Project.allMainSourceSet: List - get() = extensions.findByType() - ?.filter { it.name.startsWith(MAIN_SOURCE_SET_NAME) } - .orEmpty() + get() = + extensions + .findByType() + ?.filter { it.name.startsWith(MAIN_SOURCE_SET_NAME) } + .orEmpty() internal val Project.pathSlug: String get() = path.removePrefix(":").replace(':', '_') diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleVersionUtils.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleVersionUtils.kt index b223f5c20ec..da076aeb2de 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleVersionUtils.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleVersionUtils.kt @@ -37,32 +37,33 @@ internal object MuzzleVersionUtils { list: Set, skipVersions: Set, includeSnapshots: Boolean - ): Set { - return list.filter { version -> + ): Set = list + .filter { version -> val v = version.toString().lowercase(Locale.ROOT) if (includeSnapshots) { !skipVersions.contains(v) } else { - !(v.endsWith("-snapshot") || - v.contains("rc") || - v.contains(".cr") || - v.contains("alpha") || - v.contains("beta") || - v.contains("-b") || - v.contains(".m") || - v.contains("-m") || - v.contains("-dev") || - v.contains("-ea") || - v.contains("-atlassian-") || - v.contains("public_draft") || - v.contains("-cr") || - v.contains("-preview") || - skipVersions.contains(v) || - END_NMN_PATTERN.matches(v) || - GIT_SHA_PATTERN.matches(v)) + !( + v.endsWith("-snapshot") || + v.contains("rc") || + v.contains(".cr") || + v.contains("alpha") || + v.contains("beta") || + v.contains("-b") || + v.contains(".m") || + v.contains("-m") || + v.contains("-dev") || + v.contains("-ea") || + v.contains("-atlassian-") || + v.contains("public_draft") || + v.contains("-cr") || + v.contains("-preview") || + skipVersions.contains(v) || + END_NMN_PATTERN.matches(v) || + GIT_SHA_PATTERN.matches(v) + ) } }.toSet() - } /** * Select a random set of versions to test @@ -84,9 +85,10 @@ internal object MuzzleVersionUtils { ): Set { if (versions.size <= 1) return versions val beforeSize = versions.size - val filteredVersions = versions.toMutableList().apply { - removeAll { skipVersions.contains(it.toString()) } - } + val filteredVersions = + versions.toMutableList().apply { + removeAll { skipVersions.contains(it.toString()) } + } val versionSet = VersionSet(filteredVersions) val shuffled = versionSet.lowAndHighForMajorMinor.shuffled().toMutableList() var afterSize = shuffled.size diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleWorkParameters.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleWorkParameters.kt index 5af13d9a10d..6bb2c031657 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleWorkParameters.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/MuzzleWorkParameters.kt @@ -6,13 +6,12 @@ import org.gradle.api.provider.Property import org.gradle.workers.WorkParameters interface MuzzleWorkParameters : WorkParameters { - val buildStartedTime: Property - val bootstrapClassPath: ConfigurableFileCollection - val toolingClassPath: ConfigurableFileCollection - val instrumentationClassPath: ConfigurableFileCollection - val testApplicationClassPath: ConfigurableFileCollection - val assertPass: Property - val muzzleDirective: Property - val resultFile: RegularFileProperty + val buildStartedTime: Property + val bootstrapClassPath: ConfigurableFileCollection + val toolingClassPath: ConfigurableFileCollection + val instrumentationClassPath: ConfigurableFileCollection + val testApplicationClassPath: ConfigurableFileCollection + val assertPass: Property + val muzzleDirective: Property + val resultFile: RegularFileProperty } - diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/TestedArtifact.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/TestedArtifact.kt index 81f6451d651..ac2a409b93e 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/TestedArtifact.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/TestedArtifact.kt @@ -4,11 +4,11 @@ import org.eclipse.aether.version.Version // Changed from internal to public for cross-file accessibility internal data class TestedArtifact( - val instrumentation: String, - val group: String, - val module: String, - val lowVersion: Version, - val highVersion: Version + val instrumentation: String, + val group: String, + val module: String, + val lowVersion: Version, + val highVersion: Version ) { - fun key(): String = "$instrumentation:$group:$module" + fun key(): String = "$instrumentation:$group:$module" } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/VersionSet.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/VersionSet.kt index 324c4e03e98..9148d2d4e86 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/VersionSet.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/VersionSet.kt @@ -4,11 +4,11 @@ import org.eclipse.aether.version.Version import java.util.SortedSet class VersionSet(versions: Collection) { - private val sortedVersions: SortedSet = sortedSetOf() + private val sortedVersions: SortedSet = sortedSetOf() - init { - versions.forEach { sortedVersions.add(ParsedVersion(it)) } - } + init { + versions.forEach { sortedVersions.add(ParsedVersion(it)) } + } val lowAndHighForMajorMinor: List get() { @@ -30,52 +30,55 @@ class VersionSet(versions: Collection) { return resultSet.map { it.version } } - internal class ParsedVersion(val version: Version) : Comparable { - companion object { - private val dotPattern = Regex("\\.") - private const val VERSION_SHIFT = 12 - } - val versionNumber: Long - val ending: String - init { - var versionString = version.toString() - var ending = "" - val dash = versionString.indexOf('-') - if (dash > 0) { - ending = versionString.substring(dash + 1) - versionString = versionString.substring(0, dash) - } - val groups = versionString.split(dotPattern).toMutableList() - var versionNumber = 0L - var iteration = 0 - while (iteration < 3) { - versionNumber = versionNumber shl VERSION_SHIFT - if (groups.isNotEmpty() && groups[0].toIntOrNull() != null) { - versionNumber += groups.removeAt(0).toLong() - } - iteration++ - } - if (groups.isNotEmpty()) { - val rest = groups.joinToString(".") - ending = if (ending.isEmpty()) rest else "$rest-$ending" - } - this.versionNumber = versionNumber - this.ending = ending - } - val majorMinor: Int - get() = (versionNumber shr VERSION_SHIFT).toInt() - override fun compareTo(other: ParsedVersion): Int { - val diff = versionNumber - other.versionNumber - return if (diff != 0L) diff.toInt() else ending.compareTo(other.ending) - } - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is ParsedVersion) return false - return versionNumber == other.versionNumber && ending == other.ending - } - override fun hashCode(): Int { - return (versionNumber * 31 + ending.hashCode()).toInt() + internal class ParsedVersion(val version: Version) : Comparable { + companion object { + private val dotPattern = Regex("\\.") + private const val VERSION_SHIFT = 12 + } + + val versionNumber: Long + val ending: String + + init { + var versionString = version.toString() + var ending = "" + val dash = versionString.indexOf('-') + if (dash > 0) { + ending = versionString.substring(dash + 1) + versionString = versionString.substring(0, dash) + } + val groups = versionString.split(dotPattern).toMutableList() + var versionNumber = 0L + var iteration = 0 + while (iteration < 3) { + versionNumber = versionNumber shl VERSION_SHIFT + if (groups.isNotEmpty() && groups[0].toIntOrNull() != null) { + versionNumber += groups.removeAt(0).toLong() } + iteration++ + } + if (groups.isNotEmpty()) { + val rest = groups.joinToString(".") + ending = if (ending.isEmpty()) rest else "$rest-$ending" + } + this.versionNumber = versionNumber + this.ending = ending } -} + val majorMinor: Int + get() = (versionNumber shr VERSION_SHIFT).toInt() + + override fun compareTo(other: ParsedVersion): Int { + val diff = versionNumber - other.versionNumber + return if (diff != 0L) diff.toInt() else ending.compareTo(other.ending) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is ParsedVersion) return false + return versionNumber == other.versionNumber && ending == other.ending + } + + override fun hashCode(): Int = (versionNumber * 31 + ending.hashCode()).toInt() + } +} diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/AbstractMuzzleReportTask.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/AbstractMuzzleReportTask.kt index 71001aa9747..b98c9783c95 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/AbstractMuzzleReportTask.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/AbstractMuzzleReportTask.kt @@ -9,10 +9,11 @@ import java.util.SortedMap abstract class AbstractMuzzleReportTask : AbstractMuzzleTask() { @get:OutputFile - val versionsFile: Provider = project.rootProject - .layout - .buildDirectory - .file("$MUZZLE_DEPS_RESULTS/${project.pathSlug}.csv") + val versionsFile: Provider = + project.rootProject + .layout + .buildDirectory + .file("$MUZZLE_DEPS_RESULTS/${project.pathSlug}.csv") internal fun dumpVersionsToCsv(versions: SortedMap) { with(project.file(versionsFile)) { diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleEndTask.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleEndTask.kt index daf0ce44b06..f0c90706743 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleEndTask.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleEndTask.kt @@ -11,10 +11,11 @@ abstract class MuzzleEndTask : AbstractMuzzleTask() { abstract val startTimeMs: Property @get:OutputFile - val resultsFile = project.rootProject - .layout - .buildDirectory - .file("${MUZZLE_TEST_RESULTS}/${project.pathSlug}_muzzle/results.xml") + val resultsFile = + project.rootProject + .layout + .buildDirectory + .file("${MUZZLE_TEST_RESULTS}/${project.pathSlug}_muzzle/results.xml") @TaskAction fun generatesResultFile() { diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleGenerateReportTask.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleGenerateReportTask.kt index f0aa1d381ae..1b6f3964a61 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleGenerateReportTask.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleGenerateReportTask.kt @@ -28,13 +28,14 @@ abstract class MuzzleGenerateReportTask : AbstractMuzzleReportTask() { lines.forEachIndexed { idx, line -> if (idx == 0) return@forEachIndexed // skip header val split = line.split(",") - val parsed = TestedArtifact( - split[0], - split[1], - split[2], - versionScheme.parseVersion(split[3]), - versionScheme.parseVersion(split[4]) - ) + val parsed = + TestedArtifact( + split[0], + split[1], + split[2], + versionScheme.parseVersion(split[3]), + versionScheme.parseVersion(split[4]) + ) map.merge(parsed.key(), parsed) { x, y -> TestedArtifact( x.instrumentation, diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleGetReferencesTask.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleGetReferencesTask.kt index af90609ff6d..652269530c0 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleGetReferencesTask.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleGetReferencesTask.kt @@ -18,9 +18,8 @@ import javax.inject.Inject @CacheableTask abstract class MuzzleGetReferencesTask @Inject constructor( providers: ProviderFactory, - objects: ObjectFactory, + objects: ObjectFactory ) : AbstractMuzzleTask() { - @get:Inject abstract val buildEventsListenerRegistry: BuildEventsListenerRegistry @@ -35,19 +34,22 @@ abstract class MuzzleGetReferencesTask @Inject constructor( // This output is only used to make the task cacheable, this is not exposed @get:OutputFile - val outputFile = objects.fileProperty().convention( - project.layout.buildDirectory.file("reports/references.txt") - ) + val outputFile = + objects.fileProperty().convention( + project.layout.buildDirectory.file("reports/references.txt") + ) @TaskAction fun printMuzzle() { val cl = URLClassLoader(classpath.get().map { it.toURI().toURL() }.toTypedArray(), null) - val printMethod: Method = cl.loadClass("datadog.trace.agent.tooling.muzzle.MuzzleVersionScanPlugin") - .getMethod( - "printMuzzleReferences", - ClassLoader::class.java, - PrintWriter::class.java, - ) + val printMethod: Method = + cl + .loadClass("datadog.trace.agent.tooling.muzzle.MuzzleVersionScanPlugin") + .getMethod( + "printMuzzleReferences", + ClassLoader::class.java, + PrintWriter::class.java, + ) val stringWriter = StringWriter() printMethod.invoke(null, cl, PrintWriter(stringWriter)) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleMergeReportsTask.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleMergeReportsTask.kt index d443caeae08..35a1fdf9322 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleMergeReportsTask.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleMergeReportsTask.kt @@ -26,7 +26,9 @@ abstract class MuzzleMergeReportsTask : AbstractMuzzleReportTask() { val system: RepositorySystem = MuzzleMavenRepoUtils.newRepositorySystem() val session: RepositorySystemSession = MuzzleMavenRepoUtils.newRepositorySystemSession(system) val versions = TreeMap() - project.extensions.getByType().directives + project.extensions + .getByType() + .directives .filter { !it.isCoreJdk && !it.skipFromReport } .forEach { directive -> val range = MuzzleMavenRepoUtils.resolveVersionRange(directive, system, session) @@ -35,13 +37,19 @@ abstract class MuzzleMergeReportsTask : AbstractMuzzleReportTask() { val partials = resolveInstrumentationAndJarVersions(directive, cl, range.lowestVersion, range.highestVersion) partials.forEach { (key, value) -> - versions.merge(key, value, BiFunction { x, y -> - TestedArtifact( - x.instrumentation, x.group, x.module, - lowest(x.lowVersion, y.lowVersion), - highest(x.highVersion, y.highVersion) - ) - }) + versions.merge( + key, + value, + BiFunction { x, y -> + TestedArtifact( + x.instrumentation, + x.group, + x.module, + lowest(x.lowVersion, y.lowVersion), + highest(x.highVersion, y.highVersion) + ) + } + ) } } dumpVersionsToCsv(versions) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleTask.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleTask.kt index cefba57e610..1ddc3b21077 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleTask.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/muzzle/tasks/MuzzleTask.kt @@ -31,12 +31,10 @@ abstract class MuzzleTask @Inject constructor( objects: ObjectFactory, providers: ProviderFactory, ) : AbstractMuzzleTask() { - override fun getDescription(): String { - return if (muzzleDirective.isPresent) { - "Run instrumentation muzzle on ${muzzleDirective.get().name} dependency" - } else { - "Run instrumentation muzzle on compile time dependencies" - } + override fun getDescription(): String = if (muzzleDirective.isPresent) { + "Run instrumentation muzzle on ${muzzleDirective.get().name} dependency" + } else { + "Run instrumentation muzzle on compile time dependencies" } @get:Inject @@ -71,41 +69,47 @@ abstract class MuzzleTask @Inject constructor( // This output is only used to make the task cacheable, this is not exposed @get:OutputFile @get:Optional - protected val result: RegularFileProperty = objects.fileProperty().convention( - project.layout.buildDirectory.file("reports/${name}.txt") - ) + protected val result: RegularFileProperty = objects.fileProperty() + .convention(project.layout.buildDirectory.file("reports/$name.txt")) @TaskAction fun muzzle() { when { - !project.extensions.getByType().directives.any { it.assertPass } -> { - project.logger.info("No muzzle pass directives configured. Asserting pass against instrumentation compile-time dependencies") - assertMuzzle() - } - muzzleDirective.isPresent -> { - assertMuzzle(muzzleDirective.get()) - } + !project.extensions + .getByType() + .directives + .any { it.assertPass } -> { + project.logger.info("No muzzle pass directives configured. Asserting pass against instrumentation compile-time dependencies") + assertMuzzle() + } + + muzzleDirective.isPresent -> { + assertMuzzle(muzzleDirective.get()) + } } } private fun assertMuzzle(muzzleDirective: MuzzleDirective? = null) { - val workQueue = if (muzzleDirective?.javaVersion != null) { - val javaLauncher = javaToolchainService.launcherFor { - languageVersion.set(JavaLanguageVersion.of(muzzleDirective.javaVersion!!)) - }.get() - // Note process isolation leaks gradle dependencies to the child process - // and may need additional code on muzzle plugin to filter those out - // See https://github.com/gradle/gradle/issues/33987 - workerExecutor.processIsolation { - forkOptions { - executable(javaLauncher.executablePath) + val workQueue = + if (muzzleDirective?.javaVersion != null) { + val javaLauncher = + javaToolchainService + .launcherFor { + languageVersion.set(JavaLanguageVersion.of(muzzleDirective.javaVersion!!)) + }.get() + // Note process isolation leaks gradle dependencies to the child process + // and may need additional code on muzzle plugin to filter those out + // See https://github.com/gradle/gradle/issues/33987 + workerExecutor.processIsolation { + forkOptions { + executable(javaLauncher.executablePath) + } } + } else { + // noIsolation worker is OK for muzzle tasks as their checks will inspect classes outline + // and should not be impacted by the actual running JDK. + workerExecutor.noIsolation() } - } else { - // noIsolation worker is OK for muzzle tasks as their checks will inspect classes outline - // and should not be impacted by the actual running JDK. - workerExecutor.noIsolation() - } workQueue.submit(MuzzleAction::class.java) { buildStartedTime.set(invocationDetails.buildStartedTime) bootstrapClassPath.setFrom(muzzleBootstrap) @@ -136,11 +140,12 @@ abstract class MuzzleTask @Inject constructor( private fun createMuzzleClassPath(project: Project, muzzleTaskName: String): FileCollection { project.logger.info("Creating muzzle classpath for $muzzleTaskName") val cp = project.files() - val config = if (muzzleTaskName == "muzzle") { - project.configurations.named("compileClasspath").get() - } else { - project.configurations.named(muzzleTaskName).get() - } + val config = + if (muzzleTaskName == "muzzle") { + project.configurations.named("compileClasspath").get() + } else { + project.configurations.named(muzzleTaskName).get() + } cp.from(config) if (project.logger.isInfoEnabled) { cp.forEach { project.logger.info("-- $it") } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/ProvideJvmArgsOnJvmLauncherVersion.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/ProvideJvmArgsOnJvmLauncherVersion.kt index 52443474337..469774dee44 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/ProvideJvmArgsOnJvmLauncherVersion.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/ProvideJvmArgsOnJvmLauncherVersion.kt @@ -11,23 +11,20 @@ import org.gradle.process.CommandLineArgumentProvider class ProvideJvmArgsOnJvmLauncherVersion( @get:Internal val test: Test, - @get:Input val applyFromVersion: JavaVersion, - @get:Input val jvmArgsToApply: List, - @get:Input @get:Optional val additionalCondition: Provider ) : CommandLineArgumentProvider { - override fun asArguments(): Iterable { - val launcherVersion = test.javaLauncher - .map { JavaVersion.toVersion(it.metadata.languageVersion.asInt()) } - .orElse(JavaVersion.current()) - .get() + val launcherVersion = + test.javaLauncher + .map { JavaVersion.toVersion(it.metadata.languageVersion.asInt()) } + .orElse(JavaVersion.current()) + .get() return if (launcherVersion.isCompatibleWith(applyFromVersion) && additionalCondition.getOrElse(true)) { jvmArgsToApply diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsUtils.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsUtils.kt index 7df6a10d6ea..f8e70ed186b 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsUtils.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsUtils.kt @@ -5,9 +5,7 @@ import org.gradle.api.logging.Logging private val logger = Logging.getLogger("TestJvmConstraintsUtils") -internal fun TestJvmConstraintsExtension.isJavaVersionAllowed(version: JavaVersion): Boolean { - return withinAllowedRange(version) -} +internal fun TestJvmConstraintsExtension.isJavaVersionAllowed(version: JavaVersion): Boolean = withinAllowedRange(version) internal fun TestJvmConstraintsExtension.isTestJvmAllowed(testJvmSpec: TestJvmSpec): Boolean { val testJvmName = testJvmSpec.normalizedTestJvm.get() diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmSpec.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmSpec.kt index 9ce4b533a54..e4376c8afce 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmSpec.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmSpec.kt @@ -46,30 +46,40 @@ class TestJvmSpec(val project: Project) { /** * Normalized `stable` string to the highest JAVA_X_HOME found in environment variables. */ - val normalizedTestJvm: Provider = testJvmProperty.map { testJvm -> - if (testJvm.isBlank()) { - throw GradleException("testJvm property is blank") - } - - // "stable" is calculated as the largest X found in JAVA_X_HOME - when (testJvm) { - "stable" -> { - val javaVersions = project.providers.environmentVariablesPrefixedBy("JAVA_").map { javaHomes -> - javaHomes - .filter { it.key.matches(Regex("^JAVA_[0-9]+_HOME$")) && it.key != "JAVA_26_HOME" } // JDK 26 is EA - .map { Regex("^JAVA_(\\d+)_HOME$").find(it.key)!!.groupValues[1].toInt() } - }.get() - - if (javaVersions.isEmpty()) { - throw GradleException("No valid JAVA_X_HOME environment variables found.") + val normalizedTestJvm: Provider = + testJvmProperty + .map { testJvm -> + if (testJvm.isBlank()) { + throw GradleException("testJvm property is blank") } - javaVersions.max().toString() - } + // "stable" is calculated as the largest X found in JAVA_X_HOME + when (testJvm) { + "stable" -> { + val javaVersions = + project.providers + .environmentVariablesPrefixedBy("JAVA_") + .map { javaHomes -> + javaHomes + .filter { it.key.matches(Regex("^JAVA_[0-9]+_HOME$")) && it.key != "JAVA_26_HOME" } // JDK 26 is EA + .map { Regex("^JAVA_(\\d+)_HOME$").find(it.key)!!.groupValues[1].toInt() } + }.get() + + if (javaVersions.isEmpty()) { + throw GradleException("No valid JAVA_X_HOME environment variables found.") + } - else -> testJvm - } - }.map { project.logger.info("normalized testJvm: $it"); it } + javaVersions.max().toString() + } + + else -> { + testJvm + } + } + }.map { + project.logger.info("normalized testJvm: $it") + it + } /** * The home path of the test JVM. @@ -80,80 +90,96 @@ class TestJvmSpec(val project: Project) { * * Holds the resolved JavaToolchainSpec for the test JVM. */ - private val testJvmSpec = normalizedTestJvm.map { - val (distribution, version) = Regex("([a-zA-Z]*)([0-9]+)").matchEntire(it)?.groupValues?.drop(1) ?: listOf("", "") - - when { - Files.exists(Paths.get(it)) -> it.normalizeToJDKJavaHome().toToolchainSpec() - - version.isNotBlank() -> { - // Best effort to make a spec for the passed testJvm - // `8`, `11`, `ZULU8`, `GRAALVM25`, etc. - // if it is an integer, we assume it's a Java version - // also we can handle on macOs oracle, zulu, semeru, graalvm prefixes - - // This is using internal APIs - DefaultToolchainSpec(project.serviceOf()).apply { - languageVersion.set(JavaLanguageVersion.of(version.toInt())) - when (distribution.lowercase()) { - "oracle" -> { - vendor.set(JvmVendorSpec.ORACLE) - } - - "zulu" -> { - vendor.set(JvmVendorSpec.AZUL) - } + private val testJvmSpec = + normalizedTestJvm + .map { + val (distribution, version) = Regex("([a-zA-Z]*)([0-9]+)").matchEntire(it)?.groupValues?.drop(1) ?: listOf("", "") + + when { + Files.exists(Paths.get(it)) -> { + it.normalizeToJDKJavaHome().toToolchainSpec() + } - "semeru" -> { - vendor.set(JvmVendorSpec.IBM) - implementation.set(JvmImplementation.J9) + version.isNotBlank() -> { + // Best effort to make a spec for the passed testJvm + // `8`, `11`, `ZULU8`, `GRAALVM25`, etc. + // if it is an integer, we assume it's a Java version + // also we can handle on macOs oracle, zulu, semeru, graalvm prefixes + + // This is using internal APIs + DefaultToolchainSpec(project.serviceOf()).apply { + languageVersion.set(JavaLanguageVersion.of(version.toInt())) + when (distribution.lowercase()) { + "oracle" -> { + vendor.set(JvmVendorSpec.ORACLE) + } + + "zulu" -> { + vendor.set(JvmVendorSpec.AZUL) + } + + "semeru" -> { + vendor.set(JvmVendorSpec.IBM) + implementation.set(JvmImplementation.J9) + } + + "graalvm" -> { + vendor.set(JvmVendorSpec.GRAAL_VM) + nativeImageCapable.set(true) + } + } } + } - "graalvm" -> { - vendor.set(JvmVendorSpec.GRAAL_VM) - nativeImageCapable.set(true) - } + else -> { + throw GradleException( + """ + Unable to find launcher for Java '$it'. It needs to be: + 1. A valid path to a JDK home, or + 2. An environment variable named 'JAVA__HOME' or '' pointing to a JDK home, or + 3. A Java version or a known distribution+version combination (e.g. '11', 'zulu8', 'graalvm11', etc.) that can be resolved via Gradle toolchains. + 4. If using Gradle toolchains, ensure that the requested JDK is installed and configured correctly. + """.trimIndent() + ) } } + }.map { + project.logger.info("testJvm home path: $it") + it } - else -> throw GradleException( - """ - Unable to find launcher for Java '$it'. It needs to be: - 1. A valid path to a JDK home, or - 2. An environment variable named 'JAVA__HOME' or '' pointing to a JDK home, or - 3. A Java version or a known distribution+version combination (e.g. '11', 'zulu8', 'graalvm11', etc.) that can be resolved via Gradle toolchains. - 4. If using Gradle toolchains, ensure that the requested JDK is installed and configured correctly. - """.trimIndent() - ) - } - }.map { project.logger.info("testJvm home path: $it"); it } - /** * The Java launcher for the test JVM. * * Current JVM or a launcher specified via the testJvm. */ val javaTestLauncher: Provider = - project.providers.zip(testJvmSpec, normalizedTestJvm) { jvmSpec, testJvm -> - // Only change test JVM if it's not the one we are running the gradle build with - if ((jvmSpec as? SpecificInstallationToolchainSpec)?.javaHome == currentJavaHomePath.get()) { - project.providers.provider { null } - } else { - // The provider always says that a value is present so we need to wrap it for proper error messages - project.javaToolchains.launcherFor(jvmSpec).orElse(project.providers.provider { - throw GradleException("Unable to find launcher for Java '$testJvm'. Does $TEST_JVM point to a JDK?") - }) + project.providers + .zip(testJvmSpec, normalizedTestJvm) { jvmSpec, testJvm -> + // Only change test JVM if it's not the one we are running the gradle build with + if ((jvmSpec as? SpecificInstallationToolchainSpec)?.javaHome == currentJavaHomePath.get()) { + project.providers.provider { null } + } else { + // The provider always says that a value is present so we need to wrap it for proper error messages + project.javaToolchains.launcherFor(jvmSpec).orElse( + project.providers.provider { + throw GradleException("Unable to find launcher for Java '$testJvm'. Does $TEST_JVM point to a JDK?") + } + ) + } + } + .flatMap { it } + .map { + project.logger.info("testJvm launcher: ${it.executablePath}") + it } - }.flatMap { it }.map { project.logger.info("testJvm launcher: ${it.executablePath}"); it } private fun String.normalizeToJDKJavaHome(): Path { val javaHome = project.file(this).toPath().toRealPath() return if (javaHome.endsWith("jre")) javaHome.parent else javaHome } - private fun Path.toToolchainSpec(): JavaToolchainSpec = - // This is using internal APIs + private fun Path.toToolchainSpec(): JavaToolchainSpec = // This is using internal APIs SpecificInstallationToolchainSpec(project.serviceOf(), project.file(this)) private val Project.javaToolchains: JavaToolchainService diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/GitCommandValueSource.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/GitCommandValueSource.kt index dd60de6f162..75d97dc1d81 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/GitCommandValueSource.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/GitCommandValueSource.kt @@ -18,27 +18,31 @@ abstract class GitCommandValueSource @Inject constructor( val commands = parameters.gitCommand.get() val outputStream = ByteArrayOutputStream() - val result = try { - execOperations.exec { - commandLine(commands) - workingDir(workDir) - standardOutput = outputStream - errorOutput = outputStream - isIgnoreExitValue = true + val result = + try { + execOperations.exec { + commandLine(commands) + workingDir(workDir) + standardOutput = outputStream + errorOutput = outputStream + isIgnoreExitValue = true + } + } catch (e: Exception) { + throw GradleException("Failed to run: ${commands.joinToString(" ")}", e) } - } catch (e: Exception) { - throw GradleException("Failed to run: ${commands.joinToString(" ")}", e) - } val output = outputStream.toString(Charset.defaultCharset().name()).trim() when { result.exitValue == 128 && - (output.startsWith("fatal: not a git repository") - || output.startsWith("fatal: No names found, cannot describe anything.")) - -> { + ( + output.startsWith("fatal: not a git repository") || + output.startsWith("fatal: No names found, cannot describe anything.") + ) + -> { // Behaves as if not a git repo return "" } + result.exitValue != 0 -> { throw GradleException( """ @@ -46,7 +50,7 @@ abstract class GitCommandValueSource @Inject constructor( (exit code: ${result.exitValue}) Output: $output - """.trimIndent() + """.trimIndent() ) } } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt index 4e94c873457..cf30f3fc36c 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/version/TracerVersionPlugin.kt @@ -11,7 +11,7 @@ import java.io.File import javax.inject.Inject class TracerVersionPlugin @Inject constructor( - private val providerFactory: ProviderFactory, + private val providerFactory: ProviderFactory ) : Plugin { private val logger = Logging.getLogger(TracerVersionPlugin::class.java) @@ -23,9 +23,10 @@ class TracerVersionPlugin @Inject constructor( val extension = targetProject.extensions.getByType(TracerVersionExtension::class.java) extension.detectDirty.set( - providerFactory.gradleProperty("tracerVersion.dirtiness") - .map { it.trim().toBoolean() } - .orElse(false) + providerFactory + .gradleProperty("tracerVersion.dirtiness") + .map { it.trim().toBoolean() } + .orElse(false) ) val versionProvider = versionProvider(targetProject, extension) @@ -40,36 +41,37 @@ class TracerVersionPlugin @Inject constructor( ): String { val repoWorkingDirectory = targetProject.rootDir - val buildVersion: String = if (!repoWorkingDirectory.resolve(".git").exists()) { - // Not a git repository - extension.defaultVersion.get() - } else { - providerFactory.zip( - gitDescribeProvider(extension, repoWorkingDirectory), - gitCurrentBranchProvider(repoWorkingDirectory) - ) { describeString, currentBranch -> - toTracerVersion(describeString, extension) { - when { - currentBranch.startsWith("release/v") -> { - logger.info("Incrementing patch because release branch : $currentBranch") - nextPatchVersion() - } - else -> { - logger.info("Incrementing minor") - nextMinorVersion() + val buildVersion: String = + if (!repoWorkingDirectory.resolve(".git").exists()) { + // Not a git repository + extension.defaultVersion.get() + } else { + providerFactory + .zip( + gitDescribeProvider(extension, repoWorkingDirectory), + gitCurrentBranchProvider(repoWorkingDirectory) + ) { describeString, currentBranch -> + toTracerVersion(describeString, extension) { + when { + currentBranch.startsWith("release/v") -> { + logger.info("Incrementing patch because release branch : $currentBranch") + nextPatchVersion() + } + + else -> { + logger.info("Incrementing minor") + nextMinorVersion() + } + } } - } - } - }.get() - } + }.get() + } logger.lifecycle("Tracer build version: {}", buildVersion) return buildVersion } - private fun gitCurrentBranchProvider( - repoWorkingDirectory: File - ) = providerFactory.of(GitCommandValueSource::class.java) { + private fun gitCurrentBranchProvider(repoWorkingDirectory: File) = providerFactory.of(GitCommandValueSource::class.java) { parameters { gitCommand.addAll( "git", @@ -109,18 +111,20 @@ class TracerVersionPlugin @Inject constructor( val tagPrefix = extension.tagVersionPrefix.get() val tagRegex = Regex("$tagPrefix(\\d+\\.\\d+\\.\\d+)(.*)") - val matchResult = tagRegex.find(describeString) - ?: return extension.defaultVersion.get() + val matchResult = + tagRegex.find(describeString) + ?: return extension.defaultVersion.get() val (lastTagVersion, describeTrailer) = matchResult.destructured val hasLaterCommits = describeTrailer.isNotBlank() - val version = Version.parse(lastTagVersion).let { - if (hasLaterCommits) { - it.nextVersion() - } else { - it + val version = + Version.parse(lastTagVersion).let { + if (hasLaterCommits) { + it.nextVersion() + } else { + it + } } - } return buildString { append(version.toString()) @@ -136,12 +140,21 @@ class TracerVersionPlugin @Inject constructor( } open class TracerVersionExtension @Inject constructor(objectFactory: ObjectFactory) { - val defaultVersion = objectFactory.property(String::class) - .convention("0.1.0-SNAPSHOT") - val tagVersionPrefix = objectFactory.property(String::class) - .convention("v") - val useSnapshot = objectFactory.property(Boolean::class) - .convention(true) + val defaultVersion = + objectFactory + .property(String::class) + .convention("0.1.0-SNAPSHOT") + + val tagVersionPrefix = + objectFactory + .property(String::class) + .convention("v") + + val useSnapshot = + objectFactory + .property(Boolean::class) + .convention(true) + val detectDirty = objectFactory.property(Boolean::class) } } diff --git a/buildSrc/src/main/kotlin/dd-trace-java.ci-jobs.gradle.kts b/buildSrc/src/main/kotlin/dd-trace-java.ci-jobs.gradle.kts index a4d871d9e15..12e7d6d9c9c 100644 --- a/buildSrc/src/main/kotlin/dd-trace-java.ci-jobs.gradle.kts +++ b/buildSrc/src/main/kotlin/dd-trace-java.ci-jobs.gradle.kts @@ -11,7 +11,7 @@ import kotlin.math.abs // Set up activePartition property on all projects allprojects { extra.set("activePartition", true) - + val taskPartitionCountProvider = rootProject.providers.gradleProperty("taskPartitionCount") val taskPartitionProvider = rootProject.providers.gradleProperty("taskPartition") if (taskPartitionCountProvider.isPresent && taskPartitionProvider.isPresent) { @@ -20,20 +20,22 @@ allprojects { val currentTaskPartition = abs(project.path.hashCode() % taskPartitionCount.toInt()) extra.set("activePartition", currentTaskPartition == taskPartition.toInt()) } - + // Disable test tasks if not in active partition - val activePartitionProvider = providers.provider { - project.extra.properties["activePartition"] as? Boolean ?: true - } - + val activePartitionProvider = + providers.provider { + project.extra.properties["activePartition"] as? Boolean ?: true + } + tasks.withType().configureEach { enabled = activePartitionProvider.get() } } -fun relativeToGitRoot(f: File): File { - return rootProject.projectDir.toPath().relativize(f.absoluteFile.toPath()).toFile() -} +fun relativeToGitRoot(f: File): File = rootProject.projectDir + .toPath() + .relativize(f.absoluteFile.toPath()) + .toFile() fun getChangedFiles(baseRef: String, newRef: String): List { val stdout = StringBuilder() @@ -60,19 +62,24 @@ rootProject.extra.set("useGitChanges", false) val gitBaseRefProvider = rootProject.providers.gradleProperty("gitBaseRef") if (gitBaseRefProvider.isPresent) { val baseRef = gitBaseRefProvider.get() - val newRef = rootProject.providers.gradleProperty("gitNewRef").orElse("HEAD").get() - + val newRef = + rootProject.providers + .gradleProperty("gitNewRef") + .orElse("HEAD") + .get() + val changedFiles = getChangedFiles(baseRef, newRef) rootProject.extra.set("changedFiles", changedFiles) rootProject.extra.set("useGitChanges", true) - - val ignoredFiles = fileTree(rootProject.projectDir) { - include(".gitignore", ".editorconfig") - include("*.md", "**/*.md") - include("gradlew", "gradlew.bat", "mvnw", "mvnw.cmd") - include("NOTICE") - include("static-analysis.datadog.yml") - } + + val ignoredFiles = + fileTree(rootProject.projectDir) { + include(".gitignore", ".editorconfig") + include("*.md", "**/*.md") + include("gradlew", "gradlew.bat", "mvnw", "mvnw.cmd") + include("NOTICE") + include("static-analysis.datadog.yml") + } changedFiles.forEach { f -> if (ignoredFiles.contains(f)) { @@ -82,13 +89,14 @@ if (gitBaseRefProvider.isPresent) { val filteredChangedFiles = changedFiles.filter { !ignoredFiles.contains(it) } rootProject.extra.set("changedFiles", filteredChangedFiles) - - val globalEffectFiles = fileTree(rootProject.projectDir) { - include(".gitlab/**") - include("build.gradle") - include("gradle/**") - } - + + val globalEffectFiles = + fileTree(rootProject.projectDir) { + include(".gitlab/**") + include("build.gradle") + include("gradle/**") + } + for (f in filteredChangedFiles) { if (globalEffectFiles.contains(f)) { logger.warn("Global effect change: ${relativeToGitRoot(f)} (no tasks will be skipped)") @@ -96,20 +104,21 @@ if (gitBaseRefProvider.isPresent) { break } } - + if (rootProject.extra.get("useGitChanges") as Boolean) { logger.warn("Git change tracking is enabled: $baseRef..$newRef") - + val projects = subprojects.sortedByDescending { it.projectDir.path.length } val affectedProjects = mutableMapOf>() // Path prefixes mapped to affected task names. A file not matching any of these prefixes will affect all tasks in // the project ("all" can be used a task name to explicitly state the same). Only the first matching prefix is used. - val matchers = listOf( - mapOf("prefix" to "src/testFixtures/", "task" to "testFixturesClasses"), - mapOf("prefix" to "src/test/", "task" to "testClasses"), - mapOf("prefix" to "src/jmh/", "task" to "jmhCompileGeneratedClasses") - ) + val matchers = + listOf( + mapOf("prefix" to "src/testFixtures/", "task" to "testFixturesClasses"), + mapOf("prefix" to "src/test/", "task" to "testClasses"), + mapOf("prefix" to "src/jmh/", "task" to "jmhCompileGeneratedClasses") + ) for (f in filteredChangedFiles) { val p = projects.find { f.toString().startsWith(it.projectDir.path + "/") } @@ -120,20 +129,25 @@ if (gitBaseRefProvider.isPresent) { } // Make sure path separator is / - val relPath = p.projectDir.toPath().relativize(f.toPath()).joinToString("/") + val relPath = + p.projectDir + .toPath() + .relativize(f.toPath()) + .joinToString("/") val task = matchers.find { relPath.startsWith(it["prefix"]!!) }?.get("task") ?: "all" logger.warn("Changed file: ${relativeToGitRoot(f)} in project ${p.path} ($task)") affectedProjects.computeIfAbsent(p) { mutableSetOf() }.add(task) } - + rootProject.extra.set("affectedProjects", affectedProjects) } } tasks.register("runMuzzle") { - val muzzleSubprojects = subprojects.filter { p -> - val activePartition = p.extra.get("activePartition") as Boolean - activePartition && p.plugins.hasPlugin("java") && p.plugins.hasPlugin("dd-trace-java.muzzle") - } + val muzzleSubprojects = + subprojects.filter { p -> + val activePartition = p.extra.get("activePartition") as Boolean + activePartition && p.plugins.hasPlugin("java") && p.plugins.hasPlugin("dd-trace-java.muzzle") + } dependsOn(muzzleSubprojects.map { p -> "${p.path}:muzzle" }) } diff --git a/buildSrc/src/main/kotlin/dd-trace-java.configure-tests.gradle.kts b/buildSrc/src/main/kotlin/dd-trace-java.configure-tests.gradle.kts index d0060bbf278..e86868807b4 100644 --- a/buildSrc/src/main/kotlin/dd-trace-java.configure-tests.gradle.kts +++ b/buildSrc/src/main/kotlin/dd-trace-java.configure-tests.gradle.kts @@ -1,12 +1,12 @@ -import org.gradle.api.tasks.testing.Test -import org.gradle.api.tasks.testing.junitplatform.JUnitPlatformOptions +import org.gradle.api.plugins.jvm.JvmTestSuite import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters -import org.gradle.testing.base.TestingExtension -import org.gradle.api.plugins.jvm.JvmTestSuite +import org.gradle.api.tasks.testing.Test +import org.gradle.api.tasks.testing.junitplatform.JUnitPlatformOptions import org.gradle.kotlin.dsl.develocity import org.gradle.kotlin.dsl.findByType import org.gradle.kotlin.dsl.withType +import org.gradle.testing.base.TestingExtension import java.time.Duration import java.time.temporal.ChronoUnit @@ -15,9 +15,10 @@ abstract class ForkedTestLimit : BuildService // Forked tests will fail with OOM if the memory is set too high. Gitlab allows at least a limit of 3. val forkedTestsMemoryLimit = 3 -val forkedTestLimit = gradle.sharedServices.registerIfAbsent("forkedTestLimit", ForkedTestLimit::class.java) { - maxParallelUsages.set(forkedTestsMemoryLimit) -} +val forkedTestLimit = + gradle.sharedServices.registerIfAbsent("forkedTestLimit", ForkedTestLimit::class.java) { + maxParallelUsages.set(forkedTestsMemoryLimit) + } extensions.findByType()?.apply { suites.withType().configureEach { @@ -61,17 +62,21 @@ tasks.withType().configureEach { // Register a task "allTests" that depends on all non-latest and non-traceAgentTest Test tasks. // This is used when we only want to run the 'main' test sets. tasks.register("allTests") { - dependsOn(tasks.withType().matching { testTask -> - !testTask.name.contains("latest", ignoreCase = true) && testTask.name != "traceAgentTest" - }) + dependsOn( + tasks.withType().matching { testTask -> + !testTask.name.contains("latest", ignoreCase = true) && testTask.name != "traceAgentTest" + } + ) } // Register a task "allLatestDepTests" that depends on all Test tasks whose names include 'latest'. // This is used when we want to run tests against the latest dependency versions. tasks.register("allLatestDepTests") { - dependsOn(tasks.withType().matching { testTask -> - !testTask.name.contains("latest", ignoreCase = true) - }) + dependsOn( + tasks.withType().matching { testTask -> + !testTask.name.contains("latest", ignoreCase = true) + } + ) } // Make the 'check' task depend on all Test tasks in the project. diff --git a/buildSrc/src/main/kotlin/dd-trace-java.dependency-locking.gradle.kts b/buildSrc/src/main/kotlin/dd-trace-java.dependency-locking.gradle.kts index 3435f9e5925..52c990f0f66 100644 --- a/buildSrc/src/main/kotlin/dd-trace-java.dependency-locking.gradle.kts +++ b/buildSrc/src/main/kotlin/dd-trace-java.dependency-locking.gradle.kts @@ -12,9 +12,9 @@ project.dependencyLocking { lockAllConfigurations() - //lockmode set to LENIENT because there are resolution - //errors in the build with an apiguardian dependency. - //See: https://docs.gradle.org/current/userguide/dependency_locking.html for more info + // lockmode set to LENIENT because there are resolution + // errors in the build with an apiguardian dependency. + // See: https://docs.gradle.org/current/userguide/dependency_locking.html for more info lockMode = LockMode.LENIENT } @@ -24,11 +24,12 @@ tasks.register("resolveAndLockAll") { require(gradle.startParameter.isWriteDependencyLocks) } doLast { - configurations.filter { - // Add any custom filtering on the configurations to be resolved: - // - Should be resolvable - // - Should skip Scala related task (https://github.com/ben-manes/gradle-versions-plugin/issues/816#issuecomment-1872264880) - it.isCanBeResolved && !it.name.startsWith("incrementalScalaAnalysis") - }.forEach { it.resolve() } + configurations + .filter { + // Add any custom filtering on the configurations to be resolved: + // - Should be resolvable + // - Should skip Scala related task (https://github.com/ben-manes/gradle-versions-plugin/issues/816#issuecomment-1872264880) + it.isCanBeResolved && !it.name.startsWith("incrementalScalaAnalysis") + }.forEach { it.resolve() } } } diff --git a/buildSrc/src/main/kotlin/dd-trace-java.gradle-debug.gradle.kts b/buildSrc/src/main/kotlin/dd-trace-java.gradle-debug.gradle.kts index 38f9fac7411..9938befa780 100644 --- a/buildSrc/src/main/kotlin/dd-trace-java.gradle-debug.gradle.kts +++ b/buildSrc/src/main/kotlin/dd-trace-java.gradle-debug.gradle.kts @@ -9,18 +9,19 @@ fun inferJdkFromJavaHome(javaHome: String?): String { val effectiveJavaHome = javaHome ?: providers.environmentVariable("JAVA_HOME").orNull ?: error("JAVA_HOME is not set") val javaExecutable = File(effectiveJavaHome, "bin/java").absolutePath return try { - val process = ProcessBuilder(javaExecutable, "-version") + val process = + ProcessBuilder(javaExecutable, "-version") .redirectErrorStream(true) .start() val output = process.inputStream.bufferedReader().readText() val versionLine = output.lines().firstOrNull() ?: "" val versionMatch = Regex("version\\s+\"([0-9._]+)\"").find(versionLine) versionMatch?.let { - val version = it.groupValues[1] - when { - version.startsWith("1.") -> version.substring(2, 3) - else -> version.split('.').first() - } + val version = it.groupValues[1] + when { + version.startsWith("1.") -> version.substring(2, 3) + else -> version.split('.').first() + } } ?: "unknown" } catch (e: Exception) { "error: ${e.message}" @@ -41,7 +42,7 @@ fun getJdkFromCompilerOptions(co: CompileOptions): String? { fun printJdkForProjectTasks(project: Project, logFile: File) { project.tasks.forEach { task -> val data = mutableMapOf() - data["task"] = task.path.toString() + data["task"] = task.path if (task is JavaExec) { val launcher = task.javaLauncher.get() data["jdk"] = launcher.metadata.languageVersion.toString() @@ -52,8 +53,8 @@ fun printJdkForProjectTasks(project: Project, logFile: File) { val launcher = task.javaLauncher.get() data["jdk"] = launcher.metadata.languageVersion.toString() } else if (task is Exec) { - val java_home = task.environment.get("JAVA_HOME")?.toString() - data["jdk"] = inferJdkFromJavaHome(java_home) + val javaHome = task.environment["JAVA_HOME"]?.toString() + data["jdk"] = inferJdkFromJavaHome(javaHome) } else if (task is JavaCompile) { val compiler = task.javaCompiler.get() data["jdk"] = compiler.metadata.languageVersion.toString() @@ -83,18 +84,19 @@ fun printJdkForProjectTasks(project: Project, logFile: File) { } } -class DebugBuildListener : org.gradle.BuildListener { +class DebugBuildListener : BuildListener { override fun settingsEvaluated(settings: Settings) = Unit override fun projectsLoaded(gradle: Gradle) = Unit + @Deprecated("Deprecated in BuildListener") override fun buildFinished(result: BuildResult) = Unit override fun projectsEvaluated(gradle: Gradle) { val logFile = logPath.get().asFile logFile.writeText("") gradle.rootProject.allprojects.forEach { project -> - printJdkForProjectTasks(project, logFile) + printJdkForProjectTasks(project, logFile) } } } diff --git a/buildSrc/src/main/kotlin/dd-trace-java.test-jvm-contraints.gradle.kts b/buildSrc/src/main/kotlin/dd-trace-java.test-jvm-contraints.gradle.kts index aa4724183b0..ecba08ca5a1 100644 --- a/buildSrc/src/main/kotlin/dd-trace-java.test-jvm-contraints.gradle.kts +++ b/buildSrc/src/main/kotlin/dd-trace-java.test-jvm-contraints.gradle.kts @@ -20,9 +20,10 @@ tasks.withType().configureEach { inputs.property("testJvm", testJvmSpec.testJvmProperty).optional(true) - val taskExtension = project.objects.newInstance().also { - configureConventions(it, projectExtension) - } + val taskExtension = + project.objects.newInstance().also { + configureConventions(it, projectExtension) + } inputs.property("$TEST_JVM_CONSTRAINTS.allowReflectiveAccessToJdk", taskExtension.allowReflectiveAccessToJdk).optional(true) inputs.property("$TEST_JVM_CONSTRAINTS.excludeJdk", taskExtension.excludeJdk) @@ -102,27 +103,36 @@ private fun Test.configureConventions( taskExtension: TestJvmConstraintsExtension, projectExtension: TestJvmConstraintsExtension ) { - taskExtension.minJavaVersion.convention(projectExtension.minJavaVersion - .orElse(providers.provider { project.findProperty("${name}MinJavaVersionForTests") as? JavaVersion }) - .orElse(providers.provider { project.findProperty("minJavaVersion") as? JavaVersion }) + taskExtension.minJavaVersion.convention( + projectExtension.minJavaVersion + .orElse(providers.provider { project.findProperty("${name}MinJavaVersionForTests") as? JavaVersion }) + .orElse(providers.provider { project.findProperty("minJavaVersion") as? JavaVersion }) ) - taskExtension.maxJavaVersion.convention(projectExtension.maxJavaVersion - .orElse(providers.provider { project.findProperty("${name}MaxJavaVersionForTests") as? JavaVersion }) - .orElse(providers.provider { project.findProperty("maxJavaVersion") as? JavaVersion }) + taskExtension.maxJavaVersion.convention( + projectExtension.maxJavaVersion + .orElse(providers.provider { project.findProperty("${name}MaxJavaVersionForTests") as? JavaVersion }) + .orElse(providers.provider { project.findProperty("maxJavaVersion") as? JavaVersion }) ) - taskExtension.forceJdk.convention(projectExtension.forceJdk - .orElse(providers.provider { - @Suppress("UNCHECKED_CAST") - project.findProperty("forceJdk") as? List ?: emptyList() - }) + taskExtension.forceJdk.convention( + projectExtension.forceJdk + .orElse( + providers.provider { + @Suppress("UNCHECKED_CAST") + project.findProperty("forceJdk") as? List ?: emptyList() + } + ) ) - taskExtension.excludeJdk.convention(projectExtension.excludeJdk - .orElse(providers.provider { - @Suppress("UNCHECKED_CAST") - project.findProperty("excludeJdk") as? List ?: emptyList() - }) + taskExtension.excludeJdk.convention( + projectExtension.excludeJdk + .orElse( + providers.provider { + @Suppress("UNCHECKED_CAST") + project.findProperty("excludeJdk") as? List ?: emptyList() + } + ) ) - taskExtension.allowReflectiveAccessToJdk.convention(projectExtension.allowReflectiveAccessToJdk - .orElse(providers.provider { project.findProperty("allowReflectiveAccessToJdk") as? Boolean }) + taskExtension.allowReflectiveAccessToJdk.convention( + projectExtension.allowReflectiveAccessToJdk + .orElse(providers.provider { project.findProperty("allowReflectiveAccessToJdk") as? Boolean }) ) } diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPluginTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPluginTest.kt index 9b544a96530..cdac51111e7 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPluginTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPluginTest.kt @@ -12,7 +12,8 @@ import java.io.File import java.nio.file.Files class CallSiteInstrumentationPluginTest { - private val buildGradle = """ + private val buildGradle = + """ plugins { id 'java' id 'dd-trace-java.call-site-instrumentation' @@ -26,16 +27,16 @@ class CallSiteInstrumentationPluginTest { targetFolder = project.layout.buildDirectory.dir('csi') rootFolder = file('__ROOT_FOLDER__') } - + repositories { mavenCentral() } - + dependencies { implementation group: 'net.bytebuddy', name: 'byte-buddy', version: '1.18.1' implementation group: 'com.google.auto.service', name: 'auto-service-annotations', version: '1.1.1' } - """.trimIndent() + """.trimIndent() @TempDir lateinit var buildDir: File @@ -43,16 +44,17 @@ class CallSiteInstrumentationPluginTest { @Test fun `test call site instrumentation plugin`() { createGradleProject( - buildDir, buildGradle, + buildDir, + buildGradle, """ - import datadog.trace.agent.tooling.csi.*; - - @CallSite(spi = CallSites.class) - public class BeforeAdviceCallSite { - @CallSite.Before("java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)") - public static void beforeAppend(@CallSite.This final StringBuilder self, @CallSite.Argument final String param) { - } - } + import datadog.trace.agent.tooling.csi.*; + + @CallSite(spi = CallSites.class) + public class BeforeAdviceCallSite { + @CallSite.Before("java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)") + public static void beforeAppend(@CallSite.This final StringBuilder self, @CallSite.Argument final String param) { + } + } """.trimIndent() ) @@ -69,22 +71,24 @@ class CallSiteInstrumentationPluginTest { @Test fun `test call site instrumentation plugin with error`() { createGradleProject( - buildDir, buildGradle, + buildDir, + buildGradle, """ - import datadog.trace.agent.tooling.csi.*; - - @CallSite(spi = CallSites.class) - public class BeforeAdviceCallSite { - @CallSite.Before("java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)") - private void beforeAppend(@CallSite.This final StringBuilder self, @CallSite.Argument final String param) { - } - } + import datadog.trace.agent.tooling.csi.*; + + @CallSite(spi = CallSites.class) + public class BeforeAdviceCallSite { + @CallSite.Before("java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String)") + private void beforeAppend(@CallSite.This final StringBuilder self, @CallSite.Argument final String param) { + } + } """.trimIndent() ) - val error = assertThrows(UnexpectedBuildFailure::class.java) { - buildGradleProject(buildDir) - } + val error = + assertThrows(UnexpectedBuildFailure::class.java) { + buildGradleProject(buildDir) + } val generated = resolve(buildDir, "build", "csi", "BeforeAdviceCallSites.java") assertFalse(generated.exists()) @@ -96,7 +100,8 @@ class CallSiteInstrumentationPluginTest { private fun createGradleProject(buildDir: File, gradleFile: String, advice: String) { val projectFolder = File(System.getProperty("user.dir")).parentFile - val callSiteJar = resolve(projectFolder, "buildSrc", "call-site-instrumentation-plugin", "build", "libs", "call-site-instrumentation-plugin-all.jar") + val callSiteJar = + resolve(projectFolder, "buildSrc", "call-site-instrumentation-plugin", "build", "libs", "call-site-instrumentation-plugin-all.jar") val testCallSiteJarDir = resolve(buildDir, "buildSrc", "call-site-instrumentation-plugin", "build", "libs", makeDirs = true) Files.copy( @@ -113,23 +118,23 @@ class CallSiteInstrumentationPluginTest { val adviceFolder = resolve(javaFolder, *advicePackage.split("\\.").toTypedArray(), makeDirs = true) writeText(resolve(adviceFolder, "$adviceClassName.java"), advice) - val csiSource = resolve(projectFolder, "dd-java-agent", "agent-tooling", "src", "main", "java", "datadog", "trace", "agent", "tooling", "csi") + val csiSource = + resolve(projectFolder, "dd-java-agent", "agent-tooling", "src", "main", "java", "datadog", "trace", "agent", "tooling", "csi") val csiTarget = resolve(javaFolder, "datadog", "trace", "agent", "tooling", "csi", makeDirs = true) csiSource.listFiles()?.forEach { writeText(File(csiTarget, it.name), it.readText()) } } - private fun buildGradleProject(buildDir: File): BuildResult { - return GradleRunner.create() - .withTestKitDir(File(buildDir, ".gradle-test-kit")) // workaround in case the global test-kit cache becomes corrupted - .withDebug(true) // avoids starting daemon which can leave undeleted files post-cleanup - .withProjectDir(buildDir) - .withArguments("build", "--info", "--stacktrace") - .withPluginClasspath() - .forwardOutput() - .build() - } + private fun buildGradleProject(buildDir: File): BuildResult = GradleRunner + .create() + .withTestKitDir(File(buildDir, ".gradle-test-kit")) // workaround in case the global test-kit cache becomes corrupted + .withDebug(true) // avoids starting daemon which can leave undeleted files post-cleanup + .withProjectDir(buildDir) + .withArguments("build", "--info", "--stacktrace") + .withPluginClasspath() + .forwardOutput() + .build() private fun parsePackage(advice: String): String { val regex = Regex("package\\s+([\\w.]+)\\s*;", RegexOption.DOT_MATCHES_ALL) @@ -143,11 +148,9 @@ class CallSiteInstrumentationPluginTest { return match?.groupValues?.getOrNull(1) ?: "" } - private fun resolve(parent: File, vararg path: String, makeDirs: Boolean = false): File { - return path.fold(parent) { acc, next -> File(acc, next) }.apply { - if (makeDirs) { - mkdirs() - } + private fun resolve(parent: File, vararg path: String, makeDirs: Boolean = false): File = path.fold(parent) { acc, next -> File(acc, next) }.apply { + if (makeDirs) { + mkdirs() } } diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/dump/DumpHangedTestIntegrationTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/dump/DumpHangedTestIntegrationTest.kt index d0a8279c85d..1d748a25fcc 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/dump/DumpHangedTestIntegrationTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/dump/DumpHangedTestIntegrationTest.kt @@ -98,12 +98,14 @@ class DumpHangedTestIntegrationTest { ) try { - val buildResult = GradleRunner.create() - .forwardOutput() - .withPluginClasspath() - .withArguments("test") - .withProjectDir(projectDir) - .build() + val buildResult = + GradleRunner + .create() + .forwardOutput() + .withPluginClasspath() + .withArguments("test") + .withProjectDir(projectDir) + .build() return buildResult.output.lines() } catch (e: UnexpectedBuildFailure) { diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/instrument/InstrumentPluginTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/instrument/InstrumentPluginTest.kt index 49ee5bc26f6..9cf3b81490e 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/instrument/InstrumentPluginTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/instrument/InstrumentPluginTest.kt @@ -12,8 +12,8 @@ import java.io.File import java.io.FileInputStream class InstrumentPluginTest { - - private val buildGradle = """ + private val buildGradle = + """ plugins { id 'java' id 'dd-trace-java.instrument' @@ -39,9 +39,10 @@ class InstrumentPluginTest { instrument.plugins = [ 'TestPlugin' ] - """.trimIndent() + """.trimIndent() - private val testPlugin = """ + private val testPlugin = + """ import java.io.File; import java.io.IOException; import net.bytebuddy.build.Plugin; @@ -74,12 +75,13 @@ class InstrumentPluginTest { // no-op } } - """.trimIndent() + """.trimIndent() - private val exampleCode = """ + private val exampleCode = + """ package example; public class ExampleCode {} - """.trimIndent() + """.trimIndent() @TempDir lateinit var buildDir: File @@ -96,13 +98,16 @@ class InstrumentPluginTest { File(examplePackageDir, "ExampleCode.java").writeText(exampleCode) // Run Gradle build with TestKit - val result = GradleRunner.create().withTestKitDir(File(buildDir, ".gradle-test-kit")) // workaround in case the global test-kit cache becomes corrupted - .withDebug(true) // avoids starting daemon which can leave undeleted files post-cleanup - .withProjectDir(buildDir) - .withArguments("build", "--stacktrace") - .withPluginClasspath() - .forwardOutput() - .build() + val result = + GradleRunner + .create() + .withTestKitDir(File(buildDir, ".gradle-test-kit")) // workaround in case the global test-kit cache becomes corrupted + .withDebug(true) // avoids starting daemon which can leave undeleted files post-cleanup + .withProjectDir(buildDir) + .withArguments("build", "--stacktrace") + .withPluginClasspath() + .forwardOutput() + .build() val classFile = File(buildDir, "build/classes/java/main/example/ExampleCode.class") assertTrue(classFile.isFile) @@ -112,7 +117,13 @@ class InstrumentPluginTest { val classReader = ClassReader(input) classReader.accept( object : ClassVisitor(OpenedClassReader.ASM_API) { - override fun visitField(access: Int, fieldName: String?, descriptor: String?, signature: String?, value: Any?): FieldVisitor? { + override fun visitField( + access: Int, + fieldName: String?, + descriptor: String?, + signature: String?, + value: Any? + ): FieldVisitor? { if ("__TEST__FIELD__" == fieldName) { foundInsertedField = true } diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/RangeQueryTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/RangeQueryTest.kt index 6c1623f62ef..2ef95e72003 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/RangeQueryTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/RangeQueryTest.kt @@ -14,10 +14,11 @@ class RangeQueryTest { fun `test range request`() { // compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.5.0', ext: 'pom' val directiveArtifact: Artifact = DefaultArtifact("org.codehaus.groovy", "groovy-all", "jar", "[2.5.0,2.5.8)") - val rangeRequest = VersionRangeRequest().apply { - repositories = MuzzleMavenRepoUtils.MUZZLE_REPOS - artifact = directiveArtifact - } + val rangeRequest = + VersionRangeRequest().apply { + repositories = MuzzleMavenRepoUtils.MUZZLE_REPOS + artifact = directiveArtifact + } // This call makes an actual network request, which may fail if network access is limited. val rangeResult = system.resolveVersionRange(session, rangeRequest) diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/VersionSetTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/VersionSetTest.kt index b632ee81e38..6a44b13897c 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/VersionSetTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/muzzle/VersionSetTest.kt @@ -5,7 +5,6 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test class VersionSetTest { - @Test fun `parse versions properly`() { data class Case( @@ -14,15 +13,16 @@ class VersionSetTest { val ending: String ) - val cases = listOf( - Case(ver("1.2.3"), num(1, 2, 3), ""), - Case(ver("4.5.6-foo"), num(4, 5, 6), "foo"), - Case(ver("7.8.9.foo"), num(7, 8, 9), "foo"), - Case(ver("10.11.12.foo-bar"), num(10, 11, 12), "foo-bar"), - Case(ver("13.14.foo-bar"), num(13, 14, 0), "foo-bar"), - Case(ver("15.foo"), num(15, 0, 0), "foo"), - Case(ver("16-foo"), num(16, 0, 0), "foo") - ) + val cases = + listOf( + Case(ver("1.2.3"), num(1, 2, 3), ""), + Case(ver("4.5.6-foo"), num(4, 5, 6), "foo"), + Case(ver("7.8.9.foo"), num(7, 8, 9), "foo"), + Case(ver("10.11.12.foo-bar"), num(10, 11, 12), "foo-bar"), + Case(ver("13.14.foo-bar"), num(13, 14, 0), "foo-bar"), + Case(ver("15.foo"), num(15, 0, 0), "foo"), + Case(ver("16-foo"), num(16, 0, 0), "foo") + ) for (c in cases) { val parsed = VersionSet.ParsedVersion(c.version) @@ -38,36 +38,38 @@ class VersionSetTest { @Test fun `select low and high from major minor`() { - val versionsCases = listOf( + val versionsCases = listOf( - ver("4.5.6"), - ver("1.2.3") - ), - listOf( - ver("1.2.3"), - ver("1.2.1"), - ver("1.3.0"), - ver("1.2.7"), - ver("1.4.17"), - ver("1.4.1"), - ver("1.4.0"), - ver("1.4.10") + listOf( + ver("4.5.6"), + ver("1.2.3") + ), + listOf( + ver("1.2.3"), + ver("1.2.1"), + ver("1.3.0"), + ver("1.2.7"), + ver("1.4.17"), + ver("1.4.1"), + ver("1.4.0"), + ver("1.4.10") + ) ) - ) - val expectedCases = listOf( + val expectedCases = listOf( - ver("1.2.3"), - ver("4.5.6") - ), - listOf( - ver("1.2.1"), - ver("1.2.7"), - ver("1.3.0"), - ver("1.4.0"), - ver("1.4.17") + listOf( + ver("1.2.3"), + ver("4.5.6") + ), + listOf( + ver("1.2.1"), + ver("1.2.7"), + ver("1.3.0"), + ver("1.4.0"), + ver("1.4.17") + ) ) - ) versionsCases.zip(expectedCases).forEach { (versions, expected) -> val versionSet = VersionSet(versions) @@ -92,8 +94,7 @@ class VersionSetTest { return 1 } - override fun equals(other: Any?): Boolean = - other is TestVersion && v == other.v + override fun equals(other: Any?): Boolean = other is TestVersion && v == other.v override fun hashCode(): Int = v.hashCode() diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt index 0726fb0b82d..d5c8f0f0b14 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/version/TracerVersionIntegrationTest.kt @@ -8,7 +8,6 @@ import java.io.File import java.io.IOException class TracerVersionIntegrationTest { - @Test fun `should use default version when not under a git clone`(@TempDir projectDir: File) { assertTracerVersion(projectDir, "0.1.0-SNAPSHOT") @@ -41,10 +40,12 @@ class TracerVersionIntegrationTest { exec(projectDir, "git", "add", "-A") exec(projectDir, "git", "commit", "-m", "A commit") - File(projectDir, "settings.gradle.kts").appendText(""" + File(projectDir, "settings.gradle.kts").appendText( + """ // uncommitted change this file, - """.trimIndent()) + """.trimIndent(), + ) } ) } @@ -101,10 +102,12 @@ class TracerVersionIntegrationTest { exec(projectDir, "git", "commit", "-m", "A commit") exec(projectDir, "git", "tag", "v1.52.0", "-m", "") - File(projectDir, "settings.gradle.kts").appendText(""" + File(projectDir, "settings.gradle.kts").appendText( + """ // uncommitted change this file, - """.trimIndent()) + """.trimIndent() + ) } ) } @@ -126,7 +129,7 @@ class TracerVersionIntegrationTest { """ // Committed change this file, - """.trimIndent() + """.trimIndent() ) exec(projectDir, "git", "commit", "-am", "Another commit") } @@ -153,16 +156,20 @@ class TracerVersionIntegrationTest { exec(projectDir, "git", "tag", "v1.52.0", "-m", "") val settingsFile = File(projectDir, "settings.gradle.kts") - settingsFile.appendText(""" + settingsFile.appendText( + """ // uncommitted change - """.trimIndent()) + """.trimIndent() + ) exec(projectDir, "git", "commit", "-am", "Another commit") - settingsFile.appendText(""" + settingsFile.appendText( + """ // An uncommitted modification - """.trimIndent()) + """.trimIndent() + ) } ) } @@ -181,10 +188,12 @@ class TracerVersionIntegrationTest { exec(projectDir, "git", "tag", "v1.52.0", "-m", "") val settingsFile = File(projectDir, "settings.gradle.kts") - settingsFile.appendText(""" + settingsFile.appendText( + """ // Committed change - """.trimIndent()) + """.trimIndent() + ) exec(projectDir, "git", "commit", "-am", "Another commit") exec(projectDir, "git", "switch", "-c", "release/v1.52.x") @@ -207,17 +216,21 @@ class TracerVersionIntegrationTest { exec(projectDir, "git", "switch", "-c", "release/v1.52.x") val settingsFile = File(projectDir, "settings.gradle.kts") - settingsFile.appendText(""" + settingsFile.appendText( + """ // Committed change - """.trimIndent()) + """.trimIndent() + ) exec(projectDir, "git", "commit", "-am", "Another commit") exec(projectDir, "git", "tag", "v1.52.1", "-m", "") - settingsFile.appendText(""" + settingsFile.appendText( + """ // Another committed change - """.trimIndent()) + """.trimIndent() + ) exec(projectDir, "git", "commit", "-am", "Another commit") } ) @@ -243,7 +256,7 @@ class TracerVersionIntegrationTest { """ // Committed change this file, - """.trimIndent() + """.trimIndent() ) exec(workTreeDir, "git", "commit", "-am", "Another commit") }, @@ -278,25 +291,28 @@ class TracerVersionIntegrationTest { beforeGradle() - val buildResult = GradleRunner.create() - .forwardOutput() - // .withGradleVersion(gradleVersion) // Use current gradle version - .withPluginClasspath() - .withArguments("printVersion", "--quiet") - .withProjectDir(workingDirectory) - // .withDebug(true) - .build() + val buildResult = + GradleRunner + .create() + .forwardOutput() + // .withGradleVersion(gradleVersion) // Use current gradle version + .withPluginClasspath() + .withArguments("printVersion", "--quiet") + .withProjectDir(workingDirectory) + // .withDebug(true) + .build() assertEquals(expectedVersion, buildResult.output.lines().first()) } private fun exec(workingDirectory: File, vararg args: String) { - val exitCode = ProcessBuilder() - .command(*args) - .directory(workingDirectory) - .inheritIO() - .start() - .waitFor() + val exitCode = + ProcessBuilder() + .command(*args) + .directory(workingDirectory) + .inheritIO() + .start() + .waitFor() if (exitCode != 0) { throw IOException(String.format("Process failed: %s Exit code %d", args.joinToString(" "), exitCode))