spring-gradle-plugins / dependency-management-plugin

A Gradle plugin that provides Maven-like dependency management functionality
690 stars 88 forks source link

Add new failOnDependencyOverride ResolutionStrategy #393

Closed lukaszgyg closed 1 month ago

lukaszgyg commented 1 month ago

Use Case: We are integrating the dependency-management-plugin into our projects to ensure that the versions defined in our BOM are consistently used across all dependencies. Our organization has numerous projects where dependency versions are explicitly defined, making it challenging to determine which versions are sourced from the BOM and which are overridden by specifying versions directly within the project. Current State: We are aware of the overriddenByDependencies property that allows control over whether the version of a dependency should come from the BOM or from the explicitly declared dependency in the project. However, this approach is not ideal for us as it complicates our build.gradle files. We aim to maintain a clean build.gradle where all dependencies managed by the BOM are declared without explicit versions. Question: How can we achieve this goal? Is there a way to define a custom ResolutionStrategy or another mechanism within the dependency-management-plugin that enforces the use of BOM versions and ensures that dependencies declared in build.gradle do not specify versions if they are managed by the BOM?

wilkinsona commented 1 month ago

This isn't something that the dependency management plugin supports. The goal that you've described sounds like a good fit for Gradle's enforcedPlatform, having you considering using that rather than the dependency management plugin?

lukaszgyg commented 1 month ago

@wilkinsona thanks for the quick response! Yes, I looked into the enforcedPlatform. As I understood from the documentation, it only supports the "quiet" override (no warning, no error). It will be nice to give the user feedback that the specified version is actually not used => override.

wilkinsona commented 1 month ago

You're right. I thought dependency resolution would fail, but Gradle essentially silently ignores the override when declared like this:

dependencies {
    implementation(enforcedPlatform("org.springframework.boot:spring-boot-dependencies:3.3.2"))
    implementation("org.springframework:spring-core:6.1.0")
}

It works like this:

dependencies {
    implementation(enforcedPlatform("org.springframework.boot:spring-boot-dependencies:3.3.2"))
    implementation("org.springframework:spring-core") {
        version {
            strictly "6.1.10"
        }
    }
}

However, this relies on the version override being declared in an unusual way.

Despite this, I still think you'd be better using Gradle's platform or enforced platform support as its modelling of the dependency management as constraints allows you to implement your desired verification yourself. For example:

plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation(enforcedPlatform("org.springframework.boot:spring-boot-dependencies:3.3.2"))
    implementation("org.springframework:spring-core:6.1.0")
}

tasks.register("verifyCompileDependencies") {
    doFirst {
        def constraints = []
        configurations.compileClasspath.incoming.resolutionResult.allDependencies.each {
            if (it.constraint) {
                constraints += "${it.requested.group}:${it.requested.module}"
            }
        }
        configurations.compileClasspath.incoming.dependencies.each {
            if (it.version && constraints.contains("${it.group}:${it.name}")) {
                logger.warn("Dependency ${it.group}:${it.name}:${it.version} is attempting to override a constrained version")
            }
        }
    }
}

This will output a warning about the spring-core dependency. Replace implementation("org.springframework:spring-core:6.1.0") with implementation("org.springframework:spring-core") to resolve the warning. It should be fairly straightforward to expand this to configurations other than compileClasspath.

Thanks again for the suggestion but I'm going to close this one now as this isn't something that we want to support directly in the dependency management plugin.

lukaszgyg commented 1 month ago

Thank you, @wilkinsona, for providing the verification step! This will greatly simplify the analysis of the version source.