我正在开发一个使用 SVN 和 TeamCity 构建服务器的 C#/VB.Net 项目。 构建过程中会产生十多个组件。 我想控制程序集版本,以便它们全部匹配并匹配 TeamCity 构建标签。
我已将 TeamCity 配置为使用以下构建标签
主要.次要.{构建}.{修订}
其中 Major 和 Minor 是我手动设置的常量,{Revision} 由签出时的 SVN 存储库版本确定,而 {Build} 是 TeamCity 自动递增构建计数器。 所以一个示例构建标签是
2.5.437.4423
您建议采用哪些技术来确保所有程序集版本都与 TeamCity 构建标签匹配?
I'm working on a C#/VB.Net project that uses SVN and TeamCity build server. A dozen or so assemblies are produced by the build. I want to control the assembly versions so that they all match up and also match the TeamCity build label.
I've configured TeamCity to use a build label of
Major.Minor.{Build}.{Revision}
Where Major and Minor are constants that I set manually, {Revision} is determined by the SVN repository version at checkout and {Build} is a TeamCity auto-incrementing build counter. So an example build label would be
2.5.437.4423
What techniques would you suggest to ensure that all of the assembly versions match the TeamCity build label?
发布评论
评论(4)
尽管这已经有了一个公认的答案,但我想添加一个我们已经使用过的想法。
对于大型项目,可能有许多程序集信息文件需要更新,并且通过不断的重构,始终存在构建脚本不知道需要更新的新文件的风险。
因此,我们创建了一个简单的代码文件,它为实际版本定义了一个常量,然后所有项目都继承该常量并在程序集信息文件中继承我们。 那么构建脚本只需要更新一个文件。
这里的另一个好处是,这也稍微加快了构建过程,因为它不需要遍历许多文件并进行更改。
Even though this is already having an accepted answer, I would like to add an idea we have used.
For large projects there may be many assembly info files to update, and with constant re-factoring there is always the risk that the build script is not aware of new files that needs to be updated.
For this reason we have created a simple code file which defines a constant for the actual version and then all projects inherit this constant and us in the assembly info file. Then the build script need only update one file.
Another benefit here is that this is also speeding up the build process somewhat since it does not need to go through many files and change.
我建议使用 TeamCity 的 AssemblyInfo 修补程序构建功能:
http://confluence.jetbrains.net/ display/TCD65/AssemblyInfo+Patcher
只需从 VisualStudio 创建项目,在 BuildSteps 页面中配置构建功能(请参阅 http://confluence.jetbrains.net/display/TCD65/Adding+Build+Features),只要保留默认的 AssemblyInfo.cs 文件,它就可以工作。
这种方法对我来说非常有效。
优点:
缺点:
I'd suggest using TeamCity's AssemblyInfo patcher build feature:
http://confluence.jetbrains.net/display/TCD65/AssemblyInfo+Patcher
Just create your projects from VisualStudio, configure the build feature in the BuildSteps page (see http://confluence.jetbrains.net/display/TCD65/Adding+Build+Features), and as long as you keep the default AssemblyInfo.cs file, it will work.
This approach is working great for me.
Advantages:
Disadvantages:
我将哈米什的答案保留为已接受的答案,但为了完整起见,我认为值得记录我们最终采用的方法。
我在 TeamCity 中维护 2 个单独的构建配置,一个是 CI 构建,另一个是在有任何更改(或手动)时每周运行的构建,并且是我们的官方发布构建。 我选择了两次构建方法,因为构建端到端大约需要 40 分钟,并且我希望开发人员在提交更改时能够获得有关任何构建问题的快速反馈。 因此,CI 构建是完整发布构建的子集,但它确实构建了所有代码。 两个版本之间的版本控制也有所不同:
这样做的原因有些随意选择是为了让我们能够清楚、简单地区分 CI 构建和 Release 构建。
我们有一个名为 AssemblyVersionInfo 的解决方案范围文件,该文件包含(软链接)在解决方案的每个项目中。 该文件(实质上)包含以下内容:
因此,开发人员构建的所有版本都使用相同的静态且易于识别的版本号,该版本号高于构建服务器生成的任何版本号,因此在版本控制冲突中,开发人员的文件获胜。
在构建服务器上,我们使用 MSBuild 社区任务生成一个新的 AssemblyVersionInfo 文件来覆盖默认内容。 我们使用 TeamCity 构建字符串作为新版本。 这样,我们就可以轻松区分以下 3 种情况:
官方批准的发布构建,在 另一个变化,请注意我设置的是
AssemblyFileVersion
,而不是AssemblyVersion
。 我们强制我们的程序集版本为静态、固定版本字符串“Major.Minor.0.0”。 我们这样做是为了能够发布错误修复版本,而不必担心版本控制问题。 AssemblyFileVersion 可以让我们了解用户安装的版本,而无需将其作为程序集标识的一部分。I'm leaving Hamish's answer as the accepted answer, but for completeness I thought it would be worth documenting the approach we finally adopted.
I maintain 2 seperate build configurations in TeamCity, one is the CI build and another is a build that runs weekly when there are any changes (or manually) and is our official release build. I went for the two-build approach because the build takes perhaps 40 minutes end-to-end and I wanted developers to get a quick feedback on any build issues when they commit changes. The CI build therefore is a subset of the full release build but it does build all of the code. The versioning also differs between the two builds:
The reason for this somewhat arbitrary choice is to allow us to clearly and simply distinguish between CI builds and Release builds.
We have a solution-wide file called AssemblyVersionInfo that is included (soft linked) in every project in the solution. The file contains (in essence) this:
So developer builds all use the same static and readily identifiable version number, which is higher than anything produced by the build server so that in a versioning conflict, the developer's file wins.
On the build server, we us MSBuild Community Tasks to generate a new AssemblyVersionInfo file that overwrites the default content. We use the TeamCity build string as the new version. In this way, we can easily distinguish between the following 3 situations:
In another twist, note that I am setting
AssemblyFileVersion
, notAssemblyVersion
. We force our assembly versions to be a static, fixed version string of 'Major.Minor.0.0'. We do this so that we are able to issue bug fix releases without having to worry about versioning issues. The AssemblyFileVersion lets us figure out what build a user has installed without it being part of the assembly's identity.我们使用 CruiseControl.net 和 SVN。 我们以另一种方式驾驶它。 我们在 MSBuild 脚本中使用 MSBuildCommunityTasks 版本任务来增加 CI 构建的版本号并使用该版本用于标记源代码的编号。
编辑:询问有关 MSBuild 目标的更多详细信息...
我们使用一个单独的脚本用于 CI 构建,而不用于开发人员构建。 我们尝试在 Studio 用作项目文件的 MSBuild 文件中使用不同的目标,但这很令人头痛,并且需要手动编辑 Studio 生成的文件。
MSBuild 文件的结构非常简单:
导入额外的部分
<导入项目=“$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets”/>
BeforeBuild:设置新版本号并重写AssemblyInfo文件
OutputFile="Properties\AssemblyInfo.cs"
AssemblyTitle="$(TargetAssembly)"
AssemblyDescription="$(AssemblyDescription) svn:@(SanitizedSvnUrl) 修订版:$(SvnRevision)"
AssemblyCompany="您的公司名称"
AssemblyProduct="产品名称"
AssemblyCopyright="版权所有 © 贵公司 2009"
ComVisible="false" Guid="$(WindowGuid)"
AssemblyVersion="$(主要).$(次要).$(构建).$(修订)"
AssemblyFileVersion="$(主要).$(次要).$(构建).$(修订)"
Condition="$(Revision) != '0' " />
Build:在发布模式下构建实际的项目文件 MSBuild 脚本
AfterBuild:我们运行我们的单元测试项目(作为防止在后续步骤中为损坏的构建创建标签的防护),使用 SvnInfo 任务和一些 RegexReplace 任务来设置一些带有路径和标签名称的变量,并使用 SvnCopy 任务创建标签。
密码=“密码”
SourcePath="@(SvnTrunkPath)"
DestinationPath="@(SvnTagsPath)/BUILD-$(TargetAssembly)-$(主要).$(次要).$(构建).$(修订)"
Message="标记成功构建"/>
We're using CruiseControl.net and SVN. We drive it the other way. We are using the MSBuildCommunityTasks Version task in an MSBuild script to increment the version number for CI builds and using that version number to tag the source code.
EDIT: Asked for more detail on MSBuild targets...
We use a separate script that is for the CI build and is not used for the developer builds. We tried using different targets in the MSBuild files that studio uses as project files but this got to be a headache and required manual editing of files that studio was generating.
The structure of the MSBuild file is pretty straightforward:
Import extra pieces
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<!-- contains some variables that set project names, paths etc. -->
<Import Project="Properties.msbuild"/>
BeforeBuild: set new version number and rewrite the AssemblyInfo file
<Version VersionFile="$(VersionFile)" BuildType="None" RevisionType="Increment">
<Output TaskParameter="Major" PropertyName="Major" />
<Output TaskParameter="Minor" PropertyName="Minor" />
<Output TaskParameter="Build" PropertyName="Build" />
<Output TaskParameter="Revision" PropertyName="Revision" />
</Version>
<!--Modify Assembly Info-->
<AssemblyInfo CodeLanguage="CS"
OutputFile="Properties\AssemblyInfo.cs"
AssemblyTitle="$(TargetAssembly)"
AssemblyDescription="$(AssemblyDescription) svn:@(SanitizedSvnUrl) revision:$(SvnRevision)"
AssemblyCompany="Your company name"
AssemblyProduct="Name of product"
AssemblyCopyright="Copyright © your company 2009"
ComVisible="false" Guid="$(WindowGuid)"
AssemblyVersion="$(Major).$(Minor).$(Build).$(Revision)"
AssemblyFileVersion="$(Major).$(Minor).$(Build).$(Revision)"
Condition="$(Revision) != '0' " />
Build: build the actual project file MSBuild script in release mode
AfterBuild: we run our unit test projects (as a guard against creating tags for broken builds in the next steps), use the SvnInfo tasks and some RegexReplace tasks to set some variables up with paths and tag names, and use the SvnCopy task to create the tag.
<SvnCopy UserName="username"
Password="password"
SourcePath="@(SvnTrunkPath)"
DestinationPath="@(SvnTagsPath)/BUILD-$(TargetAssembly)-$(Major).$(Minor).$(Build).$(Revision)"
Message="Tagging successful build" />