Мы делаем это с xUnit.net для наших автоматических сборок. Мы используем CruiseControl.net
(и пробуем TeamCity). Задача MSBuild, которую мы запускаем для непрерывной интеграции, автоматически меняет номер сборки для нас, поэтому полученный ZIP-файл сборки содержит правильно настроенный набор DLL и EXE-файлов.
Наш файл MSBuild содержит ссылку UsingTask для DLL, которая выполняет замены регулярных выражений: (вы можете использовать эту DLL, так как она также покрывается лицензией MS-PL)
<UsingTask
AssemblyFile="3rdParty\CodePlex.MSBuildTasks.dll"
TaskName="CodePlex.MSBuildTasks.RegexReplace"/>
Далее мы извлекаем номер сборки, который автоматически предоставляется системой CI. Вы также можете попросить вашего поставщика управления исходным кодом предоставить номер версии исходного кода, если хотите, но мы обнаружили, что номер сборки # в системе CI был более полезным, потому что не только можно видеть результаты интеграции по номеру сборки CI, что также обеспечивает вернуться к изменениям, которые были включены в сборку.
<!-- Cascading attempts to find a build number -->
<PropertyGroup Condition="'$(BuildNumber)' == ''">
<BuildNumber>$(BUILD_NUMBER)</BuildNumber>
</PropertyGroup>
<PropertyGroup Condition="'$(BuildNumber)' == ''">
<BuildNumber>$(ccnetlabel)</BuildNumber>
</PropertyGroup>
<PropertyGroup Condition="'$(BuildNumber)' == ''">
<BuildNumber>0</BuildNumber>
</PropertyGroup>
(Мы используем BUILD_NUMBER из TeamCity, затем ccnetlabel из CC.net, и если ни того, ни другого нет, по умолчанию используется 0, чтобы мы могли вручную протестировать скрипт автоматической сборки.)
Далее у нас есть задача, которая устанавливает номер сборки в файл GlobalAssemblyInfo.cs, который мы связываем со всеми нашими проектами:
<Target Name="SetVersionNumber">
<RegexReplace
Pattern='AssemblyVersion\("(\d+\.\d+\.\d+)\.\d+"\)'
Replacement='AssemblyVersion("$1.$(BuildNumber)")'
Files='GlobalAssemblyInfo.cs'/>
<Exec Command="attrib -r xunit.installer\App.manifest"/>
</Target>
Это находит атрибут AssemblyVersion и заменяет номер версии a.b.c.d на a.b.c.BuildNumber. Обычно мы оставляем источник проверенным в дереве с фиксированными первыми тремя частями номера строителя, а четвертой - с нулем (например, сегодня это 1.0.2.0).
В процессе сборки убедитесь, что задача SetVersionNumber предшествует вашей задаче сборки. В конце мы используем нашу задачу Zip, чтобы сжать результаты сборки, чтобы у нас была история двоичных файлов для каждой автоматической сборки.