Version numbers in .NET Projects

  Subscribe
1/11/2019 - Marco von Ballmoos (updated on 3/13/2019)

Any software product should have a version number. This article will answer the following questions about how Encodo works with them.

  • 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?

Stakeholders

In decreasing order of expected expertise,

  • Developers: Writes the software; may change version numbers
  • Testers: Tests the software; highly interested in version numbers that make sense
  • End users: Uses the software as a black box

The intended audience of this document is developers.

Definitions and Assumptions

  • Build servers, not developer desktops, produce artifacts
  • The source-control system is Git
  • The quino 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 developer as an end user
  • A breaking change in a software library causes one of the following
    • a build error
    • an API to behave differently in a way that cannot be justified as a bug fix

Semantic versions

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:

  • Official releases: [Major].[Minor].[Patch].[Build]
  • Pre-releases: [Major].[Minor].[Patch]-[Label][Build]

See Microsoft's NuGet Package Version Reference for more information.

Examples

  • 0.9.0-alpha34: A pre-release of 0.9.0
  • 0.9.0-beta48: A pre-release of 0.9.0
  • 0.9.0.67: An official release of 0.9.0
  • 1.0.0-rc512: A pre-release of 1.0.0
  • 1.0.0.523: An official release of 1.0.0

The numbers are strictly ordered. The first three parts indicate the "main" version. The final part counts strictly upward.

Parts

The following list describes each of the parts and explains what to expect when it changes.

Build

  • Identifies the build task that produced the artifact
  • Strictly increasing

Label

  • An arbitrary designation for the "type" of pre-release

Patch

  • Introduces bug fixes but no features or API changes
  • May introduce obsolete members
  • May not introduce breaking changes

This part is also known as "Maintenance" (see Software versioning on Wikipedia).

Minor

  • 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

Major

  • Introduces major new features
  • Introduces breaking changes that require considerable effort to integrate
  • Introduces a new data or protocol format that requires migration

Conventions

Uniqueness for official releases

There will only ever be one artifact of an official release corresponding to a given "main" version number.

That is, if 1.0.0.523 exists, then there will never be a 1.0.0.524. 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 1.0.0.523. NuGet will not offer to upgrade to 1.0.0.524.

Pre-release Labels

There are no restrictions on the labels for pre-releases. However, it's recommended to use one of the following:

  • alpha
  • beta
  • rc

Be aware that if you choose a different label, then it is ordered alphabetically relative to the other pre-releases.

For example, if you were to use the label pre-release to produce the version 0.9.0-prealpha21, then that version is considered to be higher than 0.0.0-alpha34. A tool like NuGet will not see the latter version as an upgrade.

Release branches

The name of a release branch should be the major version of that release. E.g. release/1 for version 1.x.x.x.

Pre-release branches

The name of a pre-release branch should be of the form feature/[label] where [label] is one of the labels recommended above. It's also OK to use a personal branch to create a pre-release build, as in mvb/[label].

Setting the base version

A developer uses the quino tool to set the version.

For example, to set the version to 1.0.1, execute the following:

quino fix -v 1.0.1.0

The tool will have updated the version number in all relevant files.

Calculating final version

The build server calculates a release's version number as follows,

  • major: Taken from solution
  • minor: Taken from solution
  • maintenance: Read from solution
  • label: Taken from the Git branch (see below for details)
  • build: Provided by the build server

Git Branches

The name of the Git branch determines which kind of release to produce.

  • If the name of the branch matches the glob **/release/*, then it's an official release
  • Everything else is a pre-release

For example,

  • origin/release/1
  • origin/production/release/new
  • origin/release/
  • release/1
  • production/release/new
  • release/

The name of the branch doesn't influence the version number since an official release doesn't have a label.

Pre-release labels

The label is taken from the last part of the branch name.

For example,

  • origin/feature/beta yields beta
  • origin/feature/rc yields rc
  • origin/mvb/rc yields rc

The following algorithm ensures that the label can be part of a valid semantic version.

  • Remove invalid characters
  • Append an X after a trailing digit
  • Use X if the label is empty (or becomes empty after having removed invalid characters)

For example,

  • origin/feature/rc1 yields rc1X
  • origin/feature/linux_compat yields linuxcompat
  • origin/feature/12 yields X

Examples

Assume that,

  • the version number in the solution is 0.9.0.0
  • the build counter on the build server is at 522

Then,

  • Deploying from branch origin/release/1 produces artifacts with version number 0.9.0.522
  • Deploying from branch origin/feature/rc produces artifacts with version number 0.9.0-rc522

Release Workflow

The following are very concise guides for how to produce artifacts.

Pre-release

  • Ensure you are on a non-release branch (e.g. feature/rc, master)
  • Verify or set the base version (e.g. quino fix -v 1.0.2.0
  • Push any changes to Git
  • Execute the "deploy" task against your branch on the build server

Release

  • Ensure you are on a release branch (e.g. release/1)
  • Verify or set the base version (e.g. quino fix -v 1.0.2.0
  • Push any changes to Git
  • Execute the "deploy" task against your branch on the build server

Sign up for our Newsletter