Versioning for a maven project with small, very frequent releases - maven-2

I'm converting an ant project to a maven one. This project differs from the ones I've usually converted since it has very frequent releases, typically 8-10 times per day.
By release I mean that the resulting jar is packaged and included in the production enviroment. This project is a leaf one, so it publishes no API, it only consumes it. It is also at most a runtime dependency for two other projects.
I'd like to have a versioning scheme where:
it's easy to deploy without forcing the developers to think about what version number to assign to the project, since the number is meaningless;
It's easy to include the latest version of this project as a dependency without constantly bumping up dependency versions;
Most likely the dependency version would not be a -SNAPSHOT, since that would conflict with the maven-release-plugin we're using for other projects, but I'm open to suggestions.

Actually, you can use x-SNAPSHOT version and still use the maven-release-plugin. Just use mvn release:prepare before mvn release:perform to prepare your release and change the version in the poms from x-SNAPSHOT to a new version (you will be prompted for the versions to use). You can check out this introduction to the maven-release-plugin for a quick overview of release:prepare and release:perform.
Then, to include the latest version without constantly updating dependencies version, you could use dependency ranges like in the following snippet where we specify a range Junit 3.8 - Junit 4.0:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>[3.8,4.0)</version>
<scope>test</scope>
</dependency>
A version before or after the comma is not required, and means +/- infinity. For example, [4.0,) means any version greater than or equal to 4.0.
Personally, I don't like to use dependency ranges that much because I find that it can lead to build reproducibility issues and makes the build more fragile.
But you may have good reasons to use them.

Related

Using different eclipselink than bundled in glassfish-embedded-web

I use glassfish-embedded-web for integration tests inside a maven project:
<dependency>
<groupId>org.glassfish.extras</groupId>
<artifactId>glassfish-embedded-web</artifactId>
<version>3.2-b06</version>
<scope>test</scope>
</dependency>
glassfish-embedded-web comes with Eclipselink 2.2.0, but the project requires features of 2.4. For regular deployment, this is solved by adding je required jars to glassfish's modules directory and this dependency:
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.core</artifactId>
<version>2.4.1</version>
<scope>provided</scope>
</dependency>
I tried also compile scope, still the embedded EL 2.2.0 is used. Adding a test scope dependency on EL 2.4.1 doesn't help. Is there any way to solve this?
Did you try to specify the maven scope test? Otherwise it will not be available while testing! To only provide this version for testing you could use maven profiles.
I see two possible solutions to this problem: either you build your own glassfish-embedded or you just use a brute force approach and modify the jar.
On the 1st approach:
After spending some time building GF I figured that even with my dilettante shell scripting skills its easier to just use the second approach instead of figuring GF code. However, if you're up for this one I'd suggest to start at oracle wiki.
On the 2nd approach: As I've mentioned above, automating this task is the best approach in my opinion (at least if you're dealing with numerous libs and continuous changes), so I wrote this script with all the necessary instructions on how to use it. After you get the new jar just install it in your local repo. I'm using Nexus so for me it was a matter of couple buttons getting pressed.
P.S.: Any comments/advices/improvements on the script are welcome.

Can maven3 runtime execute maven2 compatible pom.xml files

Some of our new projects have been migrated to maven3 and some of the older projects are still using the maven2 compliant pom.xml files.
Can maven3 runtime execute maven2 compatible pom.xml files also?
maven 3 is mostly compatible with maven 2 configuration. But there is still some incompatibilities.
For a full list you should check here there is also sometime problems with plugins (as Torsten suggested).
Resources:
Maven 3.x Plugin Compatibility Matrix
On the same topic:
switching to maven3
Typically yes, but it may depend on the plugin version you are using.
Please note that e.g. the maven site plugin is different for maven 2 and maven 3 or some options of the maven enforcer plugin are no longer valid for maven 3. There might be others.
Yes, it is.
At first you may be alarmed by the fact that it reports a bunch of warnings and sometimes refuses to build before you take care of the problems, but this is actually better for you as (if you run into this) it simply tells you what was wrong with your project so far.
Other than that, the site plugin is completely re-written and you need to use the version for Maven 3. (Check here)

what is the difference between maven release and maven assemblies plugins?

Question says it all, I believe.
Please and thank you
GC
The Maven assembly plugin is dedicated to create highly customizable package, such as zip, tgz... files. You define, in a descriptor, the content of the final package (or assembly), by including files, directories, dependencies, etc.
The Maven release plugin is dedicated to the release process, which includes several repetitive manipulations and operations. For example it will do some checks (is there any uncommited changes, some SNAPSHOT libraries used and so on), prepare your Source Control Management (CVS, Subversion...), modify the pom versions (to get rid of the -SNAPSHOT), commit the modified pom.xml, etc.
You can have an example of a release process here.
EDIT
Regarding your question about -SNAPSHOT. For Maven, a fixed version is linked to a dependency that never changes. For example, two libraries with the same fixed version must be identical. So for example, foo:bar:1.2.3 is strictly identical to another foo:bar:1.2.3
This is not necessarily the case for a -SNAPSHOT version. The SNAPSHOT keyword indicates that the current library is under development. Thus, two versions of foo:bar:1.2.3-SNAPSHOT and foo:bar:1.2.3-SNAPSHOT may not be identical. A timestamp is used by Maven to check which one is the newest.
So in the normal release process, you have your 1.2.3-SNAPSHOT version, which is not in development anymore. So before releasing this library, you will have to fix the version, i.e. move your pom.xml version to 1.2.3.
This modification can be done by simply modifying the pom.xml versions, or it can be managed by the Maven release plugin (or also with the Maven version plugin).
I hope the explanations are now clear regarding this particular aspect of Maven.

Maven dependency management

Our project has a dependency like
<dependency>
<groupId>apollo.components.cots</groupId>
<artifactId>cots-wfs</artifactId>
</dependency>
And as far as I understand, maven2 will get the latest artifact for cots-wfs, say <version>2.3-20101111.000000-13</version>
The problem is, when we branch the project, the dependency stays the same, and when other developers release a new cots-wfs say <version>2.3-20101222.000000-13</version> which is not backward compatible, the build is broken.
I am trying to avoid merging the code into the branch, which is painful.
So what do I need to do to "freeze" all the dependencies when I branch the project ?
Is there any easy way to do this?
And as far as I understand, maven2 will get the latest artifact for cots-wfs, say <version>2.3-20101111.000000-13</version>
It looks like you are using a SNAPSHOT dependency for cots-wfs (2.3-SNAPSHOT), probably declared in the dependencyManagement section.
The problem is, when we branch the project, the dependency stays the same, and when other developers release a new cots-wfs (...) which is not backward compatible, the build is broken.
Indeed, which is why you should simply not branch an artifact with SNAPSHOT dependencies, the build of released artifacts should be reproducible, for ever, and using SNAPSHOT dependencies defeats this. The maven release plugin actually forbids releasing a POM having SNAPSHOT dependencies.
It is however possible to "lock" SNAPSHOT dependencies using versions:lock-snapshots or, even better, to use the corresponding released version using versions:use-releases. This is actually the way to go.
By the way, the Maven Release Plugin might help to automate the whole process.
When you branch means in a sense you are creating a new version of it. Promoting the version number should solve it.
Yeah just add the version tag to the dependency. If your unsure what the current version number is than run "mvn help:effective-pom" to see the pom with all current version numbers.

maven deploy changed artifacts only

I'm using maven 2.2 with nexus 1.4.0
Let's say I have a pom-structure like this (with corresponding versions)
parentproj, v1.0.1
- childproj1, v1.0.2
- childproj2, v1.0.7
childproj1 and childproj2 represent different parts of the application (e g gui and backend) and I want to be able to keep their versions separate so that I can release a new version of the backend without having to release a new version of the gui.
Now, to deploy this structure to Nexus it would be convenient to go to parentproj and say
mvn deploy -DperformRelease=true
which would deploy all artifacts to the Nexus realease repository. This works fine the first time I deploy it, but the second time I run into problems: let's say that I made an update to childproj1 so that we now have the following versions:
parentproj, v1.0.1
- childproj1, v1.0.3
- childproj2, v1.0.7
In this situation Nexus will not let me do mvn deploy from parentproj, since it already has a copy of childproj2 in the 1.0.7 version. Nexus will say "Resource, illegal request:Repository with ID='releases' does not allow updating artifacts." This is fine, I don't want to update existing versions by mistake.
But I guess that what I would like to do is to be able to tell maven something like "deploy only those artifacts that have versions that are not already present in the release repository".
Is there a way to do this, or would I have to deploy each project by itself?
In my experience, it has been easier to deploy everything, and often use the same version number for all the components. For example, if my team is working on version 1.0.7, all the submodules have the version number of 1.0.7-SNAPSHOT, until we release, even if no code has changed in certain modules. Then when we deploy, we would deploy the whole application. I think it has several advantages over a piecemeal deployment. First, if you every have to rollback to the last stable version, you just have to rollback to 1.0.6 for all modules--you don't have to remember that the backend was 1.0.3 while the GUI was 1.0.6. Second, it ensures that all the components are compiled correctly against each other and have been tested as a logical group.
Sorry, I know this isn't a specific answer to your question, but, at least in my team's case, it was useful to think slightly differently
First of all, I think you should distinguish between parent project and aggregation project. Parent projects should be used for those settings that are common to several projects, e.g. dependencies' versions; aggregation projects should be used in order to build at the same time a group of projects, e.g. a set of jars and the war that includes them.
The two kind of projects are best kept separated. The parent project usually does not change very often and when it does it is usually best to release new versions of all the projects that depend from it; the aggregation project's only purpose is to drive the build of a bunch of projects, so its release number should probably change whenever one of the projects it contains needs to be released.
Once you've separated parent from aggregator you're in a better position to choose whether to follow John Paulett's advice and keep everything at the same version number or to try and change each project's version number only when you actually need to release it. The first option is simpler and less error prone, but causes you to release new version of libraries that haven't changed. This might not be acceptable if, for instance, you need to ship patches rather than full releases. The second option is more complicated and error prone, but causes your release numbers to match the evolution of your software. The Maven release plugin and the Jenkins continuous integration tool may be of help there, I think you should check them out. Also, see if you can upgrade Maven to at least version 2.2.1 and Nexus to a more recent version.
I would suggest you Artifact Exists Maven Plugin (https://github.com/chonton/exists-maven-plugin). This wonderful thing requires only to be mentioned on the parent.pom, and will automatically skip the install and deploy phase for all release artifacts, that already exists in repository (Nexus or Artifactory). And still deploy the Snapshots (this is configurable).
Example:
<plugin>
<groupId>org.honton.chas</groupId>
<artifactId>exists-maven-plugin</artifactId>
<version>0.0.6</version>
<executions>
<execution>
<goals>
<goal>remote</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
I would suggest that if you plan to maintain, build, and deploy the modules independently, you should consider setting up separate CI and mvn deploy jobs for each. Having independent mvn deploy jobs will give you the behavior you are looking for out of the box. This means not using the aggregator pom (parentprj) to attempt building and deploying these modules.
If you want to do everything from the aggregator pom, like build and deploy, then I would suggest following John's answer and keeping all the version number in sync.
It just depends on how your team wants to look at the code base. If you want to keep things in a true modular fashion, you should be using your maven modules like building blocks, treating them differently, until you are ready to put the whole app together. If your app is more monolithic in nature, treat it as so and keep things in sync. This doesn't mean you still can't break out separate maven modules for maintaining code-base modularity, just recognize they don't have any value outside the context of your larger app.
A good way of making this decision is asking yourself "Will any other projects/apps need to reference this module as a dependency?". If so, it is best practice to build, version, and deploy it independently. If not, I don't see any pitfalls to making the versions match up.
Clearly this need is not addressed by maven, neither by Nexus or archiva.
For now it can only be addressed by additional tricks setup by the build manager like the ones suggested in previous posts.
In an ideal world
the pom would include
. both the release version and the snapshot version of the module
. a definition of the files which, if changed, justify the use of the snapshot version
. the source control management system reference of the released module
dependent modules poms would add in the appropriate dependency section the release version info next to the snapshot version info so that it links to the snapshot library if present in the repo and the release library otherwise
the maven reactor would have an option to read both the dependency hierarchy and the file changes info (scm diff) to know whether a given module is to be used in its release or snapshot version.
the release plugin would by default skip the releasing of the modules whitch still can be used with their release version based on the file changes and the dependency info.