Search code examples
continuous-integrationcontinuous-delivery

Build versioning in continuous delivery


I have some concrete questions about versioning in Continuous Delivery. I think I understand global workflow that more or less is this:

1) Code
2) Push to version Control
3) Continuous Integration (unit, integration and end-to-end auto testing)
4) Artifacts deployment

What about versioning? How manage build versions?

Let's say that we are working on a Maven-based project with semantic versioning: major.minor.build.

When developer commit changes to VCS and CI server perform a build, should CI server increment the build version and create a tag in VCS?

Is this build version present in the source code? If so, after each push to VCS, developer should update the project, since CI server committed changes (version increment) on project.

I'm a little confused and I would like to understand the CD workflow in a practical way.


Solution

  • In general you should have:

    1. A manually managed version number.
    2. Any number of "reference" numbers.

    The first point is crucial if you care about semver or in case you have to provide compatibility information for other tools/libs. It's only you who can tell whether a new "release" breaks anything - the most popular indication system is following the semver versioning rules.

    The second point ("reference" number) might or might not be important for you. You usually don't need more than one, the CI/CD build's version number (every popular CI/CD service has a build version number ID which refers to that specific "build"). The point of this number is that you can quickly check the related CI/CD build/logs of an artifact if you need it.

    How to merge the two (or more) parts?

    It's not uncommon to have separate "version" and "build" numbers. In fact every iOS project have that by default. In that case you have the "version" number managed manually, and a separate "build" number managed automatically. The build number can be in the artifact's name, or can be printed when someone retrieves the --version information in case of a binary (ex: $ brew info -> 0.9.5 (git revision 18c48; last commit 2015-11-02)

    Alternatively you can either add new components to semver (x.x.x.BUILDNUM), use the last component of semver (x.x.BUILDNUM - I wouldn't recommend this if you have a strictly incremental BUILDNUM) or simply include the "build" number in the name of the artifact.

    These are all possibilities, you'll have to pick the best one for your case. You have to define the meaning of these numbers and decide where the number should be presented (e.g. should it be part of a --version call or should it be just part of the filename).

    edit: to reflect on your question about "should CI server increment the build version and create a tag in VCS?" - I would never recommend this. A CI server can have issues too, you should never modify your code from a CI process. Accidentally overwriting (e.g. force pushing) something can be really dangerous. That's why it's better to just use the Build Number exposed by the CI/CD service.