Як я можу автоматично збільшити версію збірки C # за допомогою нашої платформи CI (Хадсон)?


112

Я та моя група надзвичайно великі, коли збільшуються номери версій монтажу, і ми часто постачаємо збірки з версіями 1.0.0.0. Очевидно, це викликає багато головних болів.

Ми набагато покращуємо свою практику через нашу платформу CI, і я дуже хотів би встановити її для автоматичного збільшення значень у assemblyinfo.csфайлі, щоб версії наших збірок автоматично оновлювалися зі змінами коду в цій збірці.

Раніше я налаштовував (перш ніж ми знайшли Хадсона ) спосіб збільшити значення за допомогою будь-якого msbuildабо командного рядка (не пам'ятаю), але з Хадсоном це оновить сховище SVN і запустить СКЛАДНУ збірку. Це призведе до повільного нескінченного циклу, оскільки Гудсон щогодини опитує SVN.

Чи погана ідея збільшення Хадсона на номер версії? Який був би альтернативний спосіб зробити це?

В ідеалі моїми критеріями рішення були б такі:

  • Збільшує число збірки assemblyinfo.csперед збіркою
  • Тільки збільшує кількість збірки в збірках, які змінилися. Це може бути неможливо, оскільки Хадсон видаляє папку проектів щоразу, коли збирає
  • Подає змінений Assemblyinfo.cs у сховище коду (зараз VisualSVN )
  • Не змушує Хадсон запускати нову збірку наступного разу, коли він сканує зміни

Опрацьовуючи це в голові, я міг легко придумати рішення більшості цього за допомогою пакетних файлів / команд, але всі мої ідеї змусять Хадсона запустити нову збірку наступного разу, коли вона сканує. Я не шукаю, щоб хтось зробив для мене все, просто вкажіть мене в правильному напрямку, можливо, техніка, щоб змусити Гудсона ігнорувати певні зобов’язання SVN тощо.

Все, що я знайшов до цього часу, - це лише стаття, в якій пояснюється, як автоматично збільшувати номер версії. Ніщо не враховує платформу CI, яку можна було б повернути у нескінченний цикл.

Відповіді:


63

Проста альтернатива - дозволити середовищу C # збільшити версію збірки для вас, встановивши атрибут версії до major.minor.*(як описано в шаблоні файлу AssemblyInfo.)

Ви, можливо, шукаєте більш комплексне рішення.

EDIT (відповідь на запитання в коментарі):

Від 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.*")]

Я ніколи раніше не стикався з цим, чи не могли б ви детальніше розібратися, що це робить? Чи функціонує вона лише в межах однієї IDE або вона працює у цілій команді розробників із платформою CI?
Аллен Райс

ах, я вже бачив, що раніше це може бути прийнятним рішенням, але # вбудований не зберігається в межах підривної програми тощо. У мене є настройка Хадсона для архівації файлів, і таким чином він зберігається, щоб це було прийнятним. Мені доведеться ще кілька досліджень, як працює цей механізм, дякую! Ви б не знали, як це визначає, що слід вводити як значення, чи не так?
Аллен Райс

1
Дивіться мою відповідь нижче для відповіді на ваше запитання. Значення визначаються виходячи з часу складання.
Кайл Трауберман

Нічого собі, я думаю, це спрацює. Не впевнений, як ми не помітили такого простого рішення
Аллен Райс,

Сподіваюся, це так, радий, що можу допомогти. Навіщо робити щось важке, коли легкий, швидкий шлях - це також правильний шлях? :)
Грег Д

65

Ось що я зробив для штампування атрибута AssemblyFileVersion.

Видалено AssemblyFileVersion з AssemblyInfo.cs

Додайте до проекту новий, порожній файл під назвою AssemblyFileInfo.cs.

Встановіть набір інструментів завдань спільноти MSBuild на машину збирання hudson або як залежність NuGet у своєму проекті.

Відредагуйте файл проекту (csproj), це лише файл msbuild і додайте наступне.

Десь <PropertyGroup>з'явиться версія, де зазначено версію. Змініть так, щоб він читався, наприклад

 <Major>1</Major>
 <Minor>0</Minor>
 <!--Hudson sets BUILD_NUMBER and SVN_REVISION -->
 <Build>$(BUILD_NUMBER)</Build>
 <Revision>$(SVN_REVISION)</Revision>

Хадсон надає ті змінні env, які ви бачите там, коли проект побудований на Гудзоні (припускаючи, що він отриманий із підривної роботи).

Внизу файлу проекту додайте

 <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')" />
  <Target Name="BeforeBuild" Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')">
    <Message Text="Version: $(Major).$(Minor).$(Build).$(Revision)" />
    <AssemblyInfo CodeLanguage="CS" OutputFile="AssemblyFileInfo.cs" AssemblyFileVersion="$(Major).$(Minor).$(Build).$(Revision)" AssemblyConfiguration="$(Configuration)" Condition="$(Revision) != '' " />
  </Target>

Для цього використовується MSBuildCommunityTasks для генерування AssemblyFileVersion.cs для включення атрибута AssemblyFileVersion перед тим, як проект будується. Ви можете зробити це для будь-якого / всіх атрибутів версії, якщо хочете.

Результатом є щоразу, коли ви випускаєте побудову Гудзона, отримана збірка отримує AssemblyFileVersion 1,0.HUDSON_BUILD_NR.SVN_REVISION, наприклад, 1.0.6.2632, що означає 6-ю збірку # в Хадсоні, що купується з ревізії підконтрольної версії 2632.


1
Тому просто для оновлення цього: метод працює для C #. Я використовую його вже деякий час. Але склади C ++ (тобто C ++ / CLI) все ще є проблемою. Наскільки я можу сказати, завдання AssemblyInfo не дає дійсних C ++. Крім того, я вважаю, що цей метод має невеликий недолік, оскільки він трохи непрозорий, щоб зрозуміти, що відбувається. Шкода, що ви не можете натиснути номери версій безпосередньо у MSBuild як власність ...
CJBrew

@CJBrew Ви можете просто створити невеликий .bat файл, який створює код C ++ для AssemblyInfo, і матимете команду msbuild для того, щоб почати роботу. Я не впевнений, що ви маєте на увазі, висуваючи його як властивість, ви, безумовно, можете заповнити рядки версій у будь-якому властивості, яке вам подобається - вам не потрібно використовувати основний / мінор / build / редагування, який я тут використовував.
нос

Що-небудь отримане за допомогою цього маршруту порівняно з просто коментування AssemblyFileVersion і нехай він автоматично встановлюється відповідно до [Assembly: AssemblyVersion ("1.0. *")?
Кемберлен

@ColeChamberlain Це автоматично збільшується, якщо ви будуєте його з візуальної студії на своєму ПК, а не з Хадсона - і немає ніякого відношення до номера версії та певної версії збірки та перегляду вихідного коду.
ніс

42

Ось вишукане рішення, яке потребує невеликої роботи наперед при додаванні нового проекту, але обробляє процес дуже легко.

Ідея полягає в тому, щоб кожен проект посилався на файл рішення, який містить лише інформацію про версію збірки. Тож ваш процес збирання повинен лише оновити один файл, і всі версії збірки витягуються з одного файлу при компіляції.

Кроки:

  1. Додайте до файлу рішення клас * файл .cs, я назвав min SharedAssemblyProperties.cs
  2. Видаліть всю інформацію CS з цього нового файлу
  3. Виріжте інформацію про збірку з файлу AssemblyInfo: [Assembly: AssemblyVersion ("1.0.0.0")] [Assembly: AssemblyFileVersion ("1.0.0.0")]
  4. Додайте вислів "за допомогою System.Reflection;" у файл, а потім вставити дані у новий файл cs (колишній SharedAssemblyProperties.cs)
  5. Додайте до проекту існуючий елемент (зачекайте ... читайте далі, перш ніж додавати файл)
  6. Виберіть файл і перед натисканням кнопки Додати натисніть спадне меню біля кнопки "Додати" та виберіть "Додати як посилання".
  7. Повторіть кроки 5 та 6 для всіх існуючих та нових проектів у рішенні

Коли ви додаєте файл у якості посилання, він зберігає дані у проектному файлі і після компіляції витягує інформацію про версію збірки з цього файлу.

У керуванні джерелом ви додаєте bat-файл або файл сценарію, який просто збільшує файл SharedAssemblyProperties.cs, і всі ваші проекти оновлять інформацію про його збірку з цього файлу.


дякую, Марку. Вибачте за мертве посилання, виявляється, що сервер спільноти не так легко перемістити. Мені слід шукати допомоги з цієї теми ...
sondlerd

11

Хадсон може бути налаштований на ігнорування змін до певних контурів і файлів, щоб він не вимагав нової збірки.

На сторінці конфігурації завдання в розділі Керування вихідним кодом натисніть кнопку Додатково . У полі Виключені регіони ви вводите одне або більше регулярних виразів, щоб відповідати виключенням.

Наприклад, щоб ігнорувати зміни у файлі version.properties, ви можете використовувати:

/MyProject/trunk/version.properties

Це буде працювати для інших мов, крім C #, і дозволяє зберігати інформацію про версію в межах підривної роботи.


1
Хадсон також може ігнорувати комісії від певних користувачів або не викликати збірку залежно від повідомлення про фіксацію. Таким чином ви можете проігнорувати всі зобов'язання Хадсона.
Peter Schuetze

9

.NET робить це за вас. У файлі AssemblyInfo.cs встановіть версію збірки на major.minor. * (Наприклад: 1.0. *).

Коли ви будуєте проект, версія генерується автоматично.

Я думаю, що номери збірки та ревізії створюються на основі дати, використовуючи епоху unix. Збірка заснована на поточному дні, а перегляд ґрунтується на кількості секунд з півночі.


21
<ring, ring> "привіт, підтримка продуктів, як я можу допомогти?" <customer> "у мене помилка" <support> "добре, яку версію ти працюєш?" <customer> "версія один пункт два перегляд вісім п'ять два п'ять три сім чотири побудувати сім чотири шість три п'ять два дев'ять ..." <support> "тримай, просто ввівши, що це ... хммм ... будь ласка повтори версію цифри, у нас, здається, немає цієї збірки та перегляду ... "- GRRR!
Джимбо

хаха приємний коментар. Я також не прихильник цієї системи нарощування: p
Джошуа Хайес

3
Автопосилення у візуальній студії серйозно засихає.
Кугель

8
@Jimbo: Хоча ми всі згодні, що ваш коментар був смішним, на практиці це не має значення. Якщо ви говорите про свою установку VS, чи є у вас Visual Studio 2008 SP1 або VS2008 9.0.30729.1 SP? Використання номерів збірки для автоматичного збільшення є дуже поширеною схемою, і її можна легко "виправити", збільшуючи основні / другорядні номери версій, коли виходить збірка версії.
Марек

найвищий показник збірки 678 перед тим, як повернути до 0 для збільшення незначної ревізії (звичайно, круїз-контроль, здавалося, простіше скинути, ніж Хадсон, як у круїз-контролі. Ви просто зайшли в систему і зберегли її назад до 0 в проекті , але все інше в Гудзоні краще)
Дін Хіллер

8

Я ніколи не бачив, щоб ця функція 1.0. * Працювала у VS2005 або VS2008. Чи потрібно щось зробити, щоб VS збільшував значення?

Якщо AssemblyInfo.cs жорстко кодується з 1.0. *, То де зберігаються реальні збірки / версії?

Після додавання 1.0. * У AssemblyInfo, ми не можемо використовувати наступне твердження, оскільки ProductVersion тепер має недійсне значення - воно використовує 1.0. *, А не значення, призначене VS:

Version version = new Version(Application.ProductVersion);

Зітхання - це, здається, одна з тих речей, про які всі запитують, але чомусь ніколи не існує надійної відповіді. Роки тому я бачив рішення для створення ревізійного номера та збереження його у AssemblyInfo як частина процесу після збирання. Я сподівався, що такий тип танцю не буде потрібен для VS2008. Може бути, VS2010?


10
Вам потрібно видалити AssemblyFileVersion. Крім цього, його розробка для нас приголомшлива, прийнята відповідь, яка є.
Аллен Райс

1
Так, видалення AssemblyFileVersion дозволяє оновити версію, і більше не буде помилок з Версією. Приємно. Примітка: дві операції побудови версію збільшують лише один раз, але якщо ви перезавантажуєте версію, оновлення оновлено. Як сказав ktrauberman, це виглядає як build.revision = date.time, що пояснює, чому дані не зберігаються ніде, крім як у зборі. Тепер мені потрібно отримати стандартну програму MSI для створення нового ProductCode при оновленні основного проекту. Налаштування не дозволяють переглядати, а лише створювати. Я хочу встановити поверх наявної установки, щоб зробити оновлення. Потрібні дослідження.
TonyG

5

Я припускаю, що це також можна зробити з текстовим шаблоном, коли ви створюєте атрибути збірки під час руху з навколишнього середовища, як, наприклад, AssemblyVersion.tt.

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<#
var build = Environment.GetEnvironmentVariable("BUILD_NUMBER");
build = build == null ? "0" : int.Parse(build).ToString();
var revision = Environment.GetEnvironmentVariable("SVN_REVISION");
revision = revision == null ? "0" : int.Parse(revision).ToString();    
#>
using System.Reflection;
[assembly: AssemblyVersion("1.0.<#=build#>.<#=revision#>")]
[assembly: AssemblyFileVersion("1.0.<#=build#>.<#=revision#>")]

3

Як продовження відповіді MikeS, я хотів би додати, що для того, щоб це працювало, потрібно встановити SDK для візуалізації та моделювання VS + Visual Studio, і вам також потрібно змінити файл проекту. Слід зазначити, що я використовую Jenkins як сервер збірки, що працює на сервері Windows 2008 R2 з модулем версії, де я отримую BUILD_NUMBER.

Файл мого текстового шаблона version.tt виглядає приблизно так

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<#
var build = Environment.GetEnvironmentVariable("BUILD_NUMBER");
build = build == null ? "0" : int.Parse(build).ToString();
var revision = Environment.GetEnvironmentVariable("_BuildVersion");
revision = revision == null ? "5.0.0.0" : revision;    
#>
using System.Reflection;
[assembly: AssemblyVersion("<#=revision#>")]
[assembly: AssemblyFileVersion("<#=revision#>")]

У групах властивостей є наступне

<PropertyGroup>
    <TransformOnBuild>true</TransformOnBuild>
    <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
    <TransformOutOfDateOnly>false</TransformOutOfDateOnly>
</PropertyGroup>

після імпорту Microsoft.CSharp.targets я маю це (залежно від місця встановлення VS

<Import Project="C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\TextTemplating\v10.0\Microsoft.TextTemplating.targets" />

Тоді на моєму сервері збірки у мене є наступний скрипт для запуску перетворення тексту перед фактичним складанням, щоб отримати останній номер набору змін на TFS

set _Path="C:\Build_Source\foo"

pushd %_Path% 
"%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\tf.exe" history . /r /noprompt /stopafter:1 /Version:W > bar
FOR /f "tokens=1" %%foo in ('findstr /R "^[0-9][0-9]*" bar') do set _BuildVersion=5.0.%BUILD_NUMBER%.%%foo
del bar
popd

echo %BUILD_NUMBER%
echo %_BuildVersion%
cd C:\Program Files (x86)\Jenkins\jobs\MyJob\workspace\MyProject
MSBuild MyProject.csproj /t:TransformAll 
...
<rest of bld script>

Таким чином я можу відслідковувати збірки та набори змін, тому якщо я не перевіряв нічого в минулому з моменту останньої збірки, остання цифра не повинна змінюватися, проте я могла внести зміни в процес збирання, отже, потреба в другому останньому номері . Звичайно, якщо ви зробите кілька реєстрацій перед збіркою, ви отримаєте лише останню зміну, відображену у версії. Я думаю, ви могли б поєднати це, що потрібно.

Я впевнений, що ви можете зробити щось більш фантазійне і зателефонувати в TFS безпосередньо з шаблону tt, проте це працює для мене.

Тоді я можу отримати свою версію під час виконання, як це

Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
return fvi.FileVersion;

1

Моє рішення не вимагає додавання зовнішніх інструментів або мов скриптів - це майже гарантовано працює на вашій машині побудови. Я вирішую цю проблему в декількох частинах. По-перше, я створив файл BUILD.BAT, який перетворює параметр Jenkins BUILD_NUMBER в змінну середовища. Я використовую функцію "Виконати пакетну команду Windows" Дженкінса, щоб запустити пакетний файл збірки, ввівши наступну інформацію для складання Дженкінса:

     ./build.bat --build_id %BUILD_ID% -build_number %BUILD_NUMBER%

У середовищі збірки у мене є файл build.bat, який починається наступним чином:

     rem build.bat
     set BUILD_ID=Unknown
     set BUILD_NUMBER=0
     :parse_command_line
     IF NOT "%1"=="" (
         IF "%1"=="-build_id" (
             SET BUILD_ID=%2
             SHIFT
             )
         IF "%1"=="-build_number" (
             SET BUILD_NUMBER=%2
             SHIFT
         )
         SHIFT
         GOTO :parse_command_line
     )
     REM your build continues with the environmental variables set
     MSBUILD.EXE YourProject.sln

Як тільки я це зробив, я клацнув правою кнопкою миші на проект, який потрібно побудувати на панелі провідника Рішення Visual Studio, і вибрав "Властивості", виберіть "Події збирання" та ввів наступну інформацію як командний рядок "Попередньо побудувати події", який автоматично створює файл .cs містить інформацію про номер збірки на основі поточних параметрів змінної середовища:

     set VERSION_FILE=$(ProjectDir)\Properties\VersionInfo.cs
     if !%BUILD_NUMBER%==! goto no_buildnumber_set
     goto buildnumber_set
     :no_buildnumber_set
     set BUILD_NUMBER=0
     :buildnumber_set
     if not exist %VERSION_FILE% goto no_version_file
     del /q %VERSION_FILE%
     :no_version_file
     echo using System.Reflection; >> %VERSION_FILE%
     echo using System.Runtime.CompilerServices; >> %VERSION_FILE%
     echo using System.Runtime.InteropServices; >> %VERSION_FILE%
     echo [assembly: AssemblyVersion("0.0.%BUILD_NUMBER%.1")] >> %VERSION_FILE%
     echo [assembly: AssemblyFileVersion("0.0.%BUILD_NUMBER%.1")] >> %VERSION_FILE%

Можливо, вам доведеться підлаштувати свій смак. Я будую проект вручну один раз, щоб генерувати початковий файл Version.cs в каталозі Властивості основного проекту. Нарешті, я вручну включаю файл Version.cs у рішення Visual Studio, перетягуючи його на панель Провідник рішень, під вкладку Властивості цього проекту. У майбутніх збірках Visual Studio потім зчитує файл .cs у часі збірки Дженкінса і отримує з нього правильну інформацію про номер збірки.


1

Отже, у нас є проект з одним рішенням, який містить кілька проектів, які мають збірки з різними номерами версій.

Дослідивши кілька перерахованих вище методів, я просто здійснив крок збирання для запуску сценарію Powershell, який робить пошук і заміну у файлі AssemblyInfo.cs. Я все ще використовую номер версії 1.0. * У контролі джерела, і Дженкінс просто вручну оновлює номер версії до запуску msbuild.

dir **/Properties/AssemblyInfo.cs | %{ (cat $_) | %{$_ -replace '^(\s*)\[assembly: AssemblyVersion\("(.*)\.\*"\)', "`$1[assembly: AssemblyVersion(`"`$2.$build`")"} | Out-File $_ -Encoding "UTF8" }
dir **/Properties/AssemblyInfo.cs | %{ (cat $_) | %{$_ -replace '^(\s*)\[assembly: AssemblyFileVersion\("(.*)\.\*"\)', "`$1[assembly: AssemblyFileVersion(`"`$2.$build`")"} | Out-File $_ -Encoding "UTF8" }

Я додав параметр -Encoding "UTF8", тому що git почав обробляти файл .cs як бінарні файли, якщо я цього не зробив. Звичайно, це не має значення, оскільки я ніколи фактично не здійснюю результат; це просто вийшло, як я тестував.

У нашому середовищі CI вже є можливість асоціювати побудову Дженкінса з конкретним git-комітетом (спасибі плагін Stash!), Тому я не хвилююся, що немає git-комітету із доданим до нього номером версії.


0

Це простіший механізм. Він просто передбачає додавання команди Windows Batch для створення завдання перед кроком MSBuild та використання простої програми пошуку та заміни (FART).

Крок партії

fart --svn -r AssemblyInfo.cs "[assembly: AssemblyVersion(\"1.0.0.0\")]" "[assembly: AssemblyVersion(\"1.0.%BUILD_NUMBER%.%SVN_REVISION%\")]"
if %ERRORLEVEL%==0 exit /b 1
fart --svn -r AssemblyInfo.cs "[assembly: AssemblyFileVersion(\"1.0.0.0\")]" "[assembly: AssemblyFileVersion(\"1.0.%BUILD_NUMBER%.%SVN_REVISION%\")]"
if %ERRORLEVEL%==0 exit /b 1
exit /b 0

Якщо ви використовуєте джерело управління, крім svn, змініть параметр --svn на відповідний для вашого scm середовища.

Завантажити Фарт


0

Я вирішив використати пару методів, використовуючи попередній збір сценарію Powershell ( https://gist.github.com/bradjolicoeur/e77c508089aea6614af3 ) для збільшення кожної успішної збірки, то в Global.asax я щось подібний:

  // We are using debug configuration, so increment our builds.
  if (System.Diagnostics.Debugger.IsAttached)
  {
      string version = System.Reflection.Assembly.GetExecutingAssembly()
                                                       .GetName()
                                                       .Version
                                                       .ToString();

      var psi = new ProcessStartInfo(@"svn", "commit -m \"Version: " + version + "\n \"");
      psi.WorkingDirectory = @"C:\CI\Projects\myproject";
      Process.Start(psi); 
  }

Я все ще думаю, що весь процес є надскладним, і я розглядаю більш ефективний метод досягнення того ж результату. Я хотів цього головним чином для передачі версії в SVN, а потім у Jenkin's без занадто багато додаткових інструментів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.