Perhaps the most significant problem with the simplistic versioning system we put into place last time is that we can get the same version number generated on different branches. Fortunately, semantic versioning gives us room to fix this by adding a descriptive suffix to the build number.
There’s no free lunch however - while I want to use SemVer 2.0 for this project, not everything supports that style of versioning.
While the current NuGet clients and most of the third party NuGet servers support v2, NuGet.org itself is still restricted to v1 (for good reasons of backward compatibility), with a maximum length of just 20 characters.
To complicate matters still further, Windows itself has a somewhat different notion of versioning, one that’s considerably older. Version numbers for windows software are in four parts (
major.minor.build.revision) except for when only three parts are relevant (such as when an MSI installation is running).
In short, we’re going to need to generate three different (but closely related) editions of our version.
Builds on our master branch are going to be our formal releases, and don’t need any specific semantic annotation, so we’ll stick with the approach created previously:
We can use this style of versioning pretty universally.
The develop branch is typically used to create beta builds used for testing. In some projects, these are the builds that get pushed into specific testing environments. Even though I’m not using develop on this tiny project, it’s still worth including.
The value used for
commit will be the truncated git commit hash for the current head of the
Versioning for other branches (such as those used for feature development or hot-fixes) is much less important because the chances of distributing one of those builds are quite low. But, we still want them to be distinctly versioned so we don’t get two builds confused. We’ll explicitly call them out as alpha releases so that people know they’re not considered production ready and include the actual branch name for reference.
We’ll need to do a minor transformation to make sure our branch label complies with the semver standard. Since labels are restricted to alphanumeric plus dash, if our branch is
feature/new-api, we’ll need to translate that into
Now that we’ve decided what we’re doing, here’s the implementation:
We log our progress step by step through the task, just in case something goes wrong part way - we want to give as much context as possible for any error.
Much of the work is done for us by the git console app itself, making it much easier to write the PowerShell required.
Perhaps the most complex part is the use of a regular expression to replace any sequence of unwanted characters with a single period (
.) when defining
$semverBranch. If the branch name includes any folders (say, if it was
feature/new-api) then each folder in the branch name becomes a separate fragment of the version.
For example, when testing this implementation, I got this output:
Generate.VersionInfo task from last week is relatively simple; we use the
$semver20 version string as the informational label for our assemblies.
Now that we’ve got versioning out of the way, what’s next? Creating a NuGet package.