1

We use a Maven BOM to manage dependencies of a suite of libraries. The dependencyManagement section of the BOM generally uses version ranges to specify versions of these libraries, e.g., [2.0,2.1) Child pom.xml's using the BOM do not specify versions for these managed dependencies. (Edit for clarification: we use specific versions for third party dependencies, the ranges are used for internal libraries that are undergoing development, where the versions can change rapidly. We define version ranges to ensure broad compatibility between these libraries, i.e. all within the same major version.)

(Note that this is not a multi-module project. Libraries and service projects using the BOM mechanism just declare it as a parent and pull it from a Nexus repository. they are not built together.)

We also have some build system scripts that use versions:resolve-ranges to pin the versions of dependencies appearing in our library and service pom.xml's (not the BOM's pom.xml). These pom.xml's with resolved ranges are checked in to source control and tagged, so that if we need to roll back a deployment to an earlier version, we can use that tagged pom.xml to make a build that uses the same dependency versions as the original build, even if a newer version of a dependency is now available (and thus resolve-ranges would come up with the newer version if we reran it).

I just noticed that these two mechanisms are not working well together. Running versions:resolve-ranges on the library or service pom.xml only resolves the ranges in that pom.xml. Versions under dependency management are still not specified, so if we made a new build using this pom.xml, we'd get the latest dependency version in range at build time. Not what we want!

Is there a way to use versions:resolve-ranges (or any other plugin or technique) to resolve the managed versions and stick them into the child pom.xml?

Here is a contrived example.

The BOM:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.maventest</groupId>
    <artifactId>myproject</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>myproject</name>
    <url>http://maven.apache.org</url>
    <dependencyManagement>
       <dependencies>
          <dependency>
             <groupId>commons-lang</groupId>
             <artifactId>commons-lang</artifactId>
             <version>[2.0, 2.3]</version>
          </dependency>
       </dependencies>
    </dependencyManagement>
</project>

Child project using the BOM (one managed dependency, one unmanaged):

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <parent>
    <groupId>com.maventest</groupId>
    <artifactId>myproject</artifactId>
    <version>1.0-SNAPSHOT</version>
    <relativePath>../myproject/pom.xml</relativePath>
  </parent>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.maventest</groupId>
  <artifactId>mytest</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>mytest</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <scope>compile</scope>
   </dependency>
   <dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <version>[3.8, 3.9)</version>
     <scope>test</scope>
   </dependency>
  </dependencies>
</project>

Snippet from mvn dependency:tree showing effective versions of dependencies:

[INFO] com.maventest:mytest:jar:1.0-SNAPSHOT

[INFO] +- commons-lang:commons-lang:jar:2.3:compile

[INFO] \- junit:junit:jar:3.8.2-brew:test

Dependency section from mytest pom.xml after mvn versions:resolve-ranges:

<dependencies>
  <dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>3.8.2-brew</version>
    <scope>test</scope>
  </dependency>
</dependencies>

So the unmanaged dependency is resolved, as expected. But the managed one is not. How can I get it to be resolved too?

Community
  • 1
  • 1
ryryguy
  • 610
  • 4
  • 15
  • A BOM should not use version ranges. It's better to define particular versions of the used libs...and than you don't need to change the versions in the child... – khmarbaise Oct 20 '17 at 07:54
  • The BOM does use specific versions for third party stuff. We use version ranges for our internal libraries that are undergoing development, where the versions can be changing very rapidly. It would not be practical to use specific versions for those. (That being said, maybe it's the case that we should just not provide dependency management for those libraries in the BOM and explicitly specify the ranges in the children.) – ryryguy Oct 20 '17 at 15:50
  • You can update the dependencies via versions-maven-plugin which can also being handled by automatic processes so no need to do this manually. Apart from that version ranges make your build non reproducible... – khmarbaise Oct 20 '17 at 17:13
  • Yes, we do use versions-maven-plugin the resolve the ranges automatically in Jenkins, to make a version of the pom that can be used to reproduce the build, and these are the builds we deploy. Ranges are still really useful for us doing parallel, iterative development, making local snapshot builds and so forth where we don't care about the build being reproducible. This has worked well for us before we introduced the BOM; the only problem is that this system doesn't work with ranges in the BOM. – ryryguy Oct 20 '17 at 19:40

1 Answers1

0

Forgot about this question! In the end I could never find a way to pin the managed versions which were based on ranges. So I did stop defining the versions in the BOM and just specified them with ranges in each child pom. More boilerplate in the child poms, but not that bad.

We were still able to define properties that specified the ranges in the BOM which the children could use, making it a bit easier to bump all the ranges all when necessary.

ryryguy
  • 610
  • 4
  • 15