A Couple of Simple Continuous Integration Build-Revisioning Tools
What even is this?
Here’s a couple of .NET exes I built over a couple of hours to automate the incrementing of build revision numbers in
- Xamarin/Android
AndroidManifest.xml
files - .NET
AssemblyInfo
related files
Why bother?
Xamarin.Android apps contain both kinds of version resources. And I got tired of incrementing one and forgetting to do the others. And if it’s friction, or a pain point for me, I prefer to automate it away if I can.
So this is the stupidest thing that actually works.
All these utilities do is load and parse a given file name looking for specific string/regex matches. If they are able to locate the requested bits of information, they’ll auto-increment the build revision #, and write the file back out again.
And that is all they do. Their primary function is simply to operate as part of a custom build/build-tool chain, so it’s up to the developer to integrate them with their CI process (examples below).
Yes, I know, TeamCity and some other CI toolkits can do this too. I can’t use TeamCity in a couple of current projects, because ‘not invented here’. So I slapped these little guys together.
Application versions are often displayed as a set of numbers indicating
major_version.minor_version.build_#.build_revision
This is usually displayed in the format: 1.0.1.2
or 1.0.2.0-alpha
or something similar. Normally what happens when you (re)build an app, these would be incremented automatically for you. Some “increments” aren’t actually increments. They could be git commit hashes, timestamps, you name it.
In the case of these utilities, all they do is try and locate something that looks like a set of numbers like this, in a file you specify. And if they find it, they’ll increment the build revision # (the last number in the quartet).
For example, if the existing version # is 1.2.3.4, then running these utilities will simply update that last digit to 1.2.3.5.
Yes, they could do so much more, and I’m sure you’ve got a million ideas about how yours would be 10x more awesome. But this solved an immediate problem I had.
AndroidManifestUtil (for AndroidManifest.xml files)
This updates the AndroidManifest.xml
file commonly found in Android and Xamarin.Android projects.
Normally when you build your Android app, you have to provide two version values, a version code (versionCode
in the manifest file) and a version name (versionName
in the manifest file).
The versionCode
value is a single integer used by the Google Play store to determine whether the app is a newer version than one it already has.
The versionName
is a set of numbers (and perhaps other identifiers), as described above, which you can use for “proper” version tracking in your app; maybe for analytics or crash reporting or something else).
AndroidManifestUtil
extracts the versionName
attribute from the manifest
xml node, tries to parse it to extract the 4 numbers, increments the last one (the build revision), and writes it back to the file.
It will also extract the versionCode
attribute from the manifest
xml node, increment it, and writes it back to the file.
The Google Play store depends on this versionCode
attribute to know that you’ve updated your app in the store, but the numbers don’t need to be sequential. As long as your new version has a higher versionCode
value than the previous one, that’s cool.
If you’ve got some funky version numbering you do (e.g. ‘1.0.rc-02.02Jan2014’), then you’re on your own.
Usage
Theres’s a test AndroidManifest.xml
file in the project folder which looks something like:
As you can see, the versionName
is set to 1.0.2.0.
Run the utility from the command line (or script):
It’ll give you some basic info about what it’s doing, or if it’s got a problem:
…and now it looks like:
AssemblyInfoUtil (for updating .NET AssemblyInfo-related files)
This updates the AssemblyVersion
and AssemblyFileVersion
values commonly found in AssemblyInfo.cs
(or global/shared versions of them) in .NET projects.
It simply opens the file you specify (as text), and searches for for the quartet of numbers. If it finds one (or both), it will parse out the build revision #, increment it, and then write it back to the file.
Usage
Similarly to the AndroidManifestUtil, simply point the -filename
parameter at the file containing the version strings you’re interested in updating:
Run the utility from the command line (or script):
(it has a ‘.txt’ extension because Visual Studio kept trying to compile it into the application, and then couldn’t write to it when running the debugger :)). This won’t be a problem when you point it at a ‘real’ file from a command line.
This file will look something like:
With the result:
And that’s pretty much it.
Sure, they can be tweaked to add flags for turn this on, but don’t do this, or ignore this thing and do that instead. But this was the simplest thing that actually worked, and did exactly what I need it to do.
So where is it?
The source code (as always) is on GitHub at https://github.com/wislon/ci-build-revision-utils.
Thanks to Josh Quintus for spotting that I’d forgotten to put the link in!
Build Loops
Be careful when you integrate this kind of thing with CI servers or services (like TeamCity) that commit, push and pull code changes, and rebuild on new changes that appear in your source control system.
If your build script increments the number (as it’s supposed to), and then pushes the update back to source control, and your source control triggers a build because of the new code change, you may end up in a build/commit/push/trigger/pull/increment/build loop.
A hypercube? I can’t even…
This is not your build server’s fault. Nor your source control’s. But it’s not always an easy fix. One of them has to be told how to ignore the other in certain cases, so it doesn’t start the loop.
…and in the spirit of “I needed this now, and since I’m publishing it for me, I may as well put it up for other folks”, Andrew Harcourt (@uglybugger) provides a possible solution over at https://teamcity-github-filter.azurewebsites.net/.
License
The utils in this repo released under the free-for-all MIT License, so if you want to copy it and do better stuff with it, you go right ahead! :)