.net 如何通过我们的 CI 平台 (Hudson) 自动增加 C# 程序集版本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1126880/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I auto increment the C# assembly version via our CI platform (Hudson)?
提问by Allen Rice
Myself and my group are horrendous at incrementing assembly version numbers and we frequently ship assemblies with 1.0.0.0 versions. Obviously, this causes a lot of headaches.
我和我的团队在增加程序集版本号方面非常糟糕,我们经常发布 1.0.0.0 版本的程序集。显然,这会引起很多头痛。
We're getting a lot better with our practices via our CIplatform and I'd really like to set it up to auto increment the values within the assemblyinfo.csfile so that the versions of our assemblies are auto updated with the code changes in that assembly.
通过我们的CI平台,我们的实践变得更好了,我真的很想将它设置为自动增加assemblyinfo.cs文件中的值,以便我们的程序集版本会随着该程序集中的代码更改自动更新。
I had previously setup (before we found Hudson) a way to increment the value through either msbuildor the command line (can't remember), but with Hudson, that will update the SVN repository and trigger ANOTHER build. That would result in a slow infinite loop as Hudson polls SVN every hour.
我之前(在我们找到Hudson之前)设置了一种通过msbuild命令行或命令行增加值的方法(不记得了),但是对于 Hudson,这将更新 SVN 存储库并触发另一个构建。这将导致缓慢的无限循环,因为 Hudson 每小时轮询一次 SVN。
Is having Hudson increment the version number a bad idea? What would be an alternative way to do it?
让 Hudson 增加版本号是个坏主意吗?有什么替代方法可以做到?
Ideally, my criteria for a solution would be one that:
理想情况下,我的解决方案标准是:
- Increments the build number in
assemblyinfo.csbefore a build - Only increments the build number in assemblies that have changed. This may not be possible as Hudson wipes out the project folder every time it does a build
- Commits the changed assemblyinfo.cs into the code repository (currently VisualSVN)
- Does not cause Hudson to trigger a new build the next time it scans for changes
- 在构建
assemblyinfo.cs之前增加构建号 - 仅增加已更改的程序集中的内部版本号。这可能是不可能的,因为 Hudson 每次构建时都会清除项目文件夹
- 将更改的 assemblyinfo.cs 提交到代码存储库(当前为VisualSVN)
- 不会导致 Hudson 在下次扫描更改时触发新构建
Working this out in my head, I could easily come up with a solution to most of this through batch files / commands, but all of my ideas would cause Hudson to trigger a new build the next time it scans. I'm not looking for someone to do everything for me, just point me in the right direction, maybe a technique to get Hudson to ignore certain SVN commits, etc.
在我的脑海中解决这个问题,我可以很容易地通过批处理文件/命令来解决大部分问题,但是我的所有想法都会导致 Hudson 在下次扫描时触发新构建。我不是在找人为我做所有事情,只是指出我正确的方向,也许是一种让 Hudson 忽略某些 SVN 提交的技术,等等。
Everything I've found so far is just an article explaining how to get the version number automatically incremented, nothing takes into account a CI platform that could be spun into an infinite loop.
到目前为止,我发现的所有内容都只是解释如何让版本号自动递增的文章,没有考虑到可以陷入无限循环的 CI 平台。
采纳答案by Greg D
A simple alternative is to let the C# environment increment the assembly version for you by setting the version attribute to major.minor.*(as described in the AssemblyInfo file template.)
一个简单的替代方法是通过将版本属性设置为major.minor.*(如 AssemblyInfo 文件模板中所述),让 C# 环境为您增加程序集版本。
You may be looking for a more comprehensive solution, though.
不过,您可能正在寻找更全面的解决方案。
EDIT(Response to the question in a comment):
编辑(在评论中回答问题):
From AssemblyInfo.cs:
来自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.*")]
回答by nos
Here's what I did, for stamping the AssemblyFileVersion attribute.
这是我所做的,用于标记 AssemblyFileVersion 属性。
Removed the AssemblyFileVersion from AssemblyInfo.cs
从 AssemblyInfo.cs 中删除了 AssemblyFileVersion
Add a new, empty, file called AssemblyFileInfo.cs to the project.
向项目添加一个名为 AssemblyFileInfo.cs 的新空文件。
Install the MSBuild community taskstoolset on the hudson build machine or as a NuGet dependencyin your project.
在 hudson 构建机器上或作为项目中的NuGet 依赖项安装MSBuild 社区任务工具集。
Edit the project (csproj) file , it's just an msbuild file, and add the following.
编辑项目 (csproj) 文件,它只是一个 msbuild 文件,并添加以下内容。
Somewhere there'll be a <PropertyGroup>stating the version. Change that so it reads e.g.
某处会有一个<PropertyGroup>说明版本。更改它,使其读取例如
<Major>1</Major>
<Minor>0</Minor>
<!--Hudson sets BUILD_NUMBER and SVN_REVISION -->
<Build>$(BUILD_NUMBER)</Build>
<Revision>$(SVN_REVISION)</Revision>
Hudson provides those env variables you see there when the project is built on hudson (assuming it's fetched from subversion).
当项目建立在 hudson 上时,Hudson 提供了你在那里看到的那些 env 变量(假设它是从 subversion 获取的)。
At the bottom of the project file, add
在项目文件的底部,添加
<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>
This uses the MSBuildCommunityTasks to generate the AssemblyFileVersion.cs to include an AssemblyFileVersion attribute before the project is built. You could do this for any/all of the version attributes if you want.
这使用 MSBuildCommunityTasks 生成 AssemblyFileVersion.cs 以在生成项目之前包含 AssemblyFileVersion 属性。如果需要,您可以对任何/所有版本属性执行此操作。
The result is, whenever you issue a hudson build, the resulting assembly gets an AssemblyFileVersion of 1.0.HUDSON_BUILD_NR.SVN_REVISION e.g. 1.0.6.2632 , which means the 6'th build # in hudson, buit from the subversion revision 2632.
结果是,每当您发布 hudson 构建时,生成的程序集都会获得 1.0.HUDSON_BUILD_NR.SVN_REVISION 的 AssemblyFileVersion,例如 1.0.6.2632 ,这意味着 hudson 中的第 6 个构建 #,来自 subversion 修订版 2632。
回答by sondlerd
Here is an elegant solution that requires a little work upfront when adding a new project but handles the process very easily.
这是一个优雅的解决方案,在添加新项目时需要一些前期工作,但处理过程非常容易。
The idea is that each project links to a Solution file that only contains the assembly version information. So your build process only has to update a single file and all of the assembly versions pull from the one file upon compilation.
这个想法是每个项目都链接到一个只包含程序集版本信息的解决方案文件。所以你的构建过程只需要更新一个文件,所有的程序集版本在编译时从一个文件中提取。
Steps:
脚步:
- Add a class to you solution file *.cs file, I named min SharedAssemblyProperties.cs
- Remove all of the cs information from that new file
- Cut the assembly information from an AssemblyInfo file: [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]
- Add the statement "using System.Reflection;" to the file and then paste data into your new cs file (ex SharedAssemblyProperties.cs)
- Add an existing item to you project (wait... read on before adding the file)
- Select the file and before you click Add, click the dropdown next to the add button and select "Add As Link".
- Repeat steps 5 and 6 for all existing and new projects in the solution
- 向您的解决方案文件 *.cs 文件添加一个类,我命名为 min SharedAssemblyProperties.cs
- 从该新文件中删除所有 cs 信息
- 从 AssemblyInfo 文件中剪切程序集信息:[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]
- 添加语句“使用 System.Reflection;” 到文件,然后将数据粘贴到新的 cs 文件中(例如 SharedAssemblyProperties.cs)
- 将现有项目添加到您的项目(等待...在添加文件之前阅读)
- 选择文件,然后在单击添加之前,单击添加按钮旁边的下拉列表并选择“添加为链接”。
- 对解决方案中的所有现有项目和新项目重复步骤 5 和 6
When you add the file as a link, it stores the data in the project file and upon compilation pulls the assembly version information from this one file.
当您将文件添加为链接时,它会将数据存储在项目文件中,并在编译时从该文件中提取程序集版本信息。
In you source control, you add a bat file or script file that simply increments the SharedAssemblyProperties.cs file and all of your projects will update their assembly information from that file.
在您的源代码控制中,您添加一个 bat 文件或脚本文件,它只是增加 SharedAssemblyProperties.cs 文件,您的所有项目都将从该文件更新它们的程序集信息。
回答by Matthew Blackford
Hudson can be configured to ignore changes to certain paths and files so that it does not prompt a new build.
Hudson 可以配置为忽略对某些路径和文件的更改,以便它不会提示新构建。
On the job configuration page, under Source Code Management, click the Advancedbutton. In the Excluded Regionsbox you enter one or more regular expression to match exclusions.
在作业配置页面上,在Source Code Management 下,单击Advanced按钮。在排除区域框中输入一个或多个正则表达式以匹配排除项。
For example to ignore changes to the version.propertiesfile you can use:
例如要忽略对version.properties文件的更改,您可以使用:
/MyProject/trunk/version.properties
This will work for languages other than C# and allows you to store your version info within subversion.
这适用于 C# 以外的语言,并允许您将版本信息存储在 subversion 中。
回答by Kyle Trauberman
.NET does this for you. In your AssemblyInfo.cs file, set your assembly version to major.minor.* (for example: 1.0.*).
.NET 为您做这件事。在您的 AssemblyInfo.cs 文件中,将您的程序集版本设置为 Major.minor.*(例如:1.0.*)。
When you build your project the version is auto generated.
当您构建项目时,版本是自动生成的。
The build and revision numbers are generated based on the date, using the unix epoch, I believe. The build is based on the current day, and the revision is based on the number of seconds since midnight.
我相信,构建和修订号是根据日期生成的,使用的是 unix epoch。构建基于当天,修订基于自午夜以来的秒数。
回答by TonyG
I've never actually seen that 1.0.* feature work in VS2005 or VS2008. Is there something that needs to be done to set VS to increment the values?
我从未真正见过 1.0.* 功能在 VS2005 或 VS2008 中工作。是否需要做一些事情来设置 VS 以增加值?
If AssemblyInfo.cs is hardcoded with 1.0.*, then where are the real build/revision stored?
如果 AssemblyInfo.cs 使用 1.0.* 硬编码,那么真正的构建/修订存储在哪里?
After putting 1.0.* in AssemblyInfo, we can't use the following statement because ProductVersion now has an invalid value - it's using 1.0.* and not the value assigned by VS:
将 1.0.* 放入 AssemblyInfo 后,我们不能使用以下语句,因为 ProductVersion 现在具有无效值 - 它使用 1.0.* 而不是 VS 分配的值:
Version version = new Version(Application.ProductVersion);
Sigh - this seems to be one of those things that everyone asks about but somehow there's never a solid answer. Years ago I saw solutions for generating a revision number and saving it into AssemblyInfo as part of a post-build process. I hoped that sort of dance wouldn't be required for VS2008. Maybe VS2010?
叹息 - 这似乎是每个人都在问的事情之一,但不知何故,从来没有一个可靠的答案。几年前,我看到了生成修订号并将其保存到 AssemblyInfo 作为后期构建过程的一部分的解决方案。我希望 VS2008 不需要那种舞蹈。也许VS2010?
回答by MikeS
I am assuming one might also do this with a text templatewhere you create the assembly attributes in question on the fly from the environment like AssemblyVersion.tt does below.
我假设人们也可以使用文本模板来执行此操作,您可以在其中从诸如下面的 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#>")]
回答by aggaton
As a continuation of MikeS's answer I wanted to add that VS + Visual Studio Visualization and Modeling SDK needs to be installed for this to work, and you need to modify the project file as well. Should also be mentioned I use Jenkins as build server running on a windows 2008 R2 server box with version module, where I get the BUILD_NUMBER.
作为 MikeS 回答的延续,我想补充一点,需要安装 VS + Visual Studio Visualization and Modeling SDK 才能正常工作,并且您还需要修改项目文件。还应该提到我使用 Jenkins 作为在带有版本模块的 Windows 2008 R2 服务器盒上运行的构建服务器,在那里我获得了 BUILD_NUMBER。
My Text Template file version.tt looks like this
我的文本模板文件 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#>")]
I have the following in the Property Groups
我在属性组中有以下内容
<PropertyGroup>
<TransformOnBuild>true</TransformOnBuild>
<OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
<TransformOutOfDateOnly>false</TransformOutOfDateOnly>
</PropertyGroup>
after import of Microsoft.CSharp.targets, I have this (dependant of where you install VS
导入 Microsoft.CSharp.targets 后,我有这个(取决于您安装 VS 的位置
<Import Project="C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\TextTemplating\v10.0\Microsoft.TextTemplating.targets" />
On my build server I then have the following script to run the text transformation before the actual build, to get the last changeset number on TFS
在我的构建服务器上,我使用以下脚本在实际构建之前运行文本转换,以获取 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>
This way I can keep track of builds AND changesets, so if I haven't checked anything in since last build, the last digit should not change, however I might have made changes to the build process, hence the need for the second last number. Of course if you make multiple check-ins before a build you only get the last change reflected in the version. I guess you could concatenate of that is required.
这样我就可以跟踪构建和变更集,所以如果我自上次构建以来没有检查过任何东西,最后一位数字不应该改变,但是我可能对构建过程进行了更改,因此需要倒数第二个数字. 当然,如果您在构建之前进行多次签入,您只会得到版本中反映的最后一次更改。我想你可以连接它是必需的。
I'm sure you can do something fancier and call TFS directly from within the tt Template, however this works for me.
我相信您可以做一些更有趣的事情并直接从 tt 模板中调用 TFS,但这对我有用。
I can then get my version at runtime like this
然后我可以像这样在运行时获取我的版本
Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
return fvi.FileVersion;
回答by johnwbyrd
My solution doesn't require the addition of external tools or scripting languages --it's pretty much guaranteed to work on your build machine. I solve this problem in several parts. First, I have created a BUILD.BAT file that converts the Jenkins BUILD_NUMBER parameter into an environment variable. I use Jenkins's "Execute Windows batch command" function to run the build batch file by entering the following information for the Jenkins build:
我的解决方案不需要添加外部工具或脚本语言——它几乎可以保证在您的构建机器上工作。我分几个部分解决这个问题。首先,我创建了一个 BUILD.BAT 文件,它将 Jenkins BUILD_NUMBER 参数转换为环境变量。我使用Jenkins的“执行Windows批处理命令”功能通过为Jenkins构建输入以下信息来运行构建批处理文件:
./build.bat --build_id %BUILD_ID% -build_number %BUILD_NUMBER%
In the build environment, I have a build.bat file that starts as follows:
在构建环境中,我有一个 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
Once I did that, I right-clicked on the project to be built in Visual Studio's Solution Explorer pane and selected Properties, select Build Events, and entered the following information as the Pre-Build Event Command Line, which automatically creates a .cs file containing build number information based on current environment variable settings:
一旦我这样做了,我在 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%
You may need to adjust to your build taste. I build the project manually once to generate an initial Version.cs file in the Properties directory of the main project. Lastly, I manually include the Version.cs file into the Visual Studio solution by dragging it into the Solution Explorer pane, underneath the Properties tab for that project. In future builds, Visual Studio then reads that .cs file at Jenkins build time and gets the correct build number information out of it.
您可能需要根据自己的构建品味进行调整。我手动构建项目一次,以在主项目的 Properties 目录中生成初始 Version.cs 文件。最后,我通过将 Version.cs 文件拖到该项目的“属性”选项卡下方的“解决方案资源管理器”窗格中,手动将 Version.cs 文件包含到 Visual Studio 解决方案中。在未来的构建中,Visual Studio 然后在 Jenkins 构建时读取该 .cs 文件并从中获取正确的构建号信息。
回答by jonnybot
So, we have a project with one solution that contains several projects that have assemblies with different version numbers.
因此,我们有一个包含一个解决方案的项目,其中包含多个具有不同版本号的程序集的项目。
After investigating several of the above methods, I just implemented a build step to run a Powershell script that does a find-and-replace on the AssemblyInfo.cs file. I still use the 1.0.* version number in source control, and Jenkins just manually updates the version number before msbuild runs.
在研究了上述几种方法之后,我刚刚实施了一个构建步骤来运行一个 Powershell 脚本,该脚本对 AssemblyInfo.cs 文件进行查找和替换。我在源代码管理中仍然使用 1.0.* 版本号,Jenkins 只是在 msbuild 运行之前手动更新版本号。
dir **/Properties/AssemblyInfo.cs | %{ (cat $_) | %{$_ -replace '^(\s*)\[assembly: AssemblyVersion\("(.*)\.\*"\)', "`[assembly: AssemblyVersion(`"`.$build`")"} | Out-File $_ -Encoding "UTF8" }
dir **/Properties/AssemblyInfo.cs | %{ (cat $_) | %{$_ -replace '^(\s*)\[assembly: AssemblyFileVersion\("(.*)\.\*"\)', "`[assembly: AssemblyFileVersion(`"`.$build`")"} | Out-File $_ -Encoding "UTF8" }
I added the -Encoding "UTF8" option because git started treating the .cs file as binary files if I didn't. Granted, this didn't matter, since I never actually commit the result; it just came up as I was testing.
我添加了 -Encoding "UTF8" 选项,因为如果我没有,git 开始将 .cs 文件视为二进制文件。当然,这并不重要,因为我从未真正提交过结果;它只是在我测试时出现。
Our CI environment already has a facility to associate the Jenkins build with the particular git commit (thanks Stash plugin!), so I don't worry that there's no git commit with the version number attached to it.
我们的 CI 环境已经有一个工具可以将 Jenkins 构建与特定的 git commit 相关联(感谢 Stash 插件!),所以我不担心没有附带版本号的 git commit。

