Automatic Version Numbering

Sample of class

You can also use the Wizard. Easy steps for quick results.

The most easy manually way here.

Before reading, please note: You can achieve this (or similar) result with our different modes.

For simplicity, we consider the Script Mode. However, feel free. Use any other variants if you don't like this, for example: Targets Mode or C# Mode, or with simple caller and other

Synopsis

This method should automatically generate the Version class, e.g.: ↘

// This code was generated by a vsSolutionBuildEvent.
namespace example
{
    internal class Version
    {
        public static readonly System.Version number    = new System.Version(0, 12, 2, 1917);
        public const string numberWithRevString         = "0.12.2.1917";
        public const string numberString                = "0.12.2";
        public const string branchName                  = "local_API_Reverse";
        public const string branchSha1                  = "f05afc9";
        public const string branchRevCount              = "274";
        public const string informational               = "0.12.2.1917 [ f05afc9 ]";
        public const string informationalFull           = "0.12.2.1917 [ f05afc9 ] /'local_API_Reverse':274";
    }
}

Similarly for others… e.g. for C++ you can also use preprocessor directives - #define (macro definitions):

#pragma once

#ifndef VSSBE_VERSION_H_
#define VSSBE_VERSION_H_

#define VER_BRANCH_NAME     "develop";
#define VER_BRANCH_SHA1     "e3de826";
#define VER_BRANCH_REVCOUNT "296";
#define VER_INFORMATIONAL   "0.12.4.17639 [ e3de826 ]";

#endif

or similar class or struct as above..

Then, you can use this in different places, for example:

• Attribute to VSPackage class:

[InstalledProductRegistration("#110", "#112", Version.numberWithRevString, IconResourceID = 400)]

• AssemblyInfo:

[assembly: AssemblyVersion(Version.numberString)]

• Other places, for example:

toolVersion.Text = string.Format("v{0} [ {1} ]", Version.numberString, Version.branchSha1);

etc.,

What about static files

For example, for .vsixmanifest (it used for VSPackages /VSIX Package) is a little harder than above to simply manage of versions… We can't use this directly as above, therefore we may update it only as replacement, for example:

#[IO replace.Regexp("source.extension.vsixmanifest", "<Version>[0-9.]+</Version>", "<Version>#[var number]</Version>")]

Where, #[var number] it's your number(see UserVariableComponent). You can manage this value with next variants, for example:

  • Getting from MSBuild Property #[var number = $(name)] or $(number = $(name))
  • Getting from file: #[var number = #[File get(".version")]]
  • Getting from your external utility(stdout): #[var number = #[IO sout("updv.exe", "-s new")]]
  • Manually set - #[var number = 1.2.3] or $(number = "1.2.3")
  • Other with MSBuild & SBE-Scripts
  • etc.

Note: The <Version> in .vsixmanifest follows the CLR assembly versioning format: Major.Minor.Build.Revision (1.2.40308.00). see MSDN:

Generating the Version class with build/revision number

  • Create template of Version class or struct.
    • You can use external file (for example Version.tpl) or directly define data inside script, etc. with what you want. Use placeholders instead of real values - sample for C#:
namespace example
{
    internal struct Version
    {
        public static readonly System.Version number    = new System.Version(%Version%);
        public const string numberWithRevString         = "%VersionRevString%";
        public const string numberString                = "%VersionString%";
        public const string branchName                  = "%branchName%";
        public const string branchSha1                  = "%branchSha1%";
        public const string branchRevCount              = "%branchRevCount%";
    }
}
  • Define current number of your project like major.minor.patch and similar.
    • You can also use some external file for this, e.g.: .version
    • Or some variable, e.g.: $(Version) etc.
  • Select event type - "Pre-Build".
  • Change "Processing mode" to 'Script Mode'
  • Activate SBE-Scripts support
  • Activate MSBuild support
  • Write script, for example:

See also - Custom counters & Date & Time features for details about limitations for revBuild if you work in team.

#[" 
    Define variables
"]
#[var ver   = #[File get(".version")]]
#[var tpl   = #[File get("Version.tpl")]]
#[var pDir  = $(SolutionDir)\subproject]


#[" 
    Calculate revBuild
"]
#[var tBase     = $([System.DateTime]::Parse("2015/12/02").ToBinary())]
#[var tNow      = $([System.DateTime]::UtcNow.Ticks)]
#[var revBuild  = $([System.TimeSpan]::FromTicks('$([MSBuild]::Subtract($(tNow), $(tBase)))').TotalMinutes.ToString('0'))]


#[" 
    Remove placeholders
"]
#[var cs = $(tpl.Replace("%Version%", "$(ver.Replace('.', ', ')), $(revBuild)"))]
#[var cs = $(cs.Replace("%VersionRevString%", "$(ver).$(revBuild)").Replace("%VersionString%", "$(ver)"))]


#[" 
    Checks availability of git folder +tool & retrieving sha1, branch name, etc.
"]

#[( #[IO exists.directory(".git")] && #[IO exists.file("git.exe", true)] )
{
    #[var branchSha1        = #[IO sout("git", "rev-parse --short HEAD")]]
    #[var branchName        = #[IO sout("git", "rev-parse --abbrev-ref HEAD")]]
    #[var branchRevCount    = #[IO sout("git", "rev-list HEAD --count")]]
    
    #[var cs = $(cs.Replace("%branchName%", "#[var branchName]").Replace("%branchSha1%", "#[var branchSha1]").Replace("%branchRevCount%", "#[var branchRevCount]"))]
}
else {
    #[var cs = $(cs.Replace("%branchName%", "-").Replace("%branchSha1%", "-").Replace("%branchRevCount%", "-"))]
}]


#[" 
    Save our result from cs variable as Version.cs in pDir path
"]
#[File write("#[var pDir]\Version.cs"):#[var cs]]


#[" 
    Special .vsixmanifest finalization - see above
"]
#[File replace.Regexp("#[var pDir]/source.extension.vsixmanifest", "<Version>[0-9.]+</Version>", "<Version>#[var ver]</Version>")]
  • Activate event and click apply. Enjoy.

As result you will see Version.cs as above (should be included in main project with Build Action as Compile) and .vsixmanifest file with updated number.

Also you can use conditions for rev. number, for example:

#[($(Configuration) == "Release"){
    #[var ver = #[var ver].#[var revBuild]]
}]
...
#[File replace.Regexp("source.extension.vsixmanifest", "<Version>[0-9.]+</Version>", "<Version>$(ver)</Version>")]

In example above, should be like a 0.12.4.4187 for Release configuration and 0.12.4 for another, for example:

  • v0.12.4.4187 [ f8e9259 ] API: v1.3
  • v0.12.4.5192 [ d972b2d ] API: v1.3 /'local_sync':290

To get revBuild in range (see Math), you can use for example:

  • 0 - 99999:
#[var revBuild  = ...]
#[var revBuild  = $([MSBuild]::Modulo(#[var revBuild], 100000))]
  • n - m (e.g. 1000 - 99999):

Same as above, only use limit like: = (val % (max - min)) + min

#[$(
    [MSBuild]::Add(
        $(minrev), 
        $([MSBuild]::Modulo(
            $(rev), 
            $([MSBuild]::Subtract(
                $(maxrev), 
                $(minrev)
             ))
        ))
    )
)]

Sample of how to use it for 'Assembly' attributes etc.

You can also test/debug all scripts with our testing tools, look in the Settings - Tools

Wizard or "help me, it's so hard"

ok, try the wizard for common solutions - Wizard variant

Working example

It also used for this project:

Full Automatic Versions. Serial / Sequential numbers.

Any generating of numbers still may be as you want, see for example - Increment & Decrement Numbers

Some projects can use a simple numbering of build, like a: 1, 2, 3, 4 .. 99, 100, 101 … 500, 501 etc.

And of course, primarily, this is important feature of CI servers.

For all of this you should:

  • Define where to store this number: it can be registry, simple file in directory with source code, etc.
    • By the way, the most CI servers already should provide special environment variable like a $(appveyor_build_version), $(BUILD_NUMBER), etc.
  • Increment this as you want !
$(buildNumber += 1)
or
$(buildNumber = $([MSBuild]::Add($(buildNumber), 1)))

References