continuous integration – How to deal with SemVer in a build number based company

My company uses Major.Minor.Patch.Build for our version numbers. When a new release is started, the Major.Minor.Patch part is set. Then as work is done, the build number goes up until a build is deemed good enough. When that happens, then that Major.Minor.Patch.Build is released to Testing. If it passes Testing, then I goes on to prod. If it fails testing, then it will go back to development, and the next attempt will increase the Patch number by 1. (New version numbers and builds only happen while the release is in the Dev part of the process.). This all works fantastic for my company.

But now we are trying to move to containers, Helm charts and Kubernetes. This ecosystem seems to really love SemVer V2. As I am trying to grapple with this situation, I see two options to get build numbers into SemVer V2:

  1. Put it into a prerelease tag. Something like: 1.3.2-build.21. This works, but it is considered a “prerelease” build. So if I just use it as a normal build, then version precedence will always favor 1.3.2 over 1.3.2-build.589. This seems ugly (and prone to errors).

  2. Put in the metadata. Something like: 1.3.2+build.21. This is no longer prerelease, but 1.3.2+build.21 is considered the same as 1.3.2+build.589 for version precedence.

I can kind of understand what SemVer V2 is attempting here. From my consumer’s point of view, the build number is extra detail. (A consumer of my software should never see two Major.Minor.Patch versions of the application that are different.)

But my dev teams need to keep it clear which build is which. So just using Major.Minor.Patch alone is not going to work.

And our CI/CD pipeline tools do automatic sorting and picking based on SemVer V2 precedence. So the meta data approach is not going to work.

I don’t like the idea of using prerelease builds a normal releases. So I have eliminated that from full use.

Another option is to use Major.Minor.Build. (Replace the patch number with the build number.) While I could do that, it would be a hard sell for my company to give up the Patch number. (And it just seems kind of wrong.)

Our processes don’t allow me to change the version number at the time we release to production. To change the version number of a tested and ready for prod build from a pre-release version number to a release version number would require one of the following:

  1. Another build (that then has to be tested again)
  2. Modifying the binaries (which then have to be tested again)

(I work in a medical field where mistakes can be really bad, so we have some strict testing rules.)

Right now I am going for a “fake it” approach. On surface we are still using a Major.Minor.Patch.Build. But integrate with my CI/CD tools, I am attempting to fake them out. I give them a container image that is tagged as prerelease for a deployment to Dev. And I build my helm chart dynamically at deploy time.

When I deploy to Test, I am adding another tag to the container image (the release version number). I again create a dynamic created Helm chart for deployment (this time using a release version number). I repeat the dynamic helm chart for the production deployment.

Dynamic helm charts, on the fly retagging during deployments… It all feels a bit ugly. But I can’t see any way around this consumer focused limitation in SemVer V2.

But I got to thinking, maybe I am not the only one with this issue. Maybe someone already has a solution. So I thought I would ask:

How can can one deal with SemVer V2 integration in CI/CD tools and yet still use a build number in your development and deployment processes?