spring-gradle-plugins / dependency-management-plugin

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

Multiple nested BOM imports, the last one does not win #287

Closed edudar closed 3 years ago

edudar commented 3 years ago

I have a custom platform built with Gradle like this:

ext['springBootVersion'] = '2.4.1'
ext['springCloudVersion'] = 'Hoxton.SR9'
ext['resilience4jVersion'] = '1.6.1'

dependencies {
    api platform("org.springframework.boot:spring-boot-dependencies:${springBootVersion}")
    api platform("org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}")
    api platform("io.github.resilience4j:resilience4j-bom:${resilience4jVersion}")
    ...
}

Generated POM file for it contains these dependencies in the correct order:

      ...
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.4.1</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Hoxton.SR9</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>io.github.resilience4j</groupId>
        <artifactId>resilience4j-bom</artifactId>
        <version>1.6.1</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

Now when I import my platform into a project like:

plugins {
    id 'org.springframework.boot' version '2.4.1'
    id 'io.spring.dependency-management' version '1.0.10.RELEASE'
}
dependencies {
    implementation 'io.github.resilience4j:resilience4j-circuitbreaker'
}
dependencyManagement {
    imports {
        mavenBom 'my.platform:java:1.0.0'
    }
}

This dependency resolves to 1.3.1 (spring-cloud-dependencies -> spring-cloud-circuitbreaker-dependencies) instead of 1.6.1 (resilience4j-bom). Other similar dependencies that are not in spring-cloud-dependencies resolve to 1.6.1 as expected.

wilkinsona commented 3 years ago

The dependency management plugin uses Maven to produce an effective bom for an imported bom, i.e. it's Maven's ordering rules that apply to elements consumed from Maven metadata. In Maven, the ordering is first wins so it is to be expected that the dependency management from spring-cloud-dependencies take precedence. This ensures that the dependency versions are the same when consuming a bom using this plugin as they would be win using the same bom in Maven.

edudar commented 3 years ago

@wilkinsona Am I reading this documentation section wrong then? Cause it says the last has to win: “... If multiple boms provide dependency management for the same dependency, the dependency management from the last bom will be used...”

wilkinsona commented 3 years ago

@edudar The documentation is referring to bom imports in your build.gradle script. You only have one such import:

dependencyManagement {
    imports {
        mavenBom 'my.platform:java:1.0.0'
    }
}