3

Versioning is always a big question and I see many similar questions here, however none really answer my question so I try to highlight the things that are important to me specifically.

We have a single repository for a multi-module maven project. The decision for a single repository was made, because the modules are (in part) tightly coupled, and it makes refactoring across the whole codebase easier. The move to a monorepo was done just recently without thinking about how to properly handle versioning and releases.

Before, each module (then a separate project in a separate repository) was released independently and luckily never introduced breaking changes, so customers could freely choose which versions to use and never had any issues.

What I want to do is keep offering releases for the individual modules, because it makes updating much easier. (Bugfix release? just exchange the jar file). But I always want to release distribution packages.

Consider the following layout:

pom.xml
  --- app1 pom.xml
  --- app2 pom.xml
  --- lib1 pom.xml
  --- dist pom.xml

Each module has its own version. An application might get a new feature which justifies a bump in the minor version, a library might get constant buxfixes so its micro version increases fast.

It comes down to two questions:

  • Under these circumstances - what is the meaning of the version number of the maven root project?

I could imagine it simply tracking the state of the repository. A new module is added? Bump the micro version. A module is removed/merged? Bump the major version. Things like that. But I'm not sure if this is a good approach.

  • What version should the distribution package have?

When all components have different versions, I just can't pick a single one. Every update of the components has to be reflected in the distribution's version. Although I really like semantic versioning, I feel like a date-based approach might be better suited here. Make a distribution release every 6 months or so and call it 2020_06. If an important bugfix required the update of a component in between, a version like 2020_06.2 might work as well.

2
  • @πάνταῥεῖ Thanks, I removed the offending line. Although I feel that there can be multiple different answers, and experiences help in choosing the right one for my use case. Feb 29, 2020 at 7:49
  • "Although I feel that there can be multiple different answers" That's exactly what we want to avoid with the no opinion based questions policy. Feb 29, 2020 at 7:51

2 Answers 2

1

First of all, you're mixing two things that are completely independent from each other:

  • (One for all or one for each) SCM repository and
  • Maven projects with their versioning.

Note that sub-module projects that use a <parent> don't necessarily have to use the parent POM version that's the current one in the SCM repository, e.g.:

Root POM

  <groupId>my</groupId>
  <artifactId>root</artifactId>
  <version>2.0.0-SNAPSHOT</version>

Lib1 POM

  <parent>
    <groupId>my</groupId>
    <artifactId>root</artifactId>
    <version>1.2.3</version>
  </parent>

  <groupId>my</groupId>
  <artifactId>lib1</artifactId>
  <version>4.5.6-SNAPSHOT</version>

is perfectly fine since my:root:1.2.3:pom will be resolved from the (local or remote) Maven repository (if it has been installed/deployed there previously).

Root Project Version

The meaning of the version number of the root project (with <packaging>pom) is the same as for any other Maven project:

  • x.y.z-SNAPSHOT version while you add/remove/change things in your POM and test them,
  • x.y.z release version if every work is finished, tested thoroughly and hence ready to be released into the wild.

It's entirely up to you which change increases the major, minor or patch version number. As a first approach I'd change the major version for changes that cause builds to fail potentially (e.g. if it's not clear whether an upgraded dependency version is downwards-compatible) or even definitely (replacing JUnit4 with JUnit5, for instance). I'd change the minor version for e.g. a version upgrade of a dependency that's proven downwards-compatible. I'd change the patch version if it turns out that the tests weren't that thorough after all and there's e.g. a typo or a misconfiguration of a plugin, or the like. (See also Semantic Versioning 1.0.0 and 2.0.0)

Distribution Package Version

You don't have to pick a version from (one of) the components. The things mentioned at the beginning (independence of SCM repository and Maven projects) and under Root Project Version above apply here, as well.

1

What I want to do is keep offering releases for the individual modules, because it makes updating much easier. (Bugfix release? just exchange the jar file). But I always want to release distribution packages.

I think you are coupling (virtually) different things related with the SDLC; source code management, packaging and distribution.

If the source code is under the umbrella of one repository or many should be irrelevant for its packaging and distribution.

Regardless the number of repositories and the version strategy involved, It should be possible for you to set a pipeline so that

  1. Pull the source code from 1/N repositories and from specific branches.
  2. Build the root project (non-recursive)
  3. Build all the modules or just a pre-selected one.
  4. Test the module/s
  5. Package the candidate artifact to be distributed, with the required modules/versions.
  6. Test the package (as a whole)
  7. Push one or all the binaries to the artifact repository.

Repeat #4 as many times as versions you need to prove compatibility with. It might involve repeating #1,#2 and #3 with different branches or download the existing binaries from the artifact repository.

Repeat #5 for every package in #4.

This should be possible regardless the version strategy because versions are tracked by the SCM (branches, tags, whatever) or by the artifact repository.

Under these circumstances - what is the meaning of the version number of the maven root project?

Only the one you need to provide with.

If the root project is mean to be integrable, keep the Semantic Version because is useful for consumers. You have to decide what changes on the modules cause the root project's version to change and how. That's up to you, we can't tell given the little context we have.

If not or if it's causing confusion, then change it.

Think in Android. Android is distributed following a different version strategy than the components or services It comprises.

I run Android A but the GBoard is x.y.z. There could be several patches but it's still A. There have been a couple of releases of GBoard since I installed Android A. I have installed both versions but my Android version remains the same.

Internally, Google probably follows a second strategy to track the different patched versions of Android A. Which one, I don't know. Probably one involving build dates and numbers.

What version should the distribution package have?

I don't think you are asking to the right audience.

I feel like a date-based approach might be better suited here. Make a distribution release every 6 months or so and call it 2020_06. If an important bugfix required the update of a component in between, a version like 2020_06.2 might work as well.

This answers your previous question. Note that you set the semantics according to one prupose, tracking versions and updates on the time. Yours is explaining to me that

  • There could be several versions along the year.
  • There could be updates of the current version

What it doesn't explain is

  • Differences between versions
  • Differences between versions and updates
  • What to expect from each

If that's what you want me to know, then seems fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.