Purpose build metadata in SemVer? - semantic-versioning

In Semantic Versioning
https://semver.org/#spec-item-10
Build metadata MAY be denoted by appending a plus sign and a series of dot separated identifiers immediately following the patch or pre-release version. Identifiers MUST comprise only ASCII alphanumerics and hyphens [0-9A-Za-z-]. Identifiers MUST NOT be empty. Build metadata MUST be ignored when determining version precedence. Thus two versions that differ only in the build metadata, have the same precedence. Examples: 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85, 1.0.0+21AF26D3—-117B344092BD.
What is the purpose of including build meta?
What is the difference between the commit 1.2.3+abc and 1.2.3+bcd?
In what kind of scenario including build meta data will help?

This is mostly for information purposes. You can encode full commit id in the build metadata, so it's faster to analyze from what commit this software was actually build on, or you can encode the date/time of the particular build, machine it was build on.
The version usually only increments when you do a proper release. While developing the application, the version remains unchanged. But the commit id will change with every snapshot that is released to the development environment.

Related

Finding relevant info when choosing Node Alpine Docker image version

Some might view this question as an opinion based one, but please consider that I am just asking for information sources.
I am working on a Docker based project, using a Node Alpine image. Right now I'm using the node:16.13-alpine image.
When I start updating images to the latest version, I'm always at a loss as to which version to pick.
In my example, the node image page https://hub.docker.com/_/node?tab=description&amp%3Bpage=1&amp%3Bname=alpine lists the following available images versions:
18-alpine3.15, 18.10-alpine3.15, 18.10.0-alpine3.15, alpine3.15, current-alpine3.15
18-alpine, 18-alpine3.16, 18.10-alpine, 18.10-alpine3.16, 18.10.0-alpine, 18.10.0-alpine3.16, alpine, alpine3.16, current-alpine, current-alpine3.16
16-alpine3.15, 16.17-alpine3.15, 16.17.1-alpine3.15, gallium-alpine3.15, lts-alpine3.15
16-alpine, 16-alpine3.16, 16.17-alpine, 16.17-alpine3.16, 16.17.1-alpine, 16.17.1-alpine3.16, gallium-alpine, gallium-alpine3.16, lts-alpine, lts-alpine3.16
14-alpine3.15, 14.20-alpine3.15, 14.20.1-alpine3.15, fermium-alpine3.15
14-alpine, 14-alpine3.16, 14.20-alpine, 14.20-alpine3.16, 14.20.1-alpine, 14.20.1-alpine3.16, fermium-alpine, fermium-alpine3.16
This list is of course an ever moving target.
Now, when picking a version out of all of these, what element can I take into consideration (short of reading every single release note for each image)?
Is there a page somewhere offering a high level view of these images, of known issues? Are some of these images designed to be "safe bets", unlikely to introduce freshly introduced bugs? I run an npm audit on packages used inside my image from time to time, but is there some equivalent tool which might alert it is time to update the node image itself, because a new bug / security breach has been found?
I know this is a pretty wide question, but I am sure there are some good practice guidelines to follow here, any pointer is appreciated.
Thanks!
The two most important things to do here are
Have good integration tests; and
Check your Dockerfile into source control.
If you have both of these things then trying out any of the images you list isn't a huge risk. Update the Dockerfile FROM line, build an image, and run it; if the integration tests pass, check in the change; and if not, revert it. If you can set up your continuous-integration system to run the tests for you then this becomes "open a pull request and wait for a passing build".
The other trade-off is how much you want an image you know works, versus an image that gets regular updates. Most Docker images are built on some underlying Linux distribution. The node:16.13-alpine image you have currently isn't in the list of images you show, which means that, if there is some vulnerability in the underlying Alpine base, that particular image isn't getting rebuilt. But, conversely, your build might automatically update from Node 16.13.0 to 16.13.2 without you being aware of it.
It also helps to understand your language's update and versioning strategy. Node, for example, puts out an major release roughly annually with even major version numbers (14, 16, 18, ...), but Python's annual releases have minor version numbers (3.8, 3.9, 3.10, ...).
I'd suggest:
If you can tolerate not knowing the exact version, then use a release-version image like node:16-alpine or python:3.10. Make sure to docker build --pull to get the updates in the base image.
If you've pinned to an exact version like node:16.13.0-alpine, updating to the most recent patch release node:16.13.2-alpine is most likely safe.
If your base image uses semantic versioning, then upgrading minor releases node:16.17-alpine is supposed to be safe.
It is worth reading the release notes for major-version upgrades.

How to use semantic versioning when compatibility differs between parts of a project

Suppose a project that consists of multiple parts
A file format definition
A library to interact with the file format
A CLI utility application that uses the library to perform tasks
I can do non-backwards compatible changes to (3) without breaking (1) or (2).
I can do non-backwards compatible changes to (2) without breaking (1), but (3) would break.
I can do non-backwards compatible changes to (1) without breaking (3), but (2) would break.
Does this mean that these parts must be different project, so they can have different version numbers?
A version string can refer to a collection of independently versioned API's/packages, a single API, an API and implementation, etc. Basically you have to be cognizant of exactly what it is you are applying a version number to, and what your customers expect. Semantic versioning is all about telling your customers about the risks you think they will take, if they accept an update from you.
From your description, I think you have three things that need to be versioned:
The file format.
The library.
the CLI utility application.
Whether you develop them in one, two or three repos is up to you. It's not uncommon for a file format specification to be developed and versioned independently of any implementations that depend on it. Whether your library and CLI utility belong together or in separate repo's is a matter of your development process logistics and customer expectations. Do you have consumers of the library that don't require your utility?
Whether they reside in one repo, two or three, you should package and version them separately. This implies independent feeds and packaging scripts.

How should inter-related software packages be versioned?

Some open-source projects make combined releases where the version number of each package(library) is increased to the same version.
Examples in Java are:
org.springframework
com.fasterxml.jackson
org.hamcrest
This implies that some packages may get a new version even though they have not changed (nor their dependencies). I don't think this violates semantic versioning.
Benefits I see is that:
Users can use a single version to monitor and upgrade
All users likely to use the same combination of libraries
Drawbacks:
Users using just one out of many libraries might be notified about an "update" though the package to download has not changed
If many users use just a sub-package, then all bug reports for one version are equally for a range of versions, which is difficult to track. Reverting to the previous "different" version to avoid a bug becomes more complex.
One alternative to single-versioning is to use a BOM (Bill-of-materials).
Different concepts of BOMs exist:
A BOM can list several dependencies to include in their versions (e.g. Linux apt Meta-packages)
A BOM can define versions (and other restrictions) for dependencies to be used if the dependency is included (e.g. Java Maven dependencyManagement section of BOM)
The BOM allows to declare which configuration(combination) of library-versions have been tested together, and allows separate groups of users to all use the same configuration, helping with bug reports and reproducibility.
Not all software distribution and buildsystems support the BOM concept equally well, though.

When using semver when to upgrade/bump to 1.0.0 (stable)

The Semantic Versioning Specification (SemVer) defines:
Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.
So starting with 1.0.0 is considered stable.
When starting a project normally version 0.1.0 is used and gradually increased, there is a point where the project can have something like 0.20.3 for months/years and it is "stable".
Therefore would like to know what could be considered good practices to follow besides the criteria, arguments before bumping a project to server 1.0.0.
How you are dealing with this?
If there are not issues/code activity in 3 months the version is dumped?
The development team decides when they have version 1.0.0. It is possible for a project to remain in experimental/prototype mode for very long periods of time. The only thing that matters here is whether the interface and implementation can be considered complete or not. What are your goals? Do you have all the planned v1 features in place? Do you have doubts w.r.t. implementation conformance to the documented interface?
Some teams don't have workflows that map onto the full semver spec, but they use packaging/release tooling that requires a semver version string. In order to be legal, they never release version 1.0.0, so any version bumps literally don't have full SemVer semantics. See #4 in the spec.
When I see SomeLib.0.20.3.pkg I assume it is not stable. A breaking change can occur on the very next minor field bump, whether or not there have ever been any such changes in the past. SemVer is a contract that allows the SomeLib developers to break things without notice in this particular case.
There is nothing in the spec that precludes a team from issuing a 1.0.0 and then returning to a long sequence of 0.x.x releases if they so desire to operate that way. This is similar to, but not exactly the same as using prerelease tags. When you issue 1.0.1-prerelease you are at least implying intent to release a work derived from 1.0.0 that is a bug-fix, but the prerelease tag is warning label that you are not yet certain of the safety of the changes you made. Following on from 1.0.0 to a sequence of 0.x.x releases says you might not even be deriving from 1.0.0 anymore. Basically, all bets are off again.
If you require any further elucidation on this matter, please ask, I am happy to try to answer any questions regarding SemVer.

How to use gitversion on older codebase

I tried running gitVersion on extremely old and complicated codebase that was migrated with git-tfs. I do get results in most branches but they are incorrect.
How do I get started with existing repositories?
How do I debug the results so I know what contributed to the final output?
Can some branches be ignored because they used are incorrectly attributing a larger number?
Sorry to hear that you are having issues using GitVersion.
Not sure what you mean here, can you elaborate?
The GitVersion log output is quite verbose, as you can see here as an example. It walks you through what base versions it can locate, and from there, how it asserted the final version number.
You might want to take a look at the commits-before configuration option which might help with an older code base that wasn't sticking to conventions, and a result, ignore the prior commit history, and start versioning a fresh.

Resources