Should I increase the version number in my project if a dependency changes? - maven

Let's suppose I have a project called myLib-1.1.0. This project has a dependency on lib-dependency-1.2.3.
If there's a new version for this dependency and I need to use it, should I change my project version as well? No other modifications are made to myLib.
At the same time myLib is a dependency for various other projects. My main concern is the impact of a small change in a dependency might have upstream.

Yes. In maven, released versions are immutable. If you release 1.1.0 with a dependency to lib-dependency-1.2.3 then that's it.
If you change to depend on lib-dependency-1.2.4 then that's a new version. You should not redeploy 1.1.0 since some people might have already pulled that (supposedly immutable) 1.1.0.
So that means you need a different version, even if it's a just a new qualifier (myLib-1.1.0-RC-2 for example, but better just 1.1.1)
Maven doesn't recheck remote repos for release versions once it has it in the local repo, so if someone has 1.1.0 already locally, they will not get the new, fixed 1.1.0.
And about your rippling problem. Upstream projects should depend on the lowest acceptable released version. i.e. if the upstream project itself is ok with myLib-1.1.0 because it doesn't need (indirectly) lib-dependency-1.2.4 then it should stay with 1.1.0

Any code change that potentially affects the behavior should be given a new version number, in other words: anything that's not an absolute trivial change should be given a new version number. A changed dependency would definitely qualify for that because, unless you do a thorough code inspection of the dependency, you have no reason to assume that they only made absolute trivial changes.
Changes are often advertised as "small" (similar to being absolutely trivial as I call it above), but they hardly ever are. They may be negligible in someone's use case, but not in someone else's use case. I've even seen circumstances where there were only changes to Javadocs in a project that would break things down the line. (You could argue about how smart it is for someone to depend that strongly on Javadoc, but that's besides the point, isn't it?)
That is not to say that you can't accumulate changes and release a bunch of them as a single release. While accumulating, your project is in flux, and should have a ...-SNAPSHOT version. There should be no two versions of myLib-1.1.0 (without the -SNAPSHOT) that have even the least little change.
The fact that you're re-releasing your project also makes explicit the fact that regression testing and such should be redone to validate that it's still working with the changes in its dependency.

Related

Why do I need to prefix `lein install` with `LEIN_SNAPSHOTS_IN_RELEASE=true` for the installation to succeed? What are the reasons behind this?

If I run lein install the terminal throws an error:
➜ lein install
If there are a lot of uncached dependencies this might take a while ...
Release versions may not depend upon snapshots.
Freeze snapshots to dated versions or set the LEIN_SNAPSHOTS_IN_RELEASE environment variable to override.
But, if I do what the (obscure) error message suggests and if I prefix
the command with LEIN_SNAPSHOTS_IN_RELEASE=true, it succeeds:
➜ LEIN_SNAPSHOTS_IN_RELEASE=true lein install
If there are a lot of uncached dependencies this might take a while ...
Created /Users/pedro/projects/my-project-name/target/1.3.0-ONE-PROJECT-REPOSITORY-NAME.jar
Wrote /Users/pedro/projects/my-project-name/pom.xml
Installed jar and pom into local repo.
I would like to understand this better.
Why is the prefix needed? Why can't Lein just accept lein install?
What is the reason/context behind this design?
Obs.: on project.clj the project name does not include the word SNAPSHOT. I have:
(defproject my-project-name "1.3.0-ONE-PROJECT-REPOSITORY-NAME" ...
I suspect one of your dependencies are pointing to a SNAPSHOT version?
I guess Leiningen does not allow you to release a "stable" (non-SNAPSHOT) version of anything that depends on something non-stable itself. Imagine your library depending on function xyz in the library [abc "1.0.0-SNAPSHOT"]. But in the snapshot version of abc released tomorrow the function xyz have been refactored, so the function signature is different, or maybe xyz has been removed altogether. Now your stable library doesn't work anymore.
That is why Leining wants it to be a deliberate decision (that takes extra effort) to do such things. But without knowing the exact version of Leiningen and the full dependency tree, I cannot say for sure, nor reproduce the behavior locally.
Also see the Leiningen documentation:
Snapshot Versions
Sometimes versions will end in "-SNAPSHOT". This means that it is not an official release but a development build. Relying on snapshot dependencies is discouraged but is sometimes necessary if you need bug fixes, etc. that have not made their way into a release yet. However, snapshot versions are not guaranteed to stick around, so it's important that non-development releases never depend upon snapshot versions that you don't control. Adding a snapshot dependency to your project will cause Leiningen to actively go seek out the latest version of the dependency daily (whereas normal release versions are cached in the local repository) so if you have a lot of snapshots it will slow things down.
Note that some libraries make their group-id and artifact-id correspond with the namespace they provide inside the jar, but this is just a convention. There is no guarantee they will match up at all, so consult the library's documentation before writing your :require and :import clauses.

What are the consequences of always using Maven Snapshots?

I work with a small team that manages a large number of very small applications (~100 Portlets). Each portlet has its own git repository. During some code I was reviewing today, someone made a small edit, and then updated their pom.xml version from 1.88-SNAPSHOT to 1.89-SNAPSHOT. I added a comment asking if this is the best way to do releases, but I don't really know the negative consequences of doing this.
Why not do this? I know snapshots are not supposed to be releases, but why not? What are the consequences of using only snapshots? I know maven will not cache snapshots the same as non-snapshots, and so it may download the artifact every time, but let's pretend the caching doesn't matter. From a release-management perspective, why is using a SNAPSHOT version every time and just bumping the number a bad idea?
UPDATE:
Each of these projects results in a war file that will never be available on a maven repo outside of our team, so there are no downstream users.
The main reason for not wanting to do this is that the whole Maven eco-system relies on a specific definition of what a snapshot version is. And this definition is not the one you're setting in your question: it is only supposed to represent a version currently in active development, and it is not suppose to be a stable version. The consequence is that a lot of the tools built around Maven assumes this definition by default:
The maven-release-plugin will not let you prepare a release with a snapshot version as released version. So you'll need to resort to tagging by hand on your version control, or make your own scripts. This also means that the users of those libraries won't be able to use this plugin with default configuration, they'll need to set allowTimestampedSnapshots.
The versions-maven-plugin which can be used to automatically update to the latest release version won't work properly as well, so your users won't be able to use it without configuration pain.
Repository managers, like Artifactory or Nexus, comes built-in with a clear distinction of repositories hosting snapshot dependencies and release dependencies. For example, if you use shared Nexus company-wide, it could be configured to purge old snapshots so this would break things for you... Imagine someone depends on 1.88-SNAPSHOT and it is completely removed: you'll have to go back in time and redeploy it, until the next removal... Also, certain Artifactory internal repositories can be configured not to accept any snapshots, so you won't be able to deploy it there; the users will be forced, again, to add more repository configuration to point at those that do allow snapshots, which they may not want to do.
Maven is about convention before configuration, meaning that all Maven projects should try to share the same semantics (directory layout, versioning...). New developers that would access your project will be confused and lose time trying to understand why your project is build the way it is.
In the end, doing this will just cause more pain on the users and will not simplify a single thing for you. Probably, you could make it somewhat work, but when something is going to break (because of company policy, or some other future change), don't act surprised...
Tunaki gave a lot of reasonable points why you break Maven best practices, and I fully support that view. But even if you don't care about "conventions of other companies", there are reasons:
If you are not doing CI (and consider every build as potential release), you need to distinguish between versions which should go productive and those who are just for testing. If everything is SNAPSHOT, this is hard to do.
If someone (accidentally) deploys a second 1.88-SNAPSHOT, it will be the new 1.88-SNAPSHOT, hiding the old one (which is available by a concrete timestamp, but this is messy). Release versions cannot be deployed twice.

Subversion/Maven changes in snapshot since last release

I expect this is a common issue, but one I am not aware of a sensible solution to.
We have adopted the procedure where all local dependent modules are moved straight back to SNAPSHOT once the release has been done. Time passes and we come to do a new release.
When we come to release we need to make a decision on whether a particular module has had any changes or not. If not, we dont need to update release the dependent snapshot and we can simply build against the previous release version as nothing has changed.
The difficulty in this process is establishing whether anything has actually changed since the last release or not. The only way I can imagine establishing this is to look in the subversion logs to see if any significant change has been checked in since the last release, and if it has then we need to release the dependent module. If it hasnt, we are ok to use the previous released version. This seems very labour intensive to me.
Is there a plugin or a better way to achieve this?

maven parent pom with different child versions

There are multiple modules in our applications and each of them have their separate version and depend on other modules(external to our organization). They all have a parent POM which has it's own version, independent from the children's version.
When one of those modules change, they're converted to snapshots.
For the following example:
Parent v14.0
- module1 v1.5.0
- dependency1(module2 v15.0.0)
- dependency2(external-jar v12.0.1)
- module2 v15.0.0
- module3 v3.1.0
If there would be a change in module2, then module2's version would become v15.0-SNAPSHOT, then module1 becomes v1.5-SNAPSHOT. The parent remains the same.
The purpose for not having the same version on parent+modules, is that we want to localize the updates made to some modules and not affect the others' versions.
This has been designed like this a long time ago and there are several bash scripts to support the updates, although they're not handling all the cases. In any case, we don't have a one-click release process and we feel we are quite far from it with this approach.
We don't know how to convince the management towards a single version approach on all modules. How do you feel about the above? Did you ever encountered a project using the above structure and how well did it go?
Thank you!
I've had to deal with such situations before. There is an actual benefit from having decentralized versions, especially in cases where your product is made out of a large number of modules and this is because of the following facts:
You don't have to release all of them as a whole, if only a handful have been changed (which, from my observation is almost always the case).
You don't have to create unnecessary tags in your version control for code which hasn't changed since the previous release.
You don't have to waste an excessive amount of time releasing modules which don't need to be released.
You know with certainty which modules have changed in a release, which helps a lot when you need to investigate a complex bug, which seems to be dating back a while.
You can actually release certain modules/aggregators before the actual release date of the complete product, allowing for more testing time and a feeling of completeness for a given part of the product.
You can make feature branch releases much easier and implement a continuous delivery in a better way.
You can re-use the same code across multiple development branches without wondering if that branched version matches the one for your branch (or at least with less confusion).
What we ended up doing was:
Extract a parent or set of parents (with no sub-modules).
Try to use fixed versions for parents as much as possible. This is a bit of a caveat, as you must change all modules that inherit it, but in the end it improves the stability.
Extract each of the modules whose versions are independent of the rest to separate modules.
Extract sets of modules whose versions must always move along together into aggregators.
Create jobs in your CI server that can do releases or manually release these modules.
Use the versions-maven-plugin.
I think it's a lot more mature of a project and company's development principles to use decentralized versions and I must admit that in the beginning I was very reluctant to this approach. You might not realize or understand the benefits immediately, but with some practice and a proper setup, you will start seeing the upsides. I'm not saying there aren't caveats like... for example bumping the version of a parent, or having to know in which modules to bump the version of one of your modules.
From my experience, this module actually works better in the end, once you've become used to working with it.
From my experience: Everywhere we tried this, it eventually failed.
Although Maven supports this approach it is not advisable because of the additional effort.
I try to use the following criteria when choosing whether to use distinct projects or a multimodule structure:
If all projects have the same release cycle, I put them in a common multi module structure. In that case, I give them all the same version and release them together.
If a part of the project is used by different other projects (organizational projects), I always split them of and give them a separate lifecycle and a separate version.
If one part of my project stabilizes, I split it off, and give it a separate lifecycle (Maven refactoring)
To do it different alway results in homebrew solutions that neither scale well, nor are easy to maintain.
Hope that helps.

Maven artifact version for patches

I'm currently working on Maven tools for Project Dash. One of the open issues is how to handle mistakes.
Maven central says: Nothing published ever changes. This is because Maven never tries to figure out whether a release has changed (unlike for SNAPSHOTs).
But I might have to create a new "release" of, say, part of Eclipse 3.6.2. Which version number should I use? 3.6.2.1, 3.6.2-1, 3.6.2_1, 3.6.2pl1? Why?
The convention for version numbers is major.minor.build.
major is incremented when the public interface changes incompatibly. For example, a method is removed, or its signature changes. Clients using your library need to take care when using a library with a different major version, because things may break.
minor is incremented when the public interface changes in a compatible way. For example, a method is added. Clients do not need to worry about about using the new version, as all the functions they are used to seeing will still be there and act the same.
build is incremented when the implementation of a function changes, but no signatures are added or removed. For example, you found a bug and fixed it. Clients should probably update to the new version, but if it doesn't work because they depended on the broken behavior, they can easily downgrade.
The tricky issue here is that it sounds like you are modifying code written and released by somebody else. The convention here, as I have seen it, is to postfix the version number with either -yourname-version or just -version. For example, linux-image-2.6.28-27 is a likely name of a Ubuntu kernel image.
As Maven uses dashes to differentiate between artifact coordinates, however, I would recommend (very long-windedly, apparently) to just add .version to avoid confusing it. So 3.6.2.1 in this case.
Maven project versions are specified like this.
<major version>.<minor version>.<incremental version>-<qualifier>
As you do not want to change the version number you are looking for a qualifier. I do not know if there is a general recommendation for the name of the qualifier. The Spring people e.g. did something like this
2.5.6.SEC01
2.5.6.SR02
3.0.0.M3
They didn't use the hyphen/dash notation to seperate the qualifier.
What ever you do, you have to be careful regarding the ordering of versions! Have a look at the first link I added.
Update: Also have a look at #krzyk comment for recent changes/additions.
This is because Maven never tries to
figure out whether a release has
changed
That's in my opinion not the basic reason. The reason is to have reliable builds in the future. You define the versions in your pom and that's it. If someone would remove artifacts from maven central or become worse changing an existing artifact you can't be sure that your build will be working in the future...or an older build would work.
The version number is up to you...i would suggest to use 3.6.2.1.

Resources