Pull to refresh

Полуавтоматическое инкрементирование версии проекта при работе с GIT в Visual Studio

Reading time5 min
Views20K
В Интернетах написано немало статей об инкрементировании версий своих приложений и каждый использует свой метод. У кого-то ревизии используются в качестве «билдов», у кого-то это количество секунд текущих суток (например, Microsoft), у кого-то что-то другое.

В моем проекте используются 4 определяющие версии.

Например, 1.2.34.56, где:
1 — Major version: Критические изменения проекта (введен новый функционал, в корне переработан существующий и пр.). Устанавливается вручную;
2 — Minor version: Изменение функциональных частей приложения, значительное улучшение кода и пр. Устанавливается вручную;
24 — Build: номер релиза, попадающего в общество. Назначается автоматически;
56 — Revision: номер ревизии, полученный с GIT. Назначается автоматически.

Я не буду рассматривать кто какими методами пользуется, поэтому напишу как достиг данного результата.



Шаг 1. Подготовка


Сперва нам нужно зайти в настройки проекта (Project -> MyProject Properties). Здесь, во вкладке Application, идем в Assembly Information и проверяем, чтобы все 4 поля параметра Assembly version были заполнены, причем, первые 2 цифры указываем соответствующие нашему релизу. В моем случае это версия "2.3", а остальные цифры ставим любые.

image

После внесения изменений нам нужно зайти в папку проекта и найти файл AssemblyInfo.cs, который обычно находится в папке Properties.
Открываем файл на редактирование и в самом низу ищем строки:

// 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")]


Удаляем закомментированную строку:
// [assembly: AssemblyVersion("1.0.*")]

Сделать это необходимо по той причине, что при записи новой версии будет использоваться регулярное выражение, считывающее ключевые цифры версии (major, minor) из первого найденного совпадения.
Удалили, сохранили, закрыли файл. Более он нам не понадобится.

Шаг 2. «ChangeRevision»


Для удобства я скомпилировал консольное приложение, которое считывает значения major, minor и build из файла Properties\AssemblyInfo.cs, а также количество коммитов GIT.
Итак, код 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();
            }

        }
    }
}


Скомпилированный файл кладем в директорию Solution.

Ниже подробнее распишу как работает данный код.

Шаг 3. Pre-Build Event


Так как мне необходимо изменить версию билда перед компиляцией, код вписывается в окно Pre-Build Event.
"$(SolutionDir)ChangeRevision.exe" $(ConfigurationName) "$(ProjectName)"


image

Где:
"$(SolutionDir)ChangeRevision.exe" — Указывается путь к solution с указанием запуска нашего скомпилированного файла, о котором написано выше.
$(ConfigurationName) — Тип конфигурации (Debug или Release).
Если при запуске файла ChangeRevision.exe был передан параметр Debug, то в версии проекта будет увеличено только значение ревизии, то есть, если было 2.3.0.0, то станет 2.3.0.х, где «х» — количество коммитов по проекту. Если передан параметр Release, то автоматически будет инкрементирован номер билда совместно с изменением ревизии по количеству коммитов. Например, было 2.3.0.0, станет 2.3.1.х, где «х» — количество коммитов по проекту.
"$(ProjectName)" — Имя проекта

UPD: Из кода программы был удален параметр, содержащий имя проекта, так как при компиляции проекта стартовой директорией запуска файла с параметром являлась $(ProjectDir)\bin\Debug / Release, вследствие чего возникала ошибка. Таким образом, передача наименования проекта отпала как таковая, так как в работе приложения ChangeRevision.exe используется переход на верхний уровень относительно директории запуска, то есть, указав путь "..\..\Properties\AssemblyInfo.cs" программа переходит в директорию проекта и от туда в «Properties», где и находит необходимый файл AssemblyInfo.cs"

UPD 2: Как показала практика, если в Solution находится несколько проектов и выбрать на компиляцию не тот, что по-умолчанию, то стартовой директорией будет, почему-то, директория проекта по-умолчанию. В общем, код еще немного доработан и изменен вверху, а именно, вновь введен параметр передачи наименования проекта, который в ChangeRevision.exe перехватывается вторым по счету. Таким образом, путь к к AssemblyInfo.cs был изменен на:
@"..\..\..\" + args[1] + @"\Properties\AssemblyInfo.cs"

То есть, при компиляции любого проекта стартовая директория смещается на 3 ступени вверх (директория solution), а затем перемещается в папку проекта, указанную в параметре запуска файла, переходя к искомому файлу.

Количество коммитов можно узнать путем передачи параметра
git rev-list master --count

Это в том случае, если нужно получить количество коммитов из ветки MASTER.

По завершению работы приложения будет изменен файл Properties\AssemblyInfo.cs, переданного в первом параметре, проекта, после чего среда разработки скомпилирует файл самого проекта с указанной в файле версией.
P.S.: При изменении версии AssemblyVersion также изменяется и значение в параметре AssemblyFileVersion, а в некоторых случаях и AssemblyFileVersionAttribute.

Таким образом я достиг полуавтоматического инкрементирования версии своего приложения.

P.S.: Конечно, работая в команде или выполняя регулярное объединение версий, данный вариант не подходит ВООБЩЕ не подходит, так как количество коммитов может внезапно сократиться, таким образом получем «новую» «старую» версию ПО. А для одного человека, без использования объединения версий, данный вариант более чем достаточен.

Спасибо за внимание!

UPD: Внес изменения в код на Шаге 2. Поправил описание
UPD 2: Все на том же шаге вновь изменения в коде.
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+9
Comments20

Articles