From 2c4d71d39dd9c14a63839d083e355d57dc3bec4c Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Tue, 5 Aug 2025 18:04:54 +0200 Subject: [PATCH 1/2] chore: Configure lazily MuzzlePlugin --- buildSrc/src/main/groovy/MuzzlePlugin.groovy | 160 ++++++++++--------- 1 file changed, 81 insertions(+), 79 deletions(-) diff --git a/buildSrc/src/main/groovy/MuzzlePlugin.groovy b/buildSrc/src/main/groovy/MuzzlePlugin.groovy index bd37653f056..2a3dbc1cb48 100644 --- a/buildSrc/src/main/groovy/MuzzlePlugin.groovy +++ b/buildSrc/src/main/groovy/MuzzlePlugin.groovy @@ -1,5 +1,3 @@ -import static MuzzleAction.createClassLoader - import org.apache.maven.repository.internal.MavenRepositorySystemUtils import org.eclipse.aether.DefaultRepositorySystemSession import org.eclipse.aether.RepositorySystem @@ -17,12 +15,7 @@ import org.eclipse.aether.spi.connector.transport.TransporterFactory import org.eclipse.aether.transport.http.HttpTransporterFactory import org.eclipse.aether.util.version.GenericVersionScheme import org.eclipse.aether.version.Version -import org.gradle.api.Action -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.Task +import org.gradle.api.* import org.gradle.api.artifacts.Configuration import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.FileCollection @@ -30,6 +23,7 @@ import org.gradle.api.invocation.BuildInvocationDetails import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.TaskProvider import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.workers.WorkAction @@ -93,36 +87,31 @@ class MuzzlePlugin implements Plugin { def toolingProject = childProjects.get('agent-tooling') project.extensions.create("muzzle", MuzzleExtension, project.objects) - def muzzleBootstrap = project.configurations.create('muzzleBootstrap', { + def muzzleBootstrap = project.configurations.register('muzzleBootstrap', { canBeConsumed: false canBeResolved: true }) - def muzzleTooling = project.configurations.create('muzzleTooling', { + def muzzleTooling = project.configurations.register('muzzleTooling', { canBeConsumed: false canBeResolved: true }) - project.dependencies.add('muzzleBootstrap', bootstrapProject) - project.dependencies.add('muzzleTooling', toolingProject) + + project.dependencies.add(muzzleBootstrap.name, bootstrapProject) + project.dependencies.add(muzzleTooling.name, toolingProject) project.evaluationDependsOn ':dd-java-agent:agent-bootstrap' project.evaluationDependsOn ':dd-java-agent:agent-tooling' // compileMuzzle compiles all projects required to run muzzle validation. // Not adding group and description to keep this task from showing in `gradle tasks`. - def compileMuzzle = project.task('compileMuzzle') - compileMuzzle.dependsOn(toolingProject.tasks.named("compileJava")) - project.afterEvaluate { - project.tasks.matching { - it.name =~ /\Ainstrument(Main)?(_.+)?(Java|Scala|Kotlin)/ - }.all { - compileMuzzle.dependsOn(it) - } + TaskProvider compileMuzzle = project.tasks.register('compileMuzzle') { + it.dependsOn(project.tasks.withType(InstrumentTask)) + it.dependsOn bootstrapProject.tasks.named("compileJava") + it.dependsOn bootstrapProject.tasks.named("compileMain_java11Java") + it.dependsOn toolingProject.tasks.named("compileJava") } - compileMuzzle.dependsOn bootstrapProject.tasks.compileJava - compileMuzzle.dependsOn bootstrapProject.tasks.compileMain_java11Java - compileMuzzle.dependsOn toolingProject.tasks.compileJava - project.task(['type': MuzzleTask], 'muzzle') { + def muzzleTask = project.tasks.register('muzzle', MuzzleTask) { description = "Run instrumentation muzzle on compile time dependencies" doLast { if (!project.muzzle.directives.any { it.assertPass }) { @@ -133,14 +122,15 @@ class MuzzlePlugin implements Plugin { dependsOn compileMuzzle } - project.task(['type': MuzzleTask], 'printReferences') { + project.tasks.register('printReferences', MuzzleTask) { description = "Print references created by instrumentation muzzle" doLast { printMuzzle(project) } dependsOn compileMuzzle } - project.task(['type': MuzzleTask], 'generateMuzzleReport') { + + project.tasks.register('generateMuzzleReport', MuzzleTask) { description = "Print instrumentation version report" doLast { dumpVersionRanges(project) @@ -148,8 +138,7 @@ class MuzzlePlugin implements Plugin { dependsOn compileMuzzle } - - project.task(['type': MuzzleTask], 'mergeMuzzleReports') { + project.tasks.register('mergeMuzzleReports', MuzzleTask) { description = "Merge generated version reports in one unique csv" doLast { mergeReports(project) @@ -174,35 +163,37 @@ class MuzzlePlugin implements Plugin { final RepositorySystemSession session = newRepositorySystemSession(system) project.afterEvaluate { // use runAfter to set up task finalizers in version order - Task runAfter = project.tasks.muzzle - // runLast is the last task to finish, so we can time the execution - Task runLast = runAfter + TaskProvider runAfter = muzzleTask for (MuzzleDirective muzzleDirective : project.muzzle.directives) { project.getLogger().info("configured $muzzleDirective") if (muzzleDirective.coreJdk) { - runLast = runAfter = addMuzzleTask(muzzleDirective, null, project, runAfter, muzzleBootstrap, muzzleTooling) + runAfter = addMuzzleTask(muzzleDirective, null, project, runAfter, muzzleBootstrap, muzzleTooling) } else { def range = resolveVersionRange(muzzleDirective, system, session) - runLast = muzzleDirectiveToArtifacts(muzzleDirective, range).inject(runLast) { last, Artifact singleVersion -> + for (Artifact singleVersion : muzzleDirectiveToArtifacts(muzzleDirective, range)) { runAfter = addMuzzleTask(muzzleDirective, singleVersion, project, runAfter, muzzleBootstrap, muzzleTooling) } if (muzzleDirective.assertInverse) { - runLast = inverseOf(muzzleDirective, system, session).inject(runLast) { last1, MuzzleDirective inverseDirective -> - muzzleDirectiveToArtifacts(inverseDirective, resolveVersionRange(inverseDirective, system, session)).inject(last1) { last2, Artifact singleVersion -> + for (MuzzleDirective inverseDirective : inverseOf(muzzleDirective, system, session)) { + def inverseRange = resolveVersionRange(inverseDirective, system, session) + for (Artifact singleVersion : (muzzleDirectiveToArtifacts(inverseDirective, inverseRange))) { runAfter = addMuzzleTask(inverseDirective, singleVersion, project, runAfter, muzzleBootstrap, muzzleTooling) } } } } } - def timingTask = project.task("muzzle-end") { + def timingTask = project.tasks.register("muzzle-end") { doLast { long endTime = System.currentTimeMillis() generateResultsXML(project, endTime - startTime) } } - runLast.finalizedBy(timingTask) + // last muzzle task to run + runAfter.configure { + finalizedBy(timingTask) + } } } @@ -236,7 +227,7 @@ class MuzzlePlugin implements Plugin { Map map = new TreeMap<>() def versionScheme = new GenericVersionScheme() dir.eachFileMatch(~/.*\.csv/) { file -> - file.eachLine { line, nb -> + file.eachLine { line, nb -> if (nb == 1) { // skip header return @@ -318,9 +309,9 @@ class MuzzlePlugin implements Plugin { FileCollection cp = project.files() project.getLogger().info("Creating muzzle classpath for $muzzleTaskName") if ('muzzle' == muzzleTaskName) { - cp += project.configurations.compileClasspath + cp += project.configurations.named("compileClasspath").get() } else { - cp += project.configurations.getByName(muzzleTaskName) + cp += project.configurations.named(muzzleTaskName).get() } if (project.getLogger().isInfoEnabled()) { cp.forEach { project.getLogger().info("-- $it") } @@ -431,52 +422,61 @@ class MuzzlePlugin implements Plugin { * * @return The created muzzle task. */ - private static Task addMuzzleTask(MuzzleDirective muzzleDirective, Artifact versionArtifact, Project instrumentationProject, Task runAfter, Configuration muzzleBootstrap, Configuration muzzleTooling) { - def taskName + private static TaskProvider addMuzzleTask( + MuzzleDirective muzzleDirective, + Artifact versionArtifact, + Project instrumentationProject, + TaskProvider runAfter, + NamedDomainObjectProvider muzzleBootstrap, + NamedDomainObjectProvider muzzleTooling + ) { + def muzzleTaskName if (muzzleDirective.coreJdk) { - taskName = "muzzle-Assert$muzzleDirective" + muzzleTaskName = "muzzle-Assert$muzzleDirective" } else { - taskName = "muzzle-Assert${muzzleDirective.assertPass ? "Pass" : "Fail"}-$versionArtifact.groupId-$versionArtifact.artifactId-$versionArtifact.version${muzzleDirective.name ? "-${muzzleDirective.getNameSlug()}" : ""}" - } - def config = instrumentationProject.configurations.create(taskName) - - if (!muzzleDirective.coreJdk) { - def depId = "$versionArtifact.groupId:$versionArtifact.artifactId:$versionArtifact.version" - if (versionArtifact.classifier) { - depId += ":" + versionArtifact.classifier - } - def dep = instrumentationProject.dependencies.create(depId) { - transitive = 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. - dep.exclude group: 'com.sun.jdmk', module: 'jmxtools' - dep.exclude group: 'com.sun.jmx', module: 'jmxri' - // Also exclude specifically excluded dependencies - for (String excluded : muzzleDirective.excludedDependencies) { - String[] parts = excluded.split(':') - dep.exclude group: parts[0], module: parts[1] - } - - config.dependencies.add(dep) + muzzleTaskName = "muzzle-Assert${muzzleDirective.assertPass ? "Pass" : "Fail"}-$versionArtifact.groupId-$versionArtifact.artifactId-$versionArtifact.version${muzzleDirective.name ? "-${muzzleDirective.getNameSlug()}" : ""}" } - for (String additionalDependency : muzzleDirective.additionalDependencies) { - config.dependencies.add(instrumentationProject.dependencies.create(additionalDependency) { dep -> + instrumentationProject.configurations.register(muzzleTaskName) { Configuration taskConfig -> + if (!muzzleDirective.coreJdk) { + def depId = "$versionArtifact.groupId:$versionArtifact.artifactId:$versionArtifact.version" + if (versionArtifact.classifier) { + depId += ":" + versionArtifact.classifier + } + def dep = instrumentationProject.dependencies.create(depId) { + transitive = 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. + dep.exclude group: 'com.sun.jdmk', module: 'jmxtools' + dep.exclude group: 'com.sun.jmx', module: 'jmxri' + // Also exclude specifically excluded dependencies for (String excluded : muzzleDirective.excludedDependencies) { String[] parts = excluded.split(':') dep.exclude group: parts[0], module: parts[1] } - dep.transitive = true - }) + + taskConfig.dependencies.add(dep) + } + for (String additionalDependency : muzzleDirective.additionalDependencies) { + taskConfig.dependencies.add(instrumentationProject.dependencies.create(additionalDependency) { dep -> + for (String excluded : muzzleDirective.excludedDependencies) { + String[] parts = excluded.split(':') + dep.exclude group: parts[0], module: parts[1] + } + dep.transitive = true + }) + } } - def muzzleTask = instrumentationProject.task(['type': MuzzleTask], taskName) { + def muzzleTask = instrumentationProject.tasks.register(muzzleTaskName, MuzzleTask) { doLast { assertMuzzle(muzzleBootstrap, muzzleTooling, instrumentationProject, muzzleDirective) } } - runAfter.finalizedBy(muzzleTask) + runAfter.configure { + finalizedBy(muzzleTask) + } muzzleTask } @@ -710,10 +710,12 @@ abstract class MuzzleTask extends DefaultTask { @javax.inject.Inject abstract WorkerExecutor getWorkerExecutor() - void assertMuzzle(Configuration muzzleBootstrap, - Configuration muzzleTooling, - Project instrumentationProject, - MuzzleDirective muzzleDirective = null) { + public void assertMuzzle( + NamedDomainObjectProvider muzzleBootstrap, + NamedDomainObjectProvider muzzleTooling, + Project instrumentationProject, + MuzzleDirective muzzleDirective = null + ) { def workQueue String javaVersion = muzzleDirective?.javaVersion if (javaVersion) { @@ -730,8 +732,8 @@ abstract class MuzzleTask extends DefaultTask { } workQueue.submit(MuzzleAction.class, parameters -> { parameters.buildStartedTime.set(invocationDetails.buildStartedTime) - parameters.bootstrapClassPath.setFrom(muzzleBootstrap) - parameters.toolingClassPath.setFrom(muzzleTooling) + parameters.bootstrapClassPath.setFrom(muzzleBootstrap.get()) + parameters.toolingClassPath.setFrom(muzzleTooling.get()) parameters.instrumentationClassPath.setFrom(MuzzlePlugin.createAgentClassPath(instrumentationProject)) parameters.testApplicationClassPath.setFrom(MuzzlePlugin.createMuzzleClassPath(instrumentationProject, name)) if (muzzleDirective) { @@ -743,7 +745,7 @@ abstract class MuzzleTask extends DefaultTask { }) } - void printMuzzle(Project instrumentationProject) { + public void printMuzzle(Project instrumentationProject) { FileCollection cp = instrumentationProject.sourceSets.main.runtimeClasspath ClassLoader cl = new URLClassLoader(cp*.toURI()*.toURL() as URL[], null as ClassLoader) Method printMethod = cl.loadClass('datadog.trace.agent.tooling.muzzle.MuzzleVersionScanPlugin') From 9b4075eb26a055ab7c6a07570500f9688c97e83b Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 6 Aug 2025 16:21:13 +0200 Subject: [PATCH 2/2] chore: Groovy style --- buildSrc/src/main/groovy/MuzzlePlugin.groovy | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/groovy/MuzzlePlugin.groovy b/buildSrc/src/main/groovy/MuzzlePlugin.groovy index 2a3dbc1cb48..2500f288cfe 100644 --- a/buildSrc/src/main/groovy/MuzzlePlugin.groovy +++ b/buildSrc/src/main/groovy/MuzzlePlugin.groovy @@ -15,7 +15,13 @@ import org.eclipse.aether.spi.connector.transport.TransporterFactory import org.eclipse.aether.transport.http.HttpTransporterFactory import org.eclipse.aether.util.version.GenericVersionScheme import org.eclipse.aether.version.Version -import org.gradle.api.* +import org.gradle.api.Action +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.NamedDomainObjectProvider +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.Task import org.gradle.api.artifacts.Configuration import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.FileCollection @@ -246,7 +252,6 @@ class MuzzlePlugin implements Plugin { dumpVersionsToCsv(project, map) } - private static void dumpVersionRanges(Project project) { final RepositorySystem system = newRepositorySystem() final RepositorySystemSession session = newRepositorySystemSession(system)