How to update version in non pom files using maven release plugin - maven

I've a maven project and I'm using the maven-release-plugin to prepare the release.
When I run the mvn --batch-mode release:prepare command, it creates two commits as follows
(HEAD -> develop) [maven-release-plugin] prepare for next development
iteration
(tag: myapp-1.0.0) [maven-release-plugin] prepare release
myapp-1.0.0
This correctly updates all the pom files.
but I've some text files in my project where there is a version token. I'm looking for a way to replace these version tokens appropriately as per the commits.
For example, the prepare release commit should replace the token to 1.0.0 and prepare for next development should replace the token to 1.0.1-SNAPSHOT
I've checked the documentation but didn't find any way to do this. If somebody has any ideas on how to achieve this through maven-release-plugin or with the help of any other plugin, please suggest.
EDIT:
This issue is not solved even if I place the files inside resources directory. The thing I've observed is that the release plugin only selectively adds the pom.xml files in the commit, not other files even if they are modified gets added into to the commits pushed by release plugin.
Let me clarify I am not looking for replacing version in the source file and have it replaced in the generated artifact. We can argue about why there is version field in non source file, but there are genuine scenarios anyone can think of.
As a developer I want that the release commit made by the maven release should be accurate i.e. It should contain all the changes associated with that specific release version.

As khmarbaise said: Use ${project.version} in the respective files, put them into a resources directory and use filtering.

Related

should I use release:prepare before release:perform?

My regular CI build takes 1 hr and a release build takes 2 hrs. Can I skip the release:prepare and directly do a release:perform to save time? What will I miss?
Any other way to decrease the release build time if I cant skip this?
Thanks
Nube to mvn
The short answer is no you can't skip the release:prepare goal. If you want more then read on.
From the maven release plugin documentation:
Prepare for a release in SCM. Steps through several phases to ensure the POM is ready to be released and then prepares SCM to eventually contain a tagged version of the release and a record in the local copy of the parameters used.
What this actually does is the following:
Modify all your x-SNAPSHOT versions to simply x. So 1.0-snapshot will turn into 1.0
Build everything to make sure this still compiles and tests after the version change
Commit the changes (And tag them in your SCM)
Upgrade all the versions to the next SNAPSHOT version, in our case 1.1-SNAPSHOT
Commit this new change
An intended by-product of this process are files with the poms to be built for the release:perform goal, so that's why you can't skip the release:prepare.
If you're still interested in shortening your build time, and do not care for all the commits to SCM you can implement your own release mechanism (which I do not recommend) using maven-versions-plugin and maven-deploy-plugin. See this for details.

How to allow any version in Snapshot repo

We're building feature branches into a version 'feature_'. Each feature build will produce the same version. Since these are no releases, I want to deploy the artefacts into the Snapshots repo, but Nexus does not allow versions without 'SNAPSHOT' into the Snapshot repo.
How to configure Nexus to allow any version in a repo?
Solved it by appending '-SNAPSHOT' to the branch version.
It's quite tricky to get Maven in Jenkins to use the right version. The way I solved it now is like this. In the build job configure Git to build the branches origin/feature/*. Then:
In the 'build' section, first thing to do is execute a shell command to construct a file 'env.properties' containing the feature branch version to be used by the Maven build command.
echo BRANCH_VERSION="feature_${GIT_BRANCH##*/}-SNAPSHOT" > env.properties
This uses the GIT_BRANCH environment property of Jenkins. The '##*/' is a Bash Shell Parameter Expansion which strips everything from the parameter value except the part after the last '/' character.
Then use the Environment Injector Plugin to 'inject environment variables' to the build job using the 'env.properties' created in the previous step.
Put 'env.properties' in the 'Properties File Path' field.
Use Maven to build a versioned pom with the correct version using 'Invoke top-level Maven targets':
help:effective-pom -Dbuild.number=${BRANCH_VERSION} -Doutput=versioned-pom.xml. This step is necessary because otherwise the pom in the jar artefact does not contain the correct version causing other problems.
Use another 'Invoke top-level Maven targets' step to do the actual build and deploy using the pom version created in the previous step: -f versioned-pom.xml clean source:jar deploy
That's all folks. If anyone knows a simpler solution, let me know.
This is actually a Maven restriction. You can still use version like feature_x-1.2.3-SNAPSHOT though.
What are you actually trying to achieve though?

Why does release:prepare change versions back to SNAPSHOT?

I'm using the maven-release-plugin and I'm noticing that it appears to change the released version BACK to -SNAPSHOT at the end.
Here's the command line args that I'm passing to maven:
--batch-mode release:prepare -DupdateWorkingCopyVersions=false -Darguments="-DskipTests -Djava.awt.headless=true -Dmaven.javadoc.failOnError=false"
Everything appears to go well - and I notice a commit and a push from the plugin where all of the proper version numbers are indeed updated to NOT have the -SNAPSHOT.
[WARNING] Ignoring unrecognized line: ?? myProject/pom.xml.releaseBackup
I see a few of these warnings ^ in the log file (not sure if this is relevant, but appears to be related to the release plugin)
Finally I see that the plugin modifies the POMs again:
[INFO] Transforming 'myProject POM'...
[INFO] Updating my-project to 6.2-SNAPSHOT
Following this the plugin makes and pushes a commit with the following:
[maven-release-plugin] rollback changes from release preparation of myProject-6.2
Why is this last bit happening?
I don't understand the lifecycle of release:prepare or release:perform. Why does all of my code appear to be built twice?
Any help appreciated. Thanks
As I understand it, release:prepare
Updates the POM files to the version that was specified
performs the build, which runs the tests
performs other validations (ie, no dependencies to SNAPSHOT artifacts)
Commits the changes (which should be restricted to the POM files and their versions)
Tags the source that was just committed
Updates the pom files back to the nominated SNAPSHOT version
Commits those changes
Note: I'm not sure if that's the specific order. The above list is not an exhaustive list, it's just my recollection.
At this point, the release doesn't exist. That's what release:perform does. Release:perform checks out the code against the TAG and builds the artifacts against the tagged source.
This is why release:prepare moves it back to the snapshot version. It's simply preparing the source to have a release built against it. Developers working on that branch, once the tag is cut, can continue to commit changes without affecting release:perform. It also allows a release to be re-cut at a later date, as it is built against the tag.
Of course, there are variations to this plugin which is documented. But, as I understand it, this is a common workflow for this.

Maven Release: Prepare/Perform after Rollback incorrectly succeeds with wrong content

We use Maven with Subversion internally. We also use Maven's Release plugin. We noticed the issue described below when running through the following (correct, I presume) steps.
1. We run release:prepare:
Maven updates the trunk version to 1.0.0.
Maven runs svn copy trunk/myproject tags/myproject-1.0.0, thus creating tag myproject-1.0.0.
Maven updates the trunk version to 1.0.1-SNAPSHOT.
2. We run release:rollback:
Maven resets the trunk version to 1.0.0-SNAPSHOT.
Maven does not remove the tag, because Maven doesn't do this kind of stuff.
3. We commit more changes to trunk, obviously against version 1.0.0-SNAPSHOT.
4. We run release:prepare again:
Maven updates the trunk version to 1.0.0.
Maven runs svn copy trunk/myproject tags/myproject-1.0.0, thinking it created tag myproject-1.0.0 out of the latest trunk. But, alas, Subversion (1.6 and 1.7 alike) will instead create tags/myproject-1.0.0/myproject on Maven's behalf.
5. We run release:perform:
Maven checks out the contents of tag myproject-1.0.0.
Maven builds the contents and deploys the result to Nexus.
The problem is obvious: the change in step 3 did not make it into the tag. We are now releasing 1.0.0 without the change in it.
The questions are: How can we fix this? Is Maven's release rollback feature inherently broken?
In fairness, rollback should reset the project and SCM to a state that allows a second prepare to occur. This includes removing the tag. The answer is now apparent (Googling "maven release rollback remove tag"):
http://maven.apache.org/maven-release/maven-release-plugin/examples/rollback-release.html:
The created branch/tag in SCM for the release is removed. Note: This
is not yet implemented so you will need to manually remove the
branch/tag from your SCM. For more info see MRELEASE-229.
The resolution would then be to force release:rollback to include a command to delete the SCM tag using something like org.codehaus.mojo:exec-maven-plugin. Short of this, wrap rollback inside a script that does that externally.
As you've discovered, release:rollback doesn't have a whole lot of utility when it doesn't clean up SCM. What our shop has done is setup our Jenkins automation to run "mvn release:prepare release:perform" in combination with the Jenkins M2 Release Plugin.
If it fails we need to delete the tag in Subversion but, then again, we would have to do this anyway with rollback.

maven release perform failed

Today while doing the release of our project, the release:perform command failed in between as our nexus was having intermittent issues. The release command only able to upload one pom file to nexus.
Now, the nexus issue is resolved and I am trying to do the release, it fails as the pom file already exists and its not the snapshot version and we don't have access to nexus so that I can delete that file and start over again.
Is there any way I can pass an argument so that release:perform should continue if the file is already there and ignore this but continue with uploading the rest.
I have looked for options of such type but didn't find anything.
My last resource would be to start the release again, which will bump the version number, but would like to understand if there is any other approach where in I don't need to bump the version.
I am using maven 2.2.1
Here's how I have handled this in the past. The release:perform command does a checkout of the tag from your SCM provider (e.g. SVN). This is done in the target/checkout directory of that project - whatever is there should be an exact copy of the released tag, so it will have the right version number in the pom files etc.
If you move to that directory (target/checkout in the directory where you started the release), you can simply do a mvn deploy there and it should compile and package that version, and then upload it to your Nexus instance.
If you don't have the target/checkout directory, you can check out the Tag created as part of the release:prepare phase from your SCM system to a fresh directory and run mvn deploy there.
Since the tag in your SCM has already been created, the only thing that's left is really compiling, packaging and deploying the release, which is exactly what mvn deploy should do.
If you have provided additional parameters (e.g. for activating profiles) for the build during the call to mvn release:perform, you will have to provide these as well when you run mvn deploy.
Using this approach, your version number will not have to change, it can stay the same, since you're just uploading what has already been tagged as part of mvn release:prepare.
My advice would be for you to request from the admins that the old artifact be removed. You can either re-deploy the code from the tag by checking it out and simply doing
mvn deploy
Or rolling back your release:
mvn release:rollback
And re-doing it as usual.
It is essential to remove the old artifact from the remote repository, if the sizes do not match. Release repositories do not allow the redeployment of artifacts, unless this has been explicitly switched on on the server side.
Furthermore, #nwinkler's answer is also quite good.

Resources