Как я могу автоматически увеличить версию сборки C # через нашу CI-платформу (Hudson)? - PullRequest
110 голосов
/ 14 июля 2009

Я и моя группа ужасно увеличиваем номера версий сборок, и мы часто поставляем сборки с версиями 1.0.0.0. Очевидно, это вызывает много головных болей.

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

Ранее я настроил (до того, как мы нашли Hudson ) способ увеличения значения с помощью msbuild или командной строки (не помню), но с Hudson, который будет обновлять SVN хранилище и запуск ДРУГОЙ сборки. Это приведет к медленному бесконечному циклу, так как Хадсон опрашивает SVN каждый час.

Плохо ли делать увеличение номера версии Хадсона? Какой альтернативный способ сделать это?

В идеале, мои критерии для решения должны быть такими:

  • Увеличивает номер сборки в assemblyinfo.cs перед сборкой
  • Увеличивает только номер сборки в сборках, которые изменились. Это может быть невозможно, так как Хадсон стирает папку проекта каждый раз, когда выполняет сборку
  • Передает измененный файл assemblyinfo.cs в хранилище кода (в настоящее время VisualSVN )
  • Не заставляет Хадсона запускать новую сборку при следующем сканировании на наличие изменений

Работая над этим, я мог бы легко найти решение для большинства из них с помощью пакетных файлов / команд, но все мои идеи заставили бы Хадсон запустить новую сборку при следующем сканировании. Я не ищу кого-то, кто сделает все для меня, просто укажи мне правильное направление, возможно, метод, позволяющий Хадсону игнорировать определенные коммиты SVN и т. Д.

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

Ответы [ 12 ]

64 голосов
/ 19 августа 2010

Вот что я сделал для отметки атрибута 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>

Hudson предоставляет переменные env, которые вы видите там, когда проект построен на hudson (при условии, что он получен из subversion).

В нижней части файла проекта добавьте

 <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 до построения проекта. Вы можете сделать это для любого / всех атрибутов версии, если хотите.

В результате каждый раз, когда вы запускаете сборку hudson, полученная сборка получает AssemblyFileVersion 1.0.HUDSON_BUILD_NR.SVN_REVISION, например, 1.0.6.2632, что означает 6-й билд # в Хадсоне, байт из ревизии Subversion 2632.

61 голосов
/ 14 июля 2009

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

Возможно, вы ищете более комплексное решение.

РЕДАКТИРОВАТЬ (Ответ на вопрос в комментарии):

С 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.*")]
42 голосов
/ 04 февраля 2010

Вот элегантное решение, которое требует небольшой предварительной работы при добавлении нового проекта, но обрабатывает процесс очень легко.

Идея состоит в том, что каждый проект ссылается на файл решения, который содержит только информацию о версии сборки. Таким образом, процесс сборки должен обновлять только один файл, и все версии сборки извлекаются из одного файла после компиляции.

Шаги:

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

Когда вы добавляете файл в виде ссылки, он сохраняет данные в файле проекта и после компиляции извлекает информацию о версии сборки из этого одного файла.

В системе контроля версий вы добавляете файл bat или файл сценария, который просто увеличивает файл SharedAssemblyProperties.cs, и все ваши проекты будут обновлять информацию о сборке из этого файла.

11 голосов
/ 22 июля 2009

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

На странице конфигурации задания в разделе Управление исходным кодом нажмите кнопку Дополнительно . В поле Исключенные регионы введите одно или несколько регулярных выражений для соответствия исключений.

Например, чтобы игнорировать изменения в файле version.properties , которые вы можете использовать:

/MyProject/trunk/version.properties

Это будет работать для языков, отличных от C #, и позволит вам хранить информацию о вашей версии в Subversion.

9 голосов
/ 14 июля 2009

.NET делает это за вас. В файле AssemblyInfo.cs установите версию сборки на major.minor. * (Например: 1.0. *).

При создании проекта автоматически генерируется версия.

Номера сборок и ревизий генерируются на основе даты, я полагаю, с использованием эпохи Unix. Сборка основана на текущем дне, а редакция - на количестве секунд с полуночи.

8 голосов
/ 16 октября 2009

Я никогда не видел, чтобы эта функция 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?

5 голосов
/ 04 февраля 2013

Я предполагаю, что можно также сделать это с текстовым шаблоном , где вы создаете атрибуты сборки на лету из среды, как это делает 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 голосов
/ 03 апреля 2014

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

Файл My Text Template 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 голос
/ 25 апреля 2016

Итак, у нас есть проект с одним решением, который содержит несколько проектов, в которых есть сборки с разными номерами версий.

После изучения нескольких из вышеперечисленных методов я просто реализовал шаг сборки для запуска сценария 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 уже есть возможность связать сборку Jenkins с конкретным git commit (спасибо плагину Stash!), Поэтому я не волнуюсь, что git commit с номером версии, к которому он прикреплен, не существует.

1 голос
/ 24 мая 2014

Мое решение не требует добавления внешних инструментов или языков сценариев - оно гарантированно будет работать на вашем компьютере сборки. Я решаю эту проблему в нескольких частях. Сначала я создал файл 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 в каталоге Properties основного проекта. Наконец, я вручную включаю файл Version.cs в решение Visual Studio, перетаскивая его на панель обозревателя решений под вкладкой Свойства этого проекта. В будущих сборках Visual Studio читает этот файл .cs во время сборки Jenkins и извлекает из него правильную информацию о номере сборки.

...