Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ muzzle-dep-report:
script:
- export SKIP_BUILDSCAN="true"
- ./gradlew --version
- ./gradlew generateMuzzleReport muzzleInstrumentationReport $GRADLE_ARGS
- ./gradlew :dd-java-agent:instrumentation:aggregateMuzzleReports $GRADLE_ARGS
after_script:
- *container_info
- *cgroup_info
Expand Down
4 changes: 4 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ gradlePlugin {
id = "dd-trace-java.muzzle"
implementationClass = "datadog.gradle.plugin.muzzle.MuzzlePlugin"
}
create("muzzle-report-aggregation-plugin") {
id = "dd-trace-java.muzzle-report-aggregation"
implementationClass = "datadog.gradle.plugin.muzzle.MuzzleReportAggregationPlugin"
}
create("call-site-instrumentation-plugin") {
id = "dd-trace-java.call-site-instrumentation"
implementationClass = "datadog.gradle.plugin.csi.CallSiteInstrumentationPlugin"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package datadog.gradle.plugin.muzzle
import datadog.gradle.plugin.muzzle.tasks.MuzzleEndTask
import datadog.gradle.plugin.muzzle.tasks.MuzzleGenerateReportTask
import datadog.gradle.plugin.muzzle.tasks.MuzzleGetReferencesTask
import datadog.gradle.plugin.muzzle.tasks.MuzzleMergeReportsTask
import datadog.gradle.plugin.muzzle.tasks.MuzzleTask
import datadog.gradle.plugin.muzzle.planner.MuzzleTaskPlanner
import org.eclipse.aether.artifact.Artifact
Expand Down Expand Up @@ -76,6 +75,7 @@ class MuzzlePlugin : Plugin<Project> {
}

val muzzleTask = project.tasks.register<MuzzleTask>("muzzle") {
description = "Check instrumentation compatibility against the configured dependency versions"
this.muzzleBootstrap.set(muzzleBootstrap)
this.muzzleTooling.set(muzzleTooling)
dependsOn(compileMuzzle)
Expand All @@ -92,11 +92,14 @@ class MuzzlePlugin : Plugin<Project> {
it.configure { finalizedBy(printReferencesTask) }
}

project.tasks.register<MuzzleGenerateReportTask>("generateMuzzleReport") {
val extension = project.extensions.getByType<MuzzleExtension>()
val runtimeClasspath = project.mainSourceSet.runtimeClasspath
val report = project.tasks.register<MuzzleGenerateReportTask>("generateMuzzleReport") {
reportDirectives.convention(project.providers.provider { extension.directives })
instrumentationClasspath.from(reportingDirectives.map { if (it.isEmpty()) emptyList<Any>() else runtimeClasspath })
dependsOn(compileMuzzle)
}

project.tasks.register<MuzzleMergeReportsTask>("mergeMuzzleReports")
project.publishMuzzleReport(report.flatMap { it.versionsFile })

val hasRelevantTask = project.gradle.startParameter.taskNames.any { taskName ->
val taskProjectPath = taskName.substringBeforeLast(":", "")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package datadog.gradle.plugin.muzzle

import org.gradle.api.file.RegularFileProperty

abstract class MuzzleReportAggregationExtension {
abstract val reportFile: RegularFileProperty
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package datadog.gradle.plugin.muzzle

import datadog.gradle.plugin.muzzle.tasks.MuzzleAggregateReportTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.Usage
import org.gradle.api.plugins.JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.register

/** Aggregates dependency reports published by instrumentation projects. */
class MuzzleReportAggregationPlugin : Plugin<Project> {
override fun apply(project: Project) {
val extension = project.extensions.create<MuzzleReportAggregationExtension>("muzzleReports")
extension.reportFile.convention(project.layout.buildDirectory.file("muzzle-deps-results/muzzle.csv"))

val aggregation = project.configurations.dependencyScope("muzzleReportAggregation")
// Reuse the Java project's declared dependencies instead of inspecting its subprojects.
project.pluginManager.withPlugin("java") {
aggregation.configure {
extendsFrom(project.configurations.getByName(IMPLEMENTATION_CONFIGURATION_NAME))
}
}

val results = project.configurations.resolvable("aggregateMuzzleReportResults") {
extendsFrom(aggregation.get())
isTransitive = false
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category::class.java, Category.LIBRARY))
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME))
}
}

val reports = results.map { configuration ->
configuration.incoming.artifactView {
// Select reports from the Java graph; plain Java stubs have no matching report variant.
withVariantReselection()
attributes.muzzleReportAttributes(project.objects)
}.files
}

val report = project.tasks.register<MuzzleAggregateReportTask>("aggregateMuzzleReports") {
versionReports.from(reports)
versionsFile.convention(extension.reportFile)
}

project.tasks.register("mergeMuzzleReports") {
group = "Muzzle"
description = "Deprecated: use aggregateMuzzleReports for dependency range reports"
dependsOn(report)
doFirst { logger.warn("mergeMuzzleReports is deprecated; use aggregateMuzzleReports") }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package datadog.gradle.plugin.muzzle

import org.gradle.api.Project
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.VerificationType
import org.gradle.api.file.RegularFile
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Provider

private const val MUZZLE_REPORT_TYPE = "muzzle-dependency-report"

internal fun AttributeContainer.muzzleReportAttributes(objects: ObjectFactory) {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category::class.java, Category.VERIFICATION))
attribute(VerificationType.VERIFICATION_TYPE_ATTRIBUTE, objects.named(VerificationType::class.java, MUZZLE_REPORT_TYPE))
}

/** Publishes the producer's output with its inferred task dependency. */
fun Project.publishMuzzleReport(report: Provider<RegularFile>) {
configurations.consumable("muzzleReportElements") {
attributes.muzzleReportAttributes(objects)
outgoing.artifact(report)
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
package datadog.gradle.plugin.muzzle.tasks

import datadog.gradle.plugin.muzzle.TestedArtifact
import datadog.gradle.plugin.muzzle.pathSlug
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.OutputFile
import java.util.SortedMap

abstract class AbstractMuzzleReportTask : AbstractMuzzleTask() {
@get:OutputFile
val versionsFile: Provider<RegularFile> = project.rootProject
.layout
.buildDirectory
.file("$MUZZLE_DEPS_RESULTS/${project.pathSlug}.csv")
abstract val versionsFile: RegularFileProperty

internal fun dumpVersionsToCsv(versions: SortedMap<String, TestedArtifact>) {
val file = versionsFile.get().asFile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,27 @@ package datadog.gradle.plugin.muzzle.tasks
import datadog.gradle.plugin.muzzle.MuzzleMavenRepoUtils
import datadog.gradle.plugin.muzzle.TestedArtifact
import org.eclipse.aether.util.version.GenericVersionScheme
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskAction
import java.util.TreeMap

abstract class MuzzleMergeReportsTask : AbstractMuzzleReportTask() {
abstract class MuzzleAggregateReportTask : AbstractMuzzleReportTask() {
init {
description = "Merge generated dependency version reports into one CSV"
description = "Aggregate instrumentation dependency range reports"
versionsFile.convention(project.layout.buildDirectory.file("$MUZZLE_DEPS_RESULTS/muzzle.csv"))
// Preserve the existing order-sensitive handling of Maven-equivalent version spellings.
outputs.upToDateWhen { false }
}

@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
val versionReports = project.files(
project.rootProject.allprojects.flatMap { producer ->
producer.tasks.withType(MuzzleGenerateReportTask::class.java).map { it.versionsFile }
}
).minus(project.files(versionsFile)).asFileTree
@get:PathSensitive(PathSensitivity.NONE)
abstract val versionReports: ConfigurableFileCollection

/**
* Merges existing CSVs from current report generators and writes the merged results to a CSV.
* Merges the declared muzzle report artifacts into a single CSV.
*/
@TaskAction
fun mergeReports() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
package datadog.gradle.plugin.muzzle.tasks

import datadog.gradle.plugin.muzzle.MuzzleDirective
import datadog.gradle.plugin.muzzle.MuzzleExtension
import datadog.gradle.plugin.muzzle.MuzzleMavenRepoUtils
import datadog.gradle.plugin.muzzle.MuzzleMavenRepoUtils.highest
import datadog.gradle.plugin.muzzle.MuzzleMavenRepoUtils.lowest
import datadog.gradle.plugin.muzzle.MuzzleMavenRepoUtils.resolveInstrumentationAndJarVersions
import datadog.gradle.plugin.muzzle.TestedArtifact
import datadog.gradle.plugin.muzzle.mainSourceSet
import datadog.gradle.plugin.muzzle.pathSlug
import org.eclipse.aether.RepositorySystem
import org.eclipse.aether.RepositorySystemSession
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.getByType
import java.net.URL
import java.net.URLClassLoader
import java.util.TreeMap
Expand All @@ -28,28 +28,25 @@ abstract class MuzzleGenerateReportTask : AbstractMuzzleReportTask() {
@get:Classpath
abstract val instrumentationClasspath: ConfigurableFileCollection

init {
description = "Generate this instrumentation's dependency version report"
@get:Internal
val reportingDirectives: Provider<List<MuzzleDirective>> = reportDirectives.map { directives ->
directives.filter { !it.isCoreJdk && !it.skipFromReport }
}

init {
description = "Generate this instrumentation's dependency range report"
reportDirectives.convention(emptyList())
versionsFile.convention(project.layout.buildDirectory.file("$MUZZLE_DEPS_RESULTS/${project.pathSlug}.csv"))
// Repository metadata can change without any local task input changing.
outputs.upToDateWhen { false }

val extension = project.extensions.getByType<MuzzleExtension>()
val runtimeClasspath = project.mainSourceSet.runtimeClasspath
val directives = project.providers.provider {
extension.directives.filter { !it.isCoreJdk && !it.skipFromReport }
}

reportDirectives.set(directives)
instrumentationClasspath.from(directives.map { if (it.isEmpty()) emptyList<Any>() else runtimeClasspath })
}

@TaskAction
fun dumpVersionRanges() {
val system: RepositorySystem = MuzzleMavenRepoUtils.newRepositorySystem()
val session: RepositorySystemSession = MuzzleMavenRepoUtils.newRepositorySystemSession(system)
val versions = TreeMap<String, TestedArtifact>()
reportDirectives.get().forEach { directive ->
reportingDirectives.get().forEach { directive ->
val range = MuzzleMavenRepoUtils.resolveVersionRange(directive, system, session)
val cp = instrumentationClasspath.map { it.toURI().toURL() }.toTypedArray<URL>()
val partials = URLClassLoader(cp, null).use { cl ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ abstract class MuzzleTask @Inject constructor(
objects: ObjectFactory,
providers: ProviderFactory,
) : AbstractMuzzleTask() {
override fun getDescription(): String = if (muzzleDirective.isPresent) {
override fun getDescription(): String = super.getDescription() ?: if (muzzleDirective.isPresent) {
"Run instrumentation muzzle on ${muzzleDirective.get().name} dependency"
} else {
"Run instrumentation muzzle on compile time dependencies"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,30 @@ open class MuzzlePluginTestFixture : GradleFixture() {
addSubproject("dd-java-agent:instrumentation:demo", instrumentationBuildScript)
}

/** Writes an aggregation project with optional instrumentation report producers. */
fun writeAggregationProject(vararg producers: String) {
addSubproject("dd-java-agent:instrumentation",
"""
plugins {
id("java")
id("dd-trace-java.muzzle-report-aggregation")
}
layout.buildDirectory.set(layout.projectDirectory.dir("relocated/build"))
muzzleReports.reportFile.set(layout.buildDirectory.file("muzzle-deps-results/dd-java-agent_instrumentation.csv"))
dependencies {
${producers.joinToString("\n") { "implementation(project(\":dd-java-agent:instrumentation:$it\"))" }}
}
tasks.register("muzzleInstrumentationReport") { dependsOn(tasks.named("aggregateMuzzleReports")) }
"""
)
writeRootProject(
"""
plugins { id("dd-trace-java.muzzle-report-aggregation") apply false }
layout.buildDirectory.set(layout.projectDirectory.dir("relocated/build"))
"""
)
}

/**
* Writes a muzzle scan plugin that always passes.
*/
Expand Down
Loading
Loading