Build versioning in continuous delivery

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.


What about versioning? How manage build versions?

The same way you would otherwise; when producing an artifact to be distributed (either to the cloud or via floppy disk) the artifacts and components should be marked with a unique and traceable version number. This number should be directly correlated to the source code that created it. We do this because it helps us to fix problems correctly in production systems, trace program behavioral changes, and a few other support/maintenance/design things. We should be doing it regardless of delivery mechanism because it's easy to do and it can save you a lot of trouble in situations where if you didn't have the ability to connect the source with the executing program, you would be making hard assumptions and guesses (with your job and/or reputation on the line).

So please ignore the advice given in another answer about not tagging your repo - Always tag your repo.

Also whenever you can, try to make sure the version number that is generated for the build to use is getting set on the program executables or libraries that are being built.

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?

Most build systems have the facility for versioning or numbering, Maven included. However only builds that produce the artifacts that get deployed should be assigning version numbering and tagging repos. Usually this will exclude Continuous Integration/Gated Checkin builds as they are only for integrating the incoming developers changes with the main branch.