Версионинг в .NET проектах и не только

    В методология изменения версий продукта для меня долгое время оставались непонятные моменты, т.к. слишком много различных способов изменения версии при внесении в продукт изменений. Стратегии с которыми я сталкивался — это использование четырех чисел в номере версии(например 1.5.2.871).

    Три первых изменяются всегда вручную, и, обычно не превышают 10, а последняя — вручную или автоматически и означает номер билда. Особенно непонятно для меня было как назначать номера версий компонентам продукта, если в Visual Studio solution и в состав продуктов входит не один исполняемый проект, а несколько проектов (может быть и 10, и больше) различных типов (исполняемые модули и библиотеки).

    Для себя я придумал вполне устраивающее меня решение, если интересно,

    В частности, в .NET проектах к по умолчанию создается файл AssemblyInfo.cs, в котором по умолчанию присутствует следующий код:

    // Version information for an assembly consists of the following four values:
    //
    //      Major Version
    //      Minor Version 
    //      Build Number
    //      Revision
    //
    // 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("1.0.0.0")]
    [assembly: AssemblyFileVersion("1.0.0.0")]
    


    Может я с этим не до конца разобрался, но заставить механизм с AssemblyVersion(«1.0.*») работать как то более менее вразумительно у меня не получилось. Внятных описаний в MSDN я также не нашел. Поэтому решил подумать над собственным решением, которое неплохо сейчас у меня работает вместе с Subversion.

    При выпуске версий продукта часто бывает нужно вручную изменять три первых цифры версии. Увеличиваем первую цифру (major) — очень существенные изменения, возможно даже переписано ядро либо какие то его части. Вторая цифра (minor) — добавлен новый функционал, возможно сравнительно небольшой. Третья цифра — поправлены баги, плюс небольшие улучшения, добавления функционала. Но для тестирования и идентификации билдов этого мало при работе с тестировщиками. Если постоянно именовать дистрибутив как «MyProductSetup_1.3.7» и отдавать на тестирование, работая с issue tracker — идентифицировать билд в котором проблема проявляется довольно сложно. Т.е инкрементировать нужно и последнюю цифру в номере версии. Делать это вручную при наличии множества проектов в solution при каждой новой сборке — весьма нудная работа.

    Потому я решил применить автоматическую сборку с автоматическим инкрементом версий. Здесь опишу без деталей реализации (конечно могу добавить если потребуется), скажу лишь что написал небольшой скрипт для MS Build и MS Build Сommunity Tasks, .NET разработчики с этими инструментами думаю хорошо знакомы.

    Итак, текущая версия продукта, из 3 цифр, хранится в SVN в plain текст файле(я храню в XML), и изменяется разработчиками продукта вручную, т.к. за изменением версии продукта обычно следует релиз, release notes, уведомления пользователей, обновление сайта и т.д.

    Сборка по шагам, выполняемая скриптом:
    1. Делаем SvnCheckout
    2. Меняем версии в AssemblyInfo.cs во всех проектах на текущую версию + номер ревизии соответствующей ветки проекта. Например, если текущая версия продукта — 1.3.2, а ревизия SVN ветки проекта MySoundLibrary — 286, выставляем версию в AssemblyInfo 1.3.2.286.
    3. Для дистрибутива (у меня это InnoSetup) выставляем версию SVN ветки всего solution (каталога, где хранится файл .sln)
    4. Выполняем сборку, именуем полученный .exe(.msi) файл как MyProduct_v_1_3_2_286.exe
    5. Коммитим изменения. Важно: ветки всех проектов в solution коммитим по отдельности.

    В итоге получаем:
    — Билд «одной кнопкой»/запуском файла (можно повесить, например, на CruiseControl.NET)
    — Каждый билд дистрибутива отражает состояние SVN репозитория в последней цифре имени файла
    — Все компоненты билда(.dll, .exe) отражают cостояние соответствующих SVN веток проекта. Т.е. посмотрев, к примеру, на версию .dll файла можно узнать из какой ревизии он был собран. Также удобно отслеживать изменения: чем больше последняя версия .dll файла, тем активнее он менялся.

    Может слишком сумбурно изложил, я старался лишь предложить метод, а не реализацию, надеюсь, что я не изобрел колесо:)
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 5

      0
      Это что, руками надо вписывать номер каждой ревизии SVN, да еще и коммитить по-отдельности?
      Долбануться можно — компьютер вам на что дан? Откройте для себя SubWCRev.exe
        –1
        Я упомянул в посте у том, что я использую автоматическую сборку при помощи MSBuild проекта (небольшой XML файл) и версии в AssemblyInfo заменяются при помощи регулярных выражений. А о существовании SubWCRev действительно ничего не знал, спасибо Вам, ознакомлюсь, возможно я действительно изобретаю колесо.
        +2
        Не устаю делиться ссылкой: Continuous Integration: From Theory to Practice. Прочитав руководство, можно создать полностью автоматический билд-сервер со сбором метрик, тестированием и развёртыванием проекта!

        Указанная задача там решается целиком автоматически. Вкратце — порядковый номер билда лежит в текстовом файле, находящемся в репозитории. Билд-скрипт считывает его из файла, номер ревизии репозитория берётся с помощью команды SvnInfo (MSBuild.Community.Tasks), далее скрипт компонует файл GlobalAssemblyInfo.cs с новым номером версии продукта и прочей информацией, который используется во всём решении.
          –1
          Спасибо за ссылку. Я что то подобное раньше делал, но потом решил отказаться от CruiseControl.NET, меня не устраивало отсутствие некоторых возможностей CruiseControl.NET, кастомизировать я не смог.

          В моем решении я использую практически такой же подход, который Вы описали. Три цифры версии хранятся в XML файле, MSBuild скрипт считывает этот файл, считывает номер ревизии каждого каталога проекта с помощью SvnInfo и проставляет последнюю цифру версии в AssemblyInfo, заменяя при помощи RegExp. Отличие лишь в том, что версия проставляется для каждого проекта в solution и она может быть разной, т.к. ревизии веток каталогов могут отличаться.

          Применять GlobalAssemblyInfo.cs мне кажется не совсем корректным, т.к. это, имхо, нарушает суть версионинга, т.к в этом случае в дистрибутиве мы получаем набор assembly с одинаковыми версиями. Хотя это и не очень критично.
          0
          >2. Меняем версии в AssemblyInfo.cs во всех проектах на текущую версию + номер ревизии соответствующей ветки проекта.

          Этот пункт можно тоже облегчить. Для этого редактируйте только один из AssemblyInfo.cs в одном из проектов, все остальные замените ссылками на этот файл (Add Existing File/Add As Link). Так удобно проставлять единые для всех сборок проекта атрибуты типа AssemblyCompany, AssemblyProduct, AssemblyCopyright и т.п.

          Ну или можно перенести нужные атрибуты из AssemblyInfo.cs в свой класс, а на него как на Link уже ссылаться, правда с одним ньюансом, в случае использования файла, отличного от AssemblyInfo.cs — перестанет работать редактирование этих свойств через визуальный редактор студии.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое