Как я могу автоматически увеличивать версию сборки С# через нашу платформу CI (Hudson)?
Я и моя группа ужасны при увеличении числа версий сборки, и мы часто отправляем сборки с версиями 1.0.0.0. Очевидно, это вызывает много головных болей.
Мы значительно улучшаем наши практики с помощью нашей платформы Hudson) способ увеличить значение через msbuild
или в командной строке ( не помню), но с Hudson, который будет обновлять SVN-репозиторий и запускать ANOTHER build. Это приведет к медленному бесконечному циклу, поскольку Hudson опроса SVN каждый час.
Имеет ли Хадсон увеличение номера версии плохую идею? Каким будет альтернативный способ сделать это?
В идеале, мои критерии для решения будут такими:
- Увеличивает номер сборки в
assemblyinfo.cs
перед сборкой
- Увеличивает только номер сборки в сборках, которые были изменены. Это может быть невозможно, поскольку Хадсон вытирает папку проекта каждый раз, когда выполняет сборку
- Задает измененный файл assemblyinfo.cs в репозитории кода (в настоящее время VisualSVN)
- Не вызывает Hudson для запуска новой сборки при следующем сканировании изменений.
Используя это в моей голове, я мог бы легко найти решение большинства из этого с помощью командных файлов/команд, но все мои идеи заставили бы Хадсона запускать новую сборку при следующем сканировании. Я не ищу, чтобы кто-то делал все для меня, просто укажите мне в правильном направлении, может быть, метод, чтобы Хадсон проигнорировал некоторые обязательства SVN и т.д.
Все, что я нашел до сих пор, - это всего лишь статья, объясняющая, как получить номер версии, автоматически увеличивающийся, ничто не учитывает платформу CI, которая может быть развернута в бесконечный цикл.
Ответы
Ответ 1
Простая альтернатива - позволить среде С# увеличить версию сборки для вас, установив атрибут версии 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.*")]
Ответ 2
Вот что я сделал, для штамповки атрибута 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 (при условии, что он получен из подрывной работы).
В нижней части файла проекта добавьте
<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-ю сборку # в hudson, buit из версии 2632 подрывной версии.
Ответ 3
Вот элегантное решение, которое требует небольшой работы при добавлении нового проекта, но очень легко обрабатывает процесс.
Идея состоит в том, что каждый проект связан с файлом решения, который содержит только информацию о версии сборки. Таким образом, процесс сборки должен обновлять только один файл, а все версии сборки извлекаются из одного файла при компиляции.
Шаги:
- Добавьте класс к файлу *.cs файла решения, я назвал min SharedAssemblyProperties.cs
- Удалите всю информацию cs из этого нового файла
- Вырезать информацию сборки из файла AssemblyInfo:
[сборка: AssemblyVersion ( "1.0.0.0" )]
[сборка: AssemblyFileVersion ( "1.0.0.0" )]
- Добавить инструкцию "using System.Reflection;" в файл, а затем вставьте данные в новый файл cs (ex SharedAssemblyProperties.cs)
- Добавьте существующий элемент в проект (подождите... прочитайте перед добавлением файла)
- Выберите файл и перед тем, как нажать кнопку "Добавить", выберите раскрывающийся список рядом с кнопкой "Добавить" и выберите "Добавить как ссылку".
- Повторите шаги 5 и 6 для всех существующих и новых проектов в решении.
Когда вы добавляете файл в качестве ссылки, он сохраняет данные в файле проекта, а после компиляции выводит информацию о версии сборки из этого одного файла.
В исходном управлении вы добавляете файл bat или файл script, который просто увеличивает файл SharedAssemblyProperties.cs, и все ваши проекты будут обновлять информацию об их сборке из этого файла.
Ответ 4
Hudson может быть настроен так, чтобы игнорировать изменения определенных путей и файлов, чтобы он не запрашивал новую сборку.
На странице конфигурации задания в разделе Управление исходными кодами нажмите кнопку Дополнительно. В поле Исключенные регионы вы вводите одно или несколько регулярных выражений для соответствия исключениям.
Например, чтобы игнорировать изменения в файле version.properties, вы можете использовать:
/MyProject/trunk/version.properties
Это будет работать на языках, отличных от С#, и позволяет хранить информацию о вашей версии в рамках подрывной деятельности.
Ответ 5
.NET делает это для вас. В файле AssemblyInfo.cs установите версию сборки в файл major.minor. * (Например: 1.0. *).
Когда вы создаете проект, версия автоматически создается.
Строки и ревизионные номера создаются на основе даты, используя, по-моему, эпоху unix. Строка основывается на текущем дне, а ревизия основана на количестве секунд с полуночи.
Ответ 6
Я никогда не видел, чтобы функция 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?
Ответ 7
Я предполагаю, что также можно было бы сделать это с текстовым шаблоном, где вы создаете атрибуты сборки, о которых идет речь, из среды, такой как 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#>")]
Ответ 8
В качестве продолжения ответа MikeS я хотел добавить, что для этого нужно установить VSD Visual Studio Visualization и Modeling SDK, и вам также необходимо изменить файл проекта. Следует также упомянуть, что я использую 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" />
На моем сервере сборки у меня есть следующий script, чтобы запустить преобразование текста до фактической сборки, чтобы получить последний номер набора изменений в 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;
Ответ 9
Мое решение не требует добавления внешних инструментов или языков сценариев - почти гарантированно работает на вашей машине сборки. Я решаю эту проблему в нескольких частях. Во-первых, я создал файл BUILD.BAT, который преобразует параметр Jenkins BUILD_NUMBER в переменную среды. Я использую Jenkins "Выполнять команду пакетной команды Windows" для запуска командного файла сборки, введя следующую информацию для сборки Jenkins:
./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, перетащив его в панель Solution Explorer, под вкладкой "Свойства" для этого проекта. В будущих сборках Visual Studio затем считывает этот файл .cs в время сборки Jenkins и получает из него правильную информацию о номере сборки.
Ответ 10
Итак, у нас есть проект с одним решением, которое содержит несколько проектов, имеющих сборки с разными номерами версий.
После изучения нескольких из вышеперечисленных методов я только что реализовал шаг сборки для запуска Powershell script, который выполняет поиск и замену в файле AssemblyInfo.cs. Я все еще использую номер версии 1.0. * В исходном элементе управления, а Jenkins просто обновляет номер версии до запуска 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 (спасибо плагину Stash!), поэтому я не беспокоюсь, что нет git commit с номером версии, прикрепленным к нему.
Ответ 11
Это более простой механизм. Это просто связано с добавлением шага создания задачи командной строки Windows перед шагом 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.
Загрузить Fart
Ответ 12
Я решил использовать несколько методов, используя prebuild Powershell script (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 без слишком большого количества дополнительных инструментов.