This page shows the source for this entry, with WebCore formatting language tags and attributes highlighted.

Title

Version numbers in .NET Projects

Description

Any software product should have a version number. This article will answer the following questions about how Encodo works with them. <ul> How do we choose a version number? What parts does a version number have? What do these parts mean? How do different stakeholders interpret the number? What conventions exist for choosing numbers? Who chooses and sets these parts? </ul> <h>Stakeholders</h> In decreasing order of expected expertise, <ul> <b>Developers</b>: Writes the software; may *change* version numbers <b>Testers</b>: Tests the software; highly interested in version numbers that make sense <b>End users</b>: Uses the software as a black box </ul> The intended audience of this document is *developers*. <h>Definitions and Assumptions</h> <ul> Build servers, not developer desktops, produce artifacts The source-control system is Git The <c>quino</c> command-line tool is installed on all machines. This tool can *read* and *write* version numbers for any .NET solution, regardless of which of the many version-numbering methods a given solution actually uses. A *software library* is a package or product that has a <i>developer</i> as an *end user* A *breaking change* in a software library causes one of the following<ul> a build error an API to behave differently in a way that cannot be justified as a bug fix</ul> </ul> <h>Semantic versions</h> Encodo uses semantic versions. This scheme has a strict ordering that allows you to determine which version is "newer". It indicates pre-releases (e.g. alphas, betas, rcs) with a "minus", as shown below. Version numbers come in two flavors: <ul> Official releases: <c>[Major].[Minor].[Patch].[Build]</c> Pre-releases: <c>[Major].[Minor].[Patch]-[Label][Build]</c> </ul> See Microsoft's <a href="https://docs.microsoft.com/en-us/nuget/reference/package-versioning">NuGet Package Version Reference</a> for more information. <h level="3">Examples</h> <ul> <c>0.9.0-alpha34</c>: A pre-release of 0.9.0 <c>0.9.0-beta48</c>: A pre-release of 0.9.0 <c>0.9.0.67</c>: An official release of 0.9.0 <c>1.0.0-rc512</c>: A pre-release of 1.0.0 <c>1.0.0.523</c>: An official release of 1.0.0 </ul> The numbers are strictly ordered. The first three *parts* indicate the "main" version. The final *part* counts strictly upward. <h>Parts</h> The following list describes each of the parts and explains what to expect when it changes. <h level="3">Build</h> <ul> Identifies the build task that produced the artifact Strictly increasing </ul> <h level="3">Label</h> <ul> An arbitrary designation for the "type" of pre-release </ul> <h level="3">Patch</h> <ul> Introduces bug fixes but no features or API changes May introduce obsolete members May *not* introduce breaking changes </ul> This part is also known as "Maintenance" (see <a href="https://en.wikipedia.org/wiki/Software">versioning">Software versioning</a> on Wikipedia). <h level="3">Minor</h> <ul> Introduces new features that extend existing functionality May include bug fixes May cause minor breaking changes May introduce obsolete members that cause compile errors Workarounds must be documented in release notes or obsolete messages </ul> <h level="3">Major</h> <ul> Introduces major new features Introduces breaking changes that require considerable effort to integrate Introduces a new data or protocol format that requires migration </ul> <h>Conventions</h> <h level="3">Uniqueness for official releases</h> There will only ever be one artifact of an official release corresponding to a given "main" version number. That is, if <c>1.0.0.523</c> exists, then there will never be a <c>1.0.0.524</c>. This is due the fact that the build number (e.g. 524) is purely for auditing. For example, suppose your software uses a NuGet package with version <c>1.0.0.523</c>. NuGet will <i>not</i> offer to upgrade to <c>1.0.0.524</c>. <h level="3">Pre-release Labels</h> There are no restrictions on the labels for pre-releases. However, it's recommended to use one of the following: <ul> <c>alpha</c> <c>beta</c> <c>rc</c> </ul> Be aware that if you choose a different label, then it is ordered <i>alphabetically</i> relative to the other pre-releases. For example, if you were to use the label <c>pre-release</c> to produce the version <c>0.9.0-prealpha21</c>, then that version is considered to be <i>higher</i> than <c>0.0.0-alpha34</c>. A tool like NuGet will not see the latter version as an upgrade. <h level="3">Release branches</h> The name of a release branch should be the major version of that release. E.g. <c>release/1</c> for version 1.x.x.x. <h level="3">Pre-release branches</h> The name of a pre-release branch should be of the form <c>feature/[label]</c> where <c>[label]</c> is one of the labels recommended above. It's also OK to use a personal branch to create a pre-release build, as in <c>mvb/[label]</c>. <h>Setting the base version</h> A developer uses the <c>quino</c> tool to set the version. For example, to set the version to 1.0.1, execute the following: <code> quino fix -v 1.0.1.0 </code> The tool will have updated the version number in all relevant files. <h>Calculating final version</h> The build server calculates a release's version number as follows, <ul> <b>major</b>: Taken from solution <b>minor</b>: Taken from solution <b>maintenance</b>: Read from solution <b>label</b>: Taken from the Git branch (see below for details) <b>build</b>: Provided by the build server </ul> <h level="3">Git Branches</h> The name of the Git branch determines which kind of release to produce. <ul> If the name of the branch matches the glob <c>**/release/*</c>, then it's an official release Everything else is a pre-release </ul> For example, <ul> <c>origin/release/1</c> <c>origin/production/release/new</c> <c>origin/release/</c> <c>release/1</c> <c>production/release/new</c> <c>release/</c> </ul> The name of the branch doesn't influence the version number since an official release doesn't have a label. <h level="3">Pre-release labels</h> The label is taken from the last part of the branch name. For example, <ul> <c>origin/feature/beta</c> yields <c>beta</c> <c>origin/feature/rc</c> yields <c>rc</c> <c>origin/mvb/rc</c> yields <c>rc</c> </ul> The following algorithm ensures that the label can be part of a valid semantic version. <ul> Remove invalid characters Append an <c>X</c> after a trailing digit Use <c>X</c> if the label is empty (or becomes empty after having removed invalid characters) </ul> For example, <ul> <c>origin/feature/rc1</c> yields <c>rc1X</c> <c>origin/feature/linuxcompat</c> yields <c>linuxcompat</c> <c>origin/feature/12</c> yields <c>X</c> </ul> <h level="3">Examples</h> Assume that, <ul> the version number in the solution is 0.9.0.0 the build counter on the build server is at 522 </ul> Then, <ul> Deploying from branch <c>origin/release/1</c> produces artifacts with version number <c>0.9.0.522</c> Deploying from branch <c>origin/feature/rc</c> produces artifacts with version number <c>0.9.0-rc522</c> </ul> <h>Release Workflow</h> The following are very concise guides for how to produce artifacts. <h level="3">Pre-release</h> <ul> Ensure you are on a non-release branch (e.g. <c>feature/rc</c>, <c>master</c>) Verify or set the base version (e.g. <c>quino fix -v 1.0.2.0</c> Push any changes to Git Execute the "deploy" task against your branch on the build server </ul> <h level="3">Release</h> <ul> Ensure you are on a release branch (e.g. <c>release/1</c>) Verify or set the base version (e.g. <c>quino fix -v 1.0.2.0`</c>) Push any changes to Git Execute the "deploy" task against your branch on the build server </ul>