How to Automatically Increment the File Build Version When Using Visual Studio

How to have an auto incrementing version number (Visual Studio)?

If you add an AssemblyInfo class to your project and amend the AssemblyVersion attribute to end with an asterisk, for example:

[assembly: AssemblyVersion("2.10.*")]

Visual studio will increment the final number for you according to these rules (thanks galets, I had that completely wrong!)

To reference this version in code, so you can display it to the user, you use reflection. For example,

Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
DateTime buildDate = new DateTime(2000, 1, 1)
.AddDays(version.Build).AddSeconds(version.Revision * 2);
string displayableVersion = $"{version} ({buildDate})";

Three important gotchas that you should know

From @ashes999:

It's also worth noting that if both AssemblyVersion and AssemblyFileVersion are specified, you won't see this on your .exe.

From @BrainSlugs83:

Setting only the 4th number to be * can be bad, as the version won't always increment.
The 3rd number is the number of days since the year 2000, and the 4th number is the number of seconds since midnight (divided by 2) [IT IS NOT RANDOM]. So if you built the solution late in a day one day, and early in a day the next day, the later build would have an earlier version number. I recommend always using X.Y.* instead of X.Y.Z.* because your version number will ALWAYS increase this way.

Newer versions of Visual Studio give this error:



(this thread begun in 2009)

The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation.

See this SO answer which explains how to remove determinism (https://stackoverflow.com/a/58101474/1555612)


Can I automatically increment the file build version when using Visual Studio?

In visual Studio 2008, the following works.

Find the AssemblyInfo.cs file and find these 2 lines:

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

You could try changing this to:

[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("1.0.*")]

But this won't give you the desired result, you will end up with a Product Version of 1.0.* and a File Version of 1.0.0.0. Not what you want!

However, if you remove the second of these lines and just have:

[assembly: AssemblyVersion("1.0.*")]

Then the compiler will set the File Version to be equal to the Product Version and you will get your desired result of an automatically increment product and file version which are in sync. E.g. 1.0.3266.92689

Auto increment FileVersion (build nr) in Visual Studio 2019


Does anyone have a better solution than this ?

Better, I don't know, different yes.

There is no actual need for a 3rd party tool. We use a simple script for doing this and it was running since I can remember (about Visual Studio 2010 I think, with some changes since back then). However, you need to fulfill some prerequisites (but which can come in handy). The script below should run in Visual Studio 2019/2017 and PowerShell 3+.

We have a file version.h which looks like this:

#pragma once
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_PATCH 0
#define VERSION_BUILD 0

#define stringify(a) stringify_(a)
#define stringify_(a) #a

Note: version.h requires a new line at the end to avoid fatal error RC1004: unexpected end of file found.

Resource files can include header files, and therefore include version.h in your resource file and change it to use the defines accordingly:

#include "version.h"
// ... other stuff

VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_BUILD
PRODUCTVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_BUILD

// ... other stuff
VALUE "FileVersion", stringify(VERSION_MAJOR) "." stringify(VERSION_MINOR) "." stringify(VERSION_PATCH) "." stringify(VERSION_BUILD)
VALUE "ProductVersion", stringify(VERSION_MAJOR) "." stringify(VERSION_MINOR) "." stringify(VERSION_PATCH) "." stringify(VERSION_BUILD)
// ... other stuff

Now in the project properties pre-build scripts we are running a PowerShell script. The command:

powershell.exe -ExecutionPolicy Bypass -NoProfile -NonInteractive -File update_version.ps1 "./version.h"

And the script is a find & replace text with an increment:

(Get-Content -path $args[0] -Raw) |
ForEach-Object {
$defstr="#define VERSION_BUILD ";
$regex="$defstr(?<BuildVersion>\d*)";
if($_ -match $regex) {
$_ = $_ -replace $regex,"$($defstr)$(([int]$matches["BuildVersion"])+1)"
}
$_
} |
Out-File $args[0] -encoding ascii -nonewline

Some advantages are:

  • version.h is plain C and can be parsed by any C/C++-compliant compiler, MSVC resource compiler or even tools like Doxygen.
  • You can use it in your C++ files:
#include "version.h"
int main() {
std::cout << "Hello World Version " stringify(VERSION_MAJOR) "." stringify(VERSION_MINOR) "." stringify(VERSION_PATCH) "." stringify(VERSION_BUILD) " !\n";
}
  • versioning is centralized
  • other scripts to handle major/minor/patch versions are also simple
  • the scripts are fairly simple, and maintenance is also simple

How to auto increment the version (eg. “1.0.*”) of a .NET Core project?

One simple way I did it previously is reading the current version and increase it by one, so you get current version and increment by one using command line.

I found this article would answers your question: https://sachabarbs.wordpress.com/2020/02/23/net-core-standard-auto-incrementing-versioning/

Auto-increment version revision number with wildcard

I found this:

https://marketplace.visualstudio.com/items?itemName=PrecisionInfinity.AutomaticVersions

It's hilarious that VS doesn't have this built-in.

MSBuild auto increment build version differently for release/debug


MSBuild auto increment build version differently for release/debug

In general, MSBuild did not have a function to see the version number of the obvious incremental build but only used the timestamp of the system build determines the build order as you used before.

In fact, if you create a custom property in msbuild to record the version number of the incremental build, it still needs to use an entity to store the record, and if it is not used, the parameter is reinitialized for each build (the msbuild attribute can only be identified in msbuild).

So the ideal way it that use textfile as an intermediate. You can follow my solution:

Solution

1) create a custom msbuild task which does increment the value of the record property.

--a) Create a class library project called MyCustomTask then Right-click on the project-->Add Reference-->reference Microsoft.Build.Framework dll and Microsoft.Build.Utilities.v4.0 dll.

Sample Image

--b) add these into CustomTask.cs(this is the name of the task which will be used in xxx.csproj file).

 public class CustomTask : Task
{

private int _number;
[Required]
public int number //input taskitem
{
get { return _number; }

set { _number = value; }

}
private int _lastnumber;
[Output]
public int LastNumber //output value
{
get { return _lastnumber; }
set { _lastnumber = value; }
}

public override bool Execute() // Execution logic
{
LastNumber = number + 1;
return true;
}
}

--c) Then build the project and remember to store its MyCustomTask dll.

2) Aim to your main project and then create two txt files called Debug.txt,Release.txt and give each of them an initial value of 0.

Sample Image

3) add these into your Directory.Build.props file:

<Project>
<UsingTask TaskName="CustomTask" AssemblyFile="xxxxxx\MyCustomTask\MyCustomTask\MyCustomTask\bin\Debug\MyCustomTask.dll(the local path of the dll)"> </UsingTask>
<PropertyGroup>
<Record></Record>
</PropertyGroup>

<Target Name="WriteToFile1" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<Record Condition="'$(Configuration)'=='Debug' and !Exists('$(TargetPath)')">
0
</Record>
<Record Condition="'$(Configuration)'=='Release'and !Exists('$(TargetPath)')">
0
</Record>
</PropertyGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<MyTextFile Include="Debug.txt">
<Number>$(Record)</Number>
</MyTextFile>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Release'">
<MyTextFile Include="Release.txt">
<Number>$(Record)</Number>
</MyTextFile>
</ItemGroup>
<WriteLinesToFile
File="@(MyTextFile)"
Lines="$(Record)"
Overwrite="true"
Encoding="Unicode" Condition="'$(Configuration)'=='Debug'"/>
<WriteLinesToFile
File="@(MyTextFile)"
Lines="$(Record)"
Overwrite="true"
Encoding="Unicode" Condition="'$(Configuration)'=='Release'"/>
<PropertyGroup>
<Version>
$([System.DateTime]::Now.Year).
$([System.DateTime]::Now.Month).
$([System.DateTime]::Now.Day).
$(Record)
</Version>
</PropertyGroup>
</Target>

<Target Name="ReadLineFromFile" BeforeTargets="WriteToFile1">
<ReadLinesFromFile File="Debug.txt" Condition="'$(Configuration)'=='Debug'">
<Output TaskParameter="Lines" PropertyName="Record"/>
</ReadLinesFromFile>
<ReadLinesFromFile File="Release.txt" Condition="'$(Configuration)'=='Release'">
<Output TaskParameter="Lines" PropertyName="Record"/>
</ReadLinesFromFile>

<CustomTask number="$(Record)">
<Output TaskParameter="LastNumber" PropertyName="Record"/>
</CustomTask>
</Target>
</Project>

4) When you execute a task which depends on Build to show the property Version, it will work well as you hope.

Note that it will work for incremental build and if you click Rebuild(which execute Clean and then Build), it will set the version number to zero and start the rethrow.

Overall, this is an ideal solution which I try to realize it.



Related Topics



Leave a reply



Submit