From 8f4c321f7489aa6ba5b3ce6ff1d08e93a1d7378e Mon Sep 17 00:00:00 2001 From: Jendrik Johannes Date: Wed, 31 May 2023 13:16:20 +0200 Subject: [PATCH] Customized dependency analysis --- gradle/plugins/base-plugins/build.gradle.kts | 1 + .../kotlin/org.example.platform.gradle.kts | 1 + .../main/kotlin/org.example.root.gradle.kts | 7 ++ .../build.gradle.kts | 6 ++ ...le.dependency-analysis-platform.gradle.kts | 79 ++++++++++++++++++ ...ple.dependency-analysis-project.gradle.kts | 40 +++++++++ ...xample.dependency-analysis-root.gradle.kts | 10 +++ .../DependencyFormatCheck.kt | 81 +++++++++++++++++++ .../DependencyScopeCheck.kt | 41 ++++++++++ .../DependencyVersionUpgradesCheck.kt | 58 +++++++++++++ .../PlatformVersionConsistencyCheck.kt | 63 +++++++++++++++ .../main/kotlin/org.example.java.gradle.kts | 1 + .../plugins/plugins-platform/build.gradle.kts | 3 +- 13 files changed, 390 insertions(+), 1 deletion(-) create mode 100644 gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-platform.gradle.kts create mode 100644 gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-project.gradle.kts create mode 100644 gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-root.gradle.kts create mode 100644 gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyFormatCheck.kt create mode 100644 gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyScopeCheck.kt create mode 100644 gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyVersionUpgradesCheck.kt create mode 100644 gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/PlatformVersionConsistencyCheck.kt diff --git a/gradle/plugins/base-plugins/build.gradle.kts b/gradle/plugins/base-plugins/build.gradle.kts index 9b4b3d79..cd774386 100644 --- a/gradle/plugins/base-plugins/build.gradle.kts +++ b/gradle/plugins/base-plugins/build.gradle.kts @@ -5,5 +5,6 @@ plugins { dependencies { implementation(platform(project(":plugins-platform"))) + implementation(project(":dependency-analysis-plugins")) implementation(project(":dependency-rules-plugins")) } diff --git a/gradle/plugins/base-plugins/src/main/kotlin/org.example.platform.gradle.kts b/gradle/plugins/base-plugins/src/main/kotlin/org.example.platform.gradle.kts index 053486af..e5b2c3d4 100644 --- a/gradle/plugins/base-plugins/src/main/kotlin/org.example.platform.gradle.kts +++ b/gradle/plugins/base-plugins/src/main/kotlin/org.example.platform.gradle.kts @@ -1,6 +1,7 @@ plugins { id("java-platform") id("org.example.base") + id("org.example.dependency-analysis-platform") } // Depend on other Platforms/BOMs to align versions for libraries that consist of multiple components (like Jackson) diff --git a/gradle/plugins/base-plugins/src/main/kotlin/org.example.root.gradle.kts b/gradle/plugins/base-plugins/src/main/kotlin/org.example.root.gradle.kts index dcd6e759..d4e13ba3 100644 --- a/gradle/plugins/base-plugins/src/main/kotlin/org.example.root.gradle.kts +++ b/gradle/plugins/base-plugins/src/main/kotlin/org.example.root.gradle.kts @@ -1,5 +1,6 @@ plugins { id("lifecycle-base") + id("org.example.dependency-analysis-root") } // Configure the ':tasks' task of the root project to only show @@ -49,3 +50,9 @@ tasks.register("checkForDependencyVulnerabilities") { description = "Check current dependencies for known vulnerabilities" dependsOn(":app:dependencyCheckAnalyze") } + +tasks.register("checkForDependencyVersionUpgrades") { + group = mainBuildGroup + description = "Check for version upgrades (runs weekly on CI)" + dependsOn(gradle.includedBuild("platform").task(":$name")) +} diff --git a/gradle/plugins/dependency-analysis-plugins/build.gradle.kts b/gradle/plugins/dependency-analysis-plugins/build.gradle.kts index bc0172f0..e24ad2cc 100644 --- a/gradle/plugins/dependency-analysis-plugins/build.gradle.kts +++ b/gradle/plugins/dependency-analysis-plugins/build.gradle.kts @@ -1,3 +1,9 @@ plugins { `kotlin-dsl` } + +dependencies { + implementation(platform(project(":plugins-platform"))) + + implementation("com.autonomousapps:dependency-analysis-gradle-plugin") +} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-platform.gradle.kts b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-platform.gradle.kts new file mode 100644 index 00000000..3da50ad1 --- /dev/null +++ b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-platform.gradle.kts @@ -0,0 +1,79 @@ +import org.example.dependencyanalysis.DependencyFormatCheck +import org.example.dependencyanalysis.DependencyVersionUpgradesCheck +import org.example.dependencyanalysis.PlatformVersionConsistencyCheck + +plugins { + id("java-platform") +} + +val checkDependencyFormatting = tasks.register("checkDependencyFormatting") { + group = LifecycleBasePlugin.VERIFICATION_GROUP + + buildFilePath.set(project.buildFile.absolutePath) + shouldNotHaveVersions.set(false) + declaredDependencies.put("api", provider { configurations.api.get().dependencies.map { d -> d.toDeclaredString() } }) + declaredDependencies.put("runtime", provider { configurations.runtime.get().dependencies.map { d -> d.toDeclaredString() } }) + declaredConstraints.put("api", provider { configurations.api.get().dependencyConstraints.map { d -> d.toDeclaredString() } }) + declaredConstraints.put("runtime", provider { configurations.runtime.get().dependencyConstraints.map { d -> d.toDeclaredString() } }) +} + +val latestReleases = configurations.dependencyScope("dependencyVersionUpgrades") { + withDependencies { + add(project.dependencies.platform(project(project.path))) + configurations.api.get().dependencies.forEach { + add(project.dependencies.platform("${it.group}:${it.name}:latest.release") { isTransitive = false }) + } + configurations.api.get().dependencyConstraints.forEach { + add(project.dependencies.create("${it.group}:${it.name}:latest.release") { isTransitive = false }) + } + } +} +val latestReleasesPath = configurations.resolvable("latestReleasesPath") { + attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) + attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY)) + extendsFrom(latestReleases.get()) +} +tasks.register("checkForDependencyVersionUpgrades") { + group = HelpTasksPlugin.HELP_GROUP + projectName.set(project.name) + apiDependencies.set(configurations.api.get().dependencies.map { "${it.group}:${it.name}:${it.version}" }) + apiDependencyConstraints.set(configurations.api.get().dependencyConstraints.map { "${it.group}:${it.name}:${it.version}" }) + latestReleasesResolutionResult.set(latestReleasesPath.map { it.incoming.resolutionResult.allComponents }) +} + +// Install a task that checks the consistency of the platform against the resolution result of the product +val product = configurations.dependencyScope("product").get() +dependencies { + product(platform(project(path))) +} +val purePlatformVersions = configurations.dependencyScope("purePlatformVersions") { + withDependencies { + add(project.dependencies.platform(project(project.path))) + // Create a dependency for eac constraint defined in the platform (this is to check for unused entries) + configurations.api.get().dependencyConstraints.forEach { constraint -> + add(project.dependencies.create("${constraint.group}:${constraint.name}") { isTransitive = false }) + } + } +} +val fullProductRuntimeClasspath = configurations.resolvable("fullProductRuntimeClasspath") { + attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) + attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY)) + extendsFrom(product) +} +val purePlatformVersionsPath = configurations.resolvable("purePlatformVersionsPath") { + attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) + attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY)) + extendsFrom(purePlatformVersions.get()) +} +tasks.register("checkPlatformVersionConsistency") { + group = HelpTasksPlugin.HELP_GROUP + productClasspath.set(fullProductRuntimeClasspath.map { it.incoming.resolutionResult.allComponents }) + classpathFromPlatform.set(purePlatformVersionsPath.map { it.incoming.resolutionResult.allComponents }) +} + +tasks.check { + dependsOn(checkDependencyFormatting) +} + +fun Dependency.toDeclaredString() = "$group:$name:$version" +fun DependencyConstraint.toDeclaredString() = "$group:$name:$version" diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-project.gradle.kts b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-project.gradle.kts new file mode 100644 index 00000000..96da16fc --- /dev/null +++ b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-project.gradle.kts @@ -0,0 +1,40 @@ +import com.autonomousapps.DependencyAnalysisSubExtension +import org.example.dependencyanalysis.DependencyFormatCheck +import org.example.dependencyanalysis.DependencyScopeCheck + +plugins { + id("java") +} + +val checkDependencyFormatting = tasks.register("checkDependencyFormatting") { + group = LifecycleBasePlugin.VERIFICATION_GROUP + + buildFilePath.set(project.buildFile.absolutePath) + shouldNotHaveVersions.set(true) + sourceSets.all { + declaredDependencies.put(implementationConfigurationName, provider { configurations.getByName(implementationConfigurationName).dependencies.map { d -> d.toDeclaredString() } }) + declaredDependencies.put(runtimeOnlyConfigurationName, provider { configurations.getByName(runtimeOnlyConfigurationName).dependencies.map { d -> d.toDeclaredString() } }) + declaredDependencies.put(compileOnlyConfigurationName, provider { configurations.getByName(compileOnlyConfigurationName).dependencies.map { d -> d.toDeclaredString() } }) + declaredDependencies.put(apiConfigurationName, provider { configurations.findByName(apiConfigurationName)?.dependencies?.map { d -> d.toDeclaredString() } ?: emptyList() }) + declaredDependencies.put(compileOnlyApiConfigurationName, provider { configurations.findByName(compileOnlyApiConfigurationName)?.dependencies?.map { d -> d.toDeclaredString() } ?: emptyList() }) + } +} + +val checkDependencyScopes = tasks.register("checkDependencyScopes") { + group = LifecycleBasePlugin.VERIFICATION_GROUP + shouldRunAfter(checkDependencyFormatting) +} + +tasks.check { + dependsOn(checkDependencyFormatting) + dependsOn(checkDependencyScopes) +} + +plugins.withId("com.autonomousapps.dependency-analysis") { + extensions.getByType().registerPostProcessingTask(checkDependencyScopes) +} + +fun Dependency.toDeclaredString() = when(this) { + is ProjectDependency -> ":$name" + else -> "$group:$name${if (version == null) "" else ":$version"}" +} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-root.gradle.kts b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-root.gradle.kts new file mode 100644 index 00000000..47951078 --- /dev/null +++ b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-root.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("com.autonomousapps.dependency-analysis") +} + +// Lifecycle task to check dependency scopes in all subprojects +tasks.register("checkDependencyScopes") { + group = LifecycleBasePlugin.VERIFICATION_GROUP + description = "Check all dependency scopes (api vs implementation) and find unused dependencies" + dependsOn(subprojects.map { "${it.path}:checkDependencyScopes"}) +} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyFormatCheck.kt b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyFormatCheck.kt new file mode 100644 index 00000000..7ce8d58e --- /dev/null +++ b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyFormatCheck.kt @@ -0,0 +1,81 @@ +package org.example.dependencyanalysis + +import org.gradle.api.DefaultTask +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction + +/** + * Check that 'dependencies' are defined in alphabetical order and without version. + */ +abstract class DependencyFormatCheck : DefaultTask() { + + @get:Input + abstract val buildFilePath : Property + + @get:Input + abstract val declaredDependencies : MapProperty> // Map of 'scope' to 'coordinates' + + @get:Input + abstract val declaredConstraints : MapProperty> // Map of 'scope' to 'coordinates' + + @get:Input + abstract val shouldNotHaveVersions : Property + + @TaskAction + fun check() { + declaredDependencies.get().forEach { (scope, dependencies) -> + if (shouldNotHaveVersions.get()) { + dependencies.forEach { coordinates -> + if (coordinates.count { it == ':' } == 2 && !coordinates.startsWith("org.jetbrains.kotlin:kotlin-stdlib:")) { + throw RuntimeException(""" + ${buildFilePath.get()} + + Dependencies with versions are not allowed. Please declare the dependency as follows: + + ${scope}("${coordinates.substring(0, coordinates.lastIndexOf(':'))}") + + All versions must be declared in 'gradle/platform'. + If the version is not yet defined there, add the following to 'gradle/platform/build.gradle.kts': + + api("$coordinates") + """.trimIndent()) + } + } + } + + val declaredInBuildFile = dependencies.filter { + // Ignore dependencies that are defined in our plugins + it !in listOf( + "org.example.product:platform", + "org.slf4j:slf4j-simple", + "org.junit.jupiter:junit-jupiter-engine", + "org.junit.jupiter:junit-jupiter") + } + val sortedProject = declaredInBuildFile.filter { it.startsWith(":") }.sorted() + val sortedExternal = declaredInBuildFile.filter { !it.startsWith(":") }.sorted() + if (declaredInBuildFile != sortedProject + sortedExternal) { + throw RuntimeException(""" + ${buildFilePath.get()} + + $scope dependencies are not declared in alphabetical order. Please use this order: + ${sortedProject.joinToString("\n ") {"${scope}(project(\"${it}\"))"}} + ${sortedExternal.joinToString("\n ") {"${scope}(\"${it}\")"}} + """.trimIndent()) + } + } + + declaredConstraints.get().forEach { (scope, constraints) -> + val sortedConstraints = constraints.sorted() + if (constraints != sortedConstraints) { + throw RuntimeException(""" + ${buildFilePath.get()} + + $scope dependency constraints are not declared in alphabetical order. Please use this order: + ${sortedConstraints.joinToString("\n ") {"${scope}(\"${it}\")"}} + """.trimIndent()) + } + } + } +} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyScopeCheck.kt b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyScopeCheck.kt new file mode 100644 index 00000000..c1a2c1aa --- /dev/null +++ b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyScopeCheck.kt @@ -0,0 +1,41 @@ +package org.example.dependencyanalysis + +import com.autonomousapps.AbstractPostProcessingTask +import com.autonomousapps.model.Advice +import com.autonomousapps.model.ProjectCoordinates +import org.gradle.api.tasks.TaskAction + +/** + * Task that uses the 'com.autonomousapps.dependency-analysis' plugin to find unused dependencies and check + * 'api' vs. 'implementation' scopes. + */ +abstract class DependencyScopeCheck : AbstractPostProcessingTask() { + + @TaskAction + fun check() { + val projectAdvice = projectAdvice().dependencyAdvice + if (projectAdvice.isNotEmpty()) { + val toAdd = projectAdvice.filter { it.toConfiguration != null && it.toConfiguration != "runtimeOnly" } + .map { it.declaration(it.toConfiguration) }.sorted() + val toRemove = + projectAdvice.filter { it.fromConfiguration != null }.map { it.declaration(it.fromConfiguration) } + .sorted() + + throw RuntimeException( + """ + ${projectAdvice().projectPath.substring(1)}/build.gradle.kts + + Please add the following dependency declarations: + ${toAdd.joinToString("\n ") { it }} + + Please remove the following dependency declarations: + ${toRemove.joinToString("\n ") { it }} + """.trimIndent() + ) + } + } + + private fun Advice.declaration(conf: String?) = + if (coordinates is ProjectCoordinates) "${conf}(project(\"${coordinates.identifier}\"))" + else "${conf}(\"${coordinates.identifier}\")" +} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyVersionUpgradesCheck.kt b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyVersionUpgradesCheck.kt new file mode 100644 index 00000000..1f6b32b1 --- /dev/null +++ b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyVersionUpgradesCheck.kt @@ -0,0 +1,58 @@ +package org.example.dependencyanalysis + +import org.gradle.api.DefaultTask +import org.gradle.api.artifacts.result.ResolvedComponentResult +import org.gradle.api.provider.Property +import org.gradle.api.provider.SetProperty +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.TaskAction + +/** + * Checks if new versions are available for what is declared in the platform. + */ +abstract class DependencyVersionUpgradesCheck : DefaultTask() { + + @get:Internal + abstract val projectName: Property + + @get:Internal + abstract val apiDependencies: SetProperty + + @get:Internal + abstract val apiDependencyConstraints: SetProperty + + @get:Internal + abstract val latestReleasesResolutionResult: SetProperty + + @TaskAction + fun check() { + val platformDependencyUpgrades = apiDependencies.get().filter { declared -> declared.resolvedVersion() != declared.version() } + val constraintUpgrades = apiDependencyConstraints.get().filter { declared -> declared.resolvedVersion() != declared.version() } + if (platformDependencyUpgrades.isNotEmpty() || constraintUpgrades.isNotEmpty()) { + throw RuntimeException(""" + ${projectName.get()}/build.gradle.kts + + The following dependency versions should be upgraded in 'gradle/platform/build.gradle.kts' (dependencies {} block): + + ${platformDependencyUpgrades.joinToString("\n ") { "api(platform(\"${it.ga()}:${it.resolvedVersion()}\"))" }} + + The following dependency versions should be upgraded in 'gradle/platform/build.gradle.kts' (dependencies.constraints {} block): + + ${constraintUpgrades.joinToString("\n ") { "api(\"${it.ga()}:${it.resolvedVersion()}\")" }} + + If we cannot perform an upgrade, please add a '{ version { reject("...") } }' statement and a comment + for the versions we cannot support at the moment. + """.trimIndent()) + } + } + + private fun String.ga() = substring(0, lastIndexOf(":")) + + private fun String.version() = substring(lastIndexOf(":") + 1) + + private fun String.resolvedVersion() = + latestReleasesResolutionResult.get().find { + it.moduleVersion!!.module.toString() == ga() + }?.moduleVersion?.version ?: version() // if no fitting version could be determined, return the declared one + +} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/PlatformVersionConsistencyCheck.kt b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/PlatformVersionConsistencyCheck.kt new file mode 100644 index 00000000..dda68726 --- /dev/null +++ b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/PlatformVersionConsistencyCheck.kt @@ -0,0 +1,63 @@ +package org.example.dependencyanalysis + +import org.gradle.api.DefaultTask +import org.gradle.api.artifacts.component.ModuleComponentSelector +import org.gradle.api.artifacts.result.ResolvedComponentResult +import org.gradle.api.attributes.Attribute +import org.gradle.api.attributes.Category +import org.gradle.api.provider.SetProperty +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.TaskAction + +/** + * Checks that all versions declared in the platform are used and are consistent with the consistent resolution result. + */ +abstract class PlatformVersionConsistencyCheck : DefaultTask() { + + @get:Internal + abstract val productClasspath: SetProperty + + @get:Internal + abstract val classpathFromPlatform: SetProperty + + @TaskAction + fun check() { + val publishedCategory = Attribute.of( Category.CATEGORY_ATTRIBUTE.name, String::class.java) + val resolvedToDeclaredVersions = + productClasspath.get().filter { it.moduleVersion?.group != "org.example.product" }.associate { cpEntry -> + cpEntry.moduleVersion to cpEntry.dependents.find { + it.from.variants.any { variant -> + variant.attributes.getAttribute(Category.CATEGORY_ATTRIBUTE)?.name == Category.REGULAR_PLATFORM + || variant.attributes.getAttribute(publishedCategory) == Category.REGULAR_PLATFORM + } + }?.let { + (it.requested as ModuleComponentSelector).version + } + } + + + val unnecessaryEntries = classpathFromPlatform.get().filter { platformEntry -> + productClasspath.get().none { platformEntry.moduleVersion?.module == it.moduleVersion?.module } + } + val missingEntries = resolvedToDeclaredVersions.filter { it.value == null }.map { it.key } + val wrongEntries = resolvedToDeclaredVersions.filter { it.value != null && it.key?.version != it.value } + + if (unnecessaryEntries.isNotEmpty() || missingEntries.isNotEmpty() || wrongEntries.isNotEmpty()) { + throw RuntimeException(""" + The following entries are not used in production code: + + ${unnecessaryEntries.joinToString("\n ") { "api(\"${it.moduleVersion}\")" }} + + The following transitive dependencies are not listed in the platform: + + ${missingEntries.joinToString("\n ") { "api(\"${it}\")" }} + + The following dependencies should be updated to the resolved versions: + + ${wrongEntries.keys.joinToString("\n ") { "api(\"${it}\") - currently declared '${wrongEntries[it]}'" }} + + """.trimIndent()) + } + } +} + diff --git a/gradle/plugins/java-base-plugins/src/main/kotlin/org.example.java.gradle.kts b/gradle/plugins/java-base-plugins/src/main/kotlin/org.example.java.gradle.kts index dfe962c8..ee8824fa 100644 --- a/gradle/plugins/java-base-plugins/src/main/kotlin/org.example.java.gradle.kts +++ b/gradle/plugins/java-base-plugins/src/main/kotlin/org.example.java.gradle.kts @@ -3,6 +3,7 @@ plugins { id("jacoco") // Record test coverage data during test execution id("org.example.base") id("org.example.consistent-resolution") + id("org.example.dependency-analysis-project") } // Configure Java compilation on java {} extension or directly on 'JavaCompile' tasks diff --git a/gradle/plugins/plugins-platform/build.gradle.kts b/gradle/plugins/plugins-platform/build.gradle.kts index 2965d311..ba662629 100644 --- a/gradle/plugins/plugins-platform/build.gradle.kts +++ b/gradle/plugins/plugins-platform/build.gradle.kts @@ -3,8 +3,9 @@ plugins { } dependencies.constraints { + api("com.autonomousapps:dependency-analysis-gradle-plugin:1.27.0") api("dev.jacomet.gradle.plugins:logging-capabilities:0.11.1") api("io.fuchs.gradle.classpath-collision-detector:classpath-collision-detector:0.3") api("org.gradlex:java-ecosystem-capabilities:1.3.1") - api("org.owasp:dependency-check-gradle:7.4.4") + api("org.owasp:dependency-check-gradle:9.0.2") }