Skip to content

Commit

Permalink
Add 'checkPlatformVersionConsistency' task
Browse files Browse the repository at this point in the history
  • Loading branch information
jjohannes committed Nov 20, 2023
1 parent d2d1e07 commit 837ae66
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 1 deletion.
7 changes: 6 additions & 1 deletion gradle/platform/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ dependencies.constraints {
api("com.sun.mail:jakarta.mail:1.6.7") { version { reject("[2.0.0,)") } } // Upgrade to 2.x requires newer Jakarta APIs
api("jakarta.inject:jakarta.inject-api:1.0.5") { version { reject("[2.0.0,)") } } // Upgrade to 2.x requires newer Jakarta APIs
api("jakarta.servlet:jakarta.servlet-api:4.0.4") { version { reject("[5.0.0,)") } } // Stay Tomcat 8 compatible
api("junit:junit:4.13.2")
api("org.apache.commons:commons-lang3:3.9")
api("org.apache.solr:solr-solrj:7.7.3") { version { reject("[8.0.0,)") } } // API changes in 8 require production code changes
api("org.apache.velocity:velocity-engine-core:2.3")
api("org.apache.zookeeper:zookeeper:3.8.0")
api("org.assertj:assertj-core:3.22.0")
api("org.opensaml:opensaml:2.6.4")
api("org.reflections:reflections:0.9.11") { version { reject("[0.9.12,)") } } // Upgrade breaks 'com.github.racc:typesafeconfig-guice'
}

dependencies {
// list the 'main' modules of our software product for 'checkPlatformVersionConsistency'
product("org.example.product:app")
}
4 changes: 4 additions & 0 deletions gradle/platform/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ pluginManagement {
plugins {
id("org.example.settings")
}
dependencyResolutionManagement {
// Include the 'main' project for checkPlatformVersionConsistency anlysis
includeBuild("../..")
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import org.example.dependencyanalysis.DependencyVersionUpgradesCheck
import org.example.dependencyanalysis.PlatformVersionConsistencyCheck

plugins {
id("java-platform")
Expand Down Expand Up @@ -29,3 +30,33 @@ tasks.register<DependencyVersionUpgradesCheck>("checkForDependencyVersionUpgrade
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<PlatformVersionConsistencyCheck>("checkPlatformVersionConsistency") {
group = HelpTasksPlugin.HELP_GROUP
productClasspath.set(fullProductRuntimeClasspath.map { it.incoming.resolutionResult.allComponents })
classpathFromPlatform.set(purePlatformVersionsPath.map { it.incoming.resolutionResult.allComponents })
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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

abstract class PlatformVersionConsistencyCheck : DefaultTask() {

@get:Internal
abstract val productClasspath: SetProperty<ResolvedComponentResult>

@get:Internal
abstract val classpathFromPlatform: SetProperty<ResolvedComponentResult>

@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())
}
}
}

0 comments on commit 837ae66

Please sign in to comment.