Saturday, May 23, 2020

Inject Version in Maven Build

When it comes to code versioning and deployments, it is always a good idea at the very beginning of the project to come up with a release strategy and branching/tagging nomenclature that works well for the team.  This makes it easier to enforce good habits throughout the life of the project.

On most if not all of our projects we use git for code versioning and Jira for project management; to help keep tabs on what features are in which release, we use feature branches where the name of the branch is also the story id in Jira. For example, if you are assigned Jira story 'ABC-1234', then that is also the name of your feature branch.

This approach makes it not only easy to track which features are in a given  release, but helps those doing a code review and performing QA tasks understand what the given branch should do and understand better how to test it.

When it comes to releases, I typically prefer to go with a release branch strategy versus tags. For example release candidate 1.0.12 would be branch 'RC-1.0.12'.  The format is pretty simple, this release branch can then be added to your Jira stories to better keep tabs on what features are in each given release. While it may just seem like a bit of extra work, at some point during the lifecycle of the project someone will have a need to find out when a certain feature was introduced into the codebase, who requested the change, and who coded it.

Ok, so now that we have laid out the basics of our branch names and their meanings, this brings us to actually versioning our maven builds. There are a number of different ways to do this, one I see a lot is Release Managers manually updating the version number in the pom.xml files. In a multi-module project this can be tedious. Of course they then usually commit the update back to the git repository, then build the code.

Unless there is a strong need to have the version number updated in the release branch, there is an easier way by leveraging the Maven versions plugin to do the work for us.  To execute a maven build and set the version we would do something like the following:

mvn versions:set -DnewVersion=1.0.12 clean install
Pretty easy, but if the release branch already contains the version number, why type it in? Manually typing in version numbers could lead to human error and inconsistencies.

We can further automate this by writing a short script to parse the version number out of the branch name.

Each build tool uses different variables to make the branch name available to our script. If you are using Jenkins you can use the ${GIT_BRANCH} variable. If you are using Bamboo, you can use the ${bamboo.planRepository.1.branchName} variable to get the branch name.

Now that we have a way to get the branch name, we need to write our script to extract just the version number, store the result in a variable that can then be passed to our maven command.

While there are a number of ways to do it, for this example we will use sed in our script. Notice in the script below everything after the equals sign is enclosed with a backtick. We do this so that when the command is interpreted the results are written to the variable 'version'. We can then use the version variable in the maven command.

version=`echo ${GIT_BRANCH} | sed -e 's/.*-\([[:digit:]]\{1,\}\(\.[[:digit:]]\{1,\}\)\{1,\}\)/\1/'
mvn versions:set -DnewVersion=${version} clean install
Now we are all set, when we run our build job, it will automatically update the version in the pom.xml files based on the version number in our branch we built it against.

Using ssh config

If you have ever used ssh before, you know it is pretty straightforward to connect to other servers and virtual machines,  ssh ip_or_hostname. You may even type it without even thinking about it. As your infrastructure grows and maybe some moves to the cloud  you may begin to need to also add a username and/or a different Identity file or private key.

 ssh -i /path/to/identity/file username@ip_or_hostname

Still pretty straightforward, it is a bit more to type out which can be annoying and slow you down when you are in a hurry.  We could simplify this a bit by adding an Alias for this command. Then we would just type our Alias and let the system handle the rest. Then all we need to remember is our Alias that we created.

What happens when the number of virtual machines you are supporting increases dramatically. What if many of those servers are for production and lower environments hosted by multiple clients. Add to that multiple git repositories for those clients as well. You can very quickly end up with quite the number of Identity files and keys to manage. If we are creating Alias commands for each of those virtual machines you will have to come up with a snappy way to remember all those Alias commands.


An alternative would be to take a few moments and add the entries to a ssh config file on the machine we are connecting from. By default OpenSSH doesn't create a config file iin your profile or home directory, but we can manually add it there.

Using your favorite text editor, create a file called 'config' in your .ssh directory. By default OpenSSH will automatically look for this file

vi ~/.ssh/config

Now we are ready to add our entries using the following format for each entry:

# This is a comment line
Host clientADev
HostName devserver.example.com 
User myUserID 
IdentityFile ~/.ssh/clientA-dev.pem
Save the file, and now we can ssh using the following command:

ssh clientADev

OpenSSH will find that host in our config file and use the HostName, User, and IdentityFile we specified to make the connection.

But what if we have a dev environment with more than 1 server and we use the same credentials for all of them. We can specify multiple entries by hostname or ip in the Host line to account for this.


# This is a comment line
Host 123.345.789 789.475.123  67.234.123
User myUserID 
IdentityFile ~/.ssh/clientA-dev.pem

Now when we ssh to any of the hosts listed OpenSSH will automatically use the proper credentials, and we no longer need to type long commands or remember which creds go to which server(s).

There are many other options we can add to the config file to better control and configure our ssh client. For more on that you may want to review the man pages on this topic.