📜 ⬆️ ⬇️

Semi-automatic incrementing of the project version when working with GIT in Visual Studio

There are a lot of articles on the Internet about incrementing versions of their applications and each one uses its own method. Someone uses revisions as “builds”, someone has the number of seconds of the current day (for example, Microsoft), someone has something else.

My project uses 4 defining versions.

For example, 1.2.34.56 , where:
1 - Major version: Critical changes to the project (new functionality was introduced, existing ones were redesigned, etc.). Set manually;
2 - Minor version: Changing the functional parts of the application, a significant improvement in the code, etc. It is installed manually;
24 - Build: release number entering the community. Automatically assigned;
56 - Revision: revision number obtained with GIT. Assigned automatically.
')
I will not consider who uses what methods, so I will write how I achieved this result.



Step 1. Preparation


First we need to go to the project settings ( Project -> MyProject Properties ). Here, in the Application tab, go to the Assembly Information and check that all 4 fields of the Assembly version parameter are filled, and the first 2 digits indicate the corresponding to our release. In my case, this is version " 2.3 ", and the remaining numbers are set to any.

image

After making changes, we need to go to the project folder and find the AssemblyInfo.cs file, which is usually located in the Properties folder.
We open the file for editing and at the very bottom look for the lines:

// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("2.3.0.0")] [assembly: AssemblyFileVersion("2.3.0.0")] 


Delete the commented line:
 // [assembly: AssemblyVersion("1.0.*")] 

This is necessary for the reason that when writing a new version a regular expression will be used that reads the key digits of the version (major, minor) from the first match found.
Removed, saved, closed the file. More we do not need it.

Step 2. “ChangeRevision”


For convenience, I compiled a console application that reads the major, minor, and build values ​​from the Properties \ AssemblyInfo.cs file, as well as the number of GIT commits .
So, the code ChangeRevision.exe :

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.IO; using System.Diagnostics; namespace ChangeRevision { class Program { static void Main(string[] args) { try { Process process = new Process(); process.StartInfo.WorkingDirectory = Environment.CurrentDirectory; process.StartInfo.FileName = "\"c:\\Program Files (x86)\\Git\\cmd\\git.exe\""; process.StartInfo.Arguments = @"rev-list master --count"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; StringBuilder output = new StringBuilder(); int timeout = 10000; using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false)) { process.OutputDataReceived += (sender, e) => { if (e.Data == null) outputWaitHandle.Set(); else output.AppendLine(e.Data); }; process.Start(); process.BeginOutputReadLine(); if (process.WaitForExit(timeout) && outputWaitHandle.WaitOne(timeout)) { string text = File.ReadAllText(@"..\..\..\"+args[1]+@"\Properties\AssemblyInfo.cs"); Match match = new Regex("AssemblyVersion\\(\"(.*?)\"\\)").Match(text); Version ver = new Version(match.Groups[1].Value); int build = args[0] == "Release" ? ver.Build + 1 : ver.Build; Version newVer = new Version(ver.Major, ver.Minor, build, Convert.ToInt16(output.ToString().Trim())); text = Regex.Replace(text, @"AssemblyVersion\((.*?)\)", "AssemblyVersion(\"" + newVer.ToString() + "\")"); text = Regex.Replace(text, @"AssemblyFileVersionAttribute\((.*?)\)", "AssemblyFileVersionAttribute(\"" + newVer.ToString() + "\")"); text = Regex.Replace(text, @"AssemblyFileVersion\((.*?)\)", "AssemblyFileVersion(\"" + newVer.ToString() + "\")"); File.WriteAllText(@"..\..\..\" + args[1] + @"\Properties\AssemblyInfo.cs", text); } } } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(""); Console.WriteLine(ex.StackTrace); Console.ReadLine(); } } } } 


We put the compiled file in the Solution directory.

Below I will describe in more detail how this code works.

Step 3. Pre-Build Event


Since I need to change the build version before compiling, the code fits into the Pre-Build Event window.
 "$(SolutionDir)ChangeRevision.exe" $(ConfigurationName) "$(ProjectName)" 


image

Where:
"$ (SolutionDir) ChangeRevision.exe" - Indicates the path to the solution indicating the launch of our compiled file, which is written above.
$ (ConfigurationName) - Configuration type ( Debug or Release ).
If the Debug parameter was passed when the ChangeRevision.exe file was launched, then in the project version only the revision value will be increased , that is, if it was 2.3.0.0, it will become 2.3.0.x, where "x" is the number of commits for the project. If the Release parameter is passed, the build number will be automatically incremented along with the change in revision by the number of commits . For example, it was 2.3.0.0, it becomes 2.3.1.x, where "x" is the number of commits for the project.
"$ (ProjectName)" - Project Name

UPD: The parameter containing the name of the project was deleted from the program code, because when the project was compiled, the starting directory for launching the file with the parameter was $ (ProjectDir) \ bin \ Debug / Release , which resulted in an error. Thus, the transfer of the project name has disappeared as such, since the ChangeRevision.exe application uses a transition to the upper level relative to the launch directory, that is, specifying the path ".. \ .. \ Properties \ AssemblyInfo.cs" the program goes to the project directory and from there to “Properties” , where it finds the required AssemblyInfo.cs file "

UPD 2: As practice has shown, if there are several projects in Solution and choosing not the default one for compilation, then the starting directory will be, for some reason, the default project directory. In general, the code is still a little refined and changed at the top, namely, the parameter to transfer the project name has been reintroduced, which is intercepted in ChangeRevision.exe second in a row. Thus, the path to AssemblyInfo.cs has been changed to:
 @"..\..\..\" + args[1] + @"\Properties\AssemblyInfo.cs" 

That is, when compiling any project, the start directory is shifted up 3 steps (the solution directory) and then moved to the project folder specified in the file launch parameter, moving to the desired file.

The number of commits can be obtained by passing the parameter
 git rev-list master --count 

This is if you need to get the number of commits from the MASTER branch.

Upon completion of the application, the Properties \ AssemblyInfo.cs file passed in the first parameter of the project will be modified, after which the development environment will compile the project file itself with the version specified in the file.
PS: If you change the version of AssemblyVersion , the value in the AssemblyFileVersion parameter and, in some cases, the AssemblyFileVersionAttribute , also changes.

Thus, I achieved a semi-automatic incrementing version of my application.

PS: Of course, working in a team or performing regular version merging, this option is not suitable AT ALL, as the number of commits can suddenly decrease, thus we get a “new” “old” version of software. And for one person, without the use of combining versions, this option is more than sufficient.

Thanks for attention!

UPD: Made changes to the code in Step 2. Corrected description
UPD 2: All at the same step again changes in the code.

Source: https://habr.com/ru/post/237585/


All Articles