How to version your app in a continuous development world

Let’s focus on build version numbers

Katie Barnett
Bilue Product Design & Technology Blog

--

Additional content and iOS guidance provided by Daniel Slone

Graphic by Jason Wall, with inspiration from here

The advice on how to manage the release versions of apps is clear, the best course is to follow semantic versioning rules. As a revision, these boil down to:

  • Major version numbers change whenever there is some significant change being introduced such as:
    - A large or potentially backward-incompatible change
    - Major new feature introduction
    - New design or UI
  • Minor version numbers change when a new, minor feature is introduced or when a set of smaller features is rolled out
  • Patch numbers change when a new build of the software is released to customers. This is normally for small bug-fixes or the like

What the version number used and what the sequence should be (e.g. should 2.10.0 roll over to 3.0.0 — not according to the semantic versioning rules!) is usually up to the individual project and may be adjusted to keep app platforms or other systems in line (e.g. ensuring all major & minor versions are the same on related iOS & Android at any point in time).

For Android, the semantic version is different to the version number that is used when determining whether a particular version of the app can be installed over another version. The semantic version is the versionName and the version number is the versionCode.

In iOS, the semantic version is the same as the version number that is used.

Build Number Versioning

There is then usually need to have a more precise version numbers for each individual build so developers, clients and QA team members can identify the exact code that the build contains between releases to end users. Usually this is referred to this as the Build Number.

This can be expressed in written form as A.B.C (X) or A.B.C.X (where A is the major version, B is the minor version, C is the patch version and X is the build number).

The most important thing to keep in mind for this is that the build numbers should be increasing so that subsequent versions can be installed over previous versions. For Android, the build number should be the versionCode and is set in the build.gradle file. For iOS, the build number should be the Bundle version and is set in the Info.plist .

There are many ways in which these numbers & number sequences can be determined, below are some examples.

Manual Increase

This can be as simple as whenever a change is committed / pushed to the codebase the build number must be updated to ensure the app can be updated over previous versions.

Advantages:

  • Can be kept in line with other versioning systems
  • Can squash multiple commits into the same version (but then you may get conflicts or uncertainty in what is in the build)
  • Probably only useful when QA builds are created rarely (in this case, probably best to just use the patch number)

Disadvantages:

  • Relies on the developer remembering to do this when committing code
  • Can get conflicts between multiple developers committing to the same version or using a different update schedule
  • If multiple commits are going into the build for each version number you may get uncertainty as to what is in the build if the CI/CD is run automatically and doesn’t require a version change

Git Commit Number

This can be set up in your build scripts to use the git commit number to generate a build number.

Android:

In the app level build.gradle

Note here the line def initValue = 1, in this, the 1 can be increased in case there is a release of code that does not include the most recent of git commits (e.g. a bugfix release to a current release while the next release is well underway). Increasing this value would be done to ensure the bugfix release build number would be greater than the current underway work.

iOS:

When using Fastlane, in the fastfile

These methods will calculate the current git commit revision number and use that in constructing the build number.

Advantages:

  • Automatic, no need for developers to think about it & little chance of collisions
  • Can carry over between CI/CD systems
  • Does have the ability to override for hotfix releases

Disadvantages:

  • Hotfix releases can get a little complex and may require some manual intervention (see Android note above)
  • The number can get large fast in a well maintained or large app (thousands) and may jump by quite a lot (will rarely be sequential)
  • You may have an issue when running the build when the code is not connected to git, the build scripts must have checks enabled to replace variables that don’t exist by valid replacements (this could occur if you have given someone a zip of the code rather than them cloning the repository)

CI/CD Generated

This can be set up so the CI/CD build number is either queried by the build script or injected into the build script.

Environment variable queried by the build script

Using Bitrise as an example (most CI/CD systems will also expose an environment variable that can be used — just check the documentation for the variable name of your chosen CI/CD system) you can use the build number environment variable that is directly tied to each build. A different environment variable could be used that only increases on pushes to certain branches or execution of certain scripts if needed. You can also add extra logic if needed to manipulate this number.

Android:

In the app level build.gradle

Note, as with the git commit method above, the init value here can be manipulated to support hotfix builds as needed, but it is not necessary as just completing another build of your hotfix code will increment the build number.

iOS:

When using Fastlane, in the fastfile

Injected into the build script from the CI/CD system

This can be done by tools available on the CI/CD system or by scripts that will look for the versioning information in expected files and modify them (and could also commit them back to git) before running the build.

This can be done in Bitrise as an example by adding to the workflow Change Android versionCode and versionName step for Android or Set Xcode Project Build Number for iOS.

There is also the ability to add an offset if it is needed when migrating from another CI/CD system to Bitrise. But usually your options are limited on how this value can be manipulated.

An advantage of this choice is that the build script does not need to be modified specifically for any particular CI/CD system (the CI/CD will make the change on their end).

Again, most other CI/CD systems have similar configurations that will allow a build number to be injected.

Advantages:

  • Automatic, no need for developers to think about it & no chance of collisions
  • Will support hotfix releases (may just require an extra build)
  • Numbers should be sequential — although this may not be the case if PR builds are also run through the CI/CD and count towards the build number — see use of different environment variables above.

Disadvantages:

  • Will not carry over if the CI/CD system is changed, some migration or resetting of build numbers may be required (not a bad thing as long as everyone is aware and it is documented — make sure to use the semantic versioning to signify this as well).
  • You may have an issue when running the build locally on your machine (rather than on the CI/CD), the build scripts must have checks enabled to replace variables that don’t exist by valid replacements

Which app build versioning system to choose?

We did a little non-scientific survey amongst the dev team at our company Bilue and found that most of the team were using CI/CD generated build numbers on the projects they are working on. My experience has been pretty much split by git commit number generated and CI/CD generated build numbers.

Ultimately the choice is yours to make with your app development team. As long as everyone is aware of what the system is and it fits into your development and QA flow and it is consistent then you should have no problem ensuring your build numbers always go up!

More Information

--

--