【问题标题】:Assembly Versioning with TeamCity使用 TeamCity 进行程序集版本控制
【发布时间】:2010-11-16 10:22:37
【问题描述】:

我正在开发一个使用 SVN 和 TeamCity 构建服务器的 C#/VB.Net 项目。构建产生了十几个程序集。我想控制程序集版本,使它们都匹配并匹配 TeamCity 构建标签。

我已将 TeamCity 配置为使用构建标签

Major.Minor.{Build}.{Revision}

其中 Major 和 Minor 是我手动设置的常量,{Revision} 由结帐时的 SVN 存储库版本确定,{Build} 是 TeamCity 自动递增的构建计数器。所以一个示例构建标签将是

2.5.437.4423

您会建议哪些技术来确保所有程序集版本都匹配 TeamCity 构建标签?

【问题讨论】:

  • 我想我还应该问:您如何管理由个人开发人员完成的私有构建与由 TeamCity 完成的自动构建的版本号?
  • [像往常一样] 意见不一……如果开发人员只是简单地从 Visual Studio 构建出来,那么他们会在程序集信息文件中获得默认值。如果开发人员使用/构建脚本,您可以选择使它们不同。我将本地构建版本号设置为 0.0.0.DaysSinceBeginningOfProject 的一个项目。这是在 ci 的早期阶段并完成的,因此我可以检测到任何手动放置在环境中的本地构建的程序集(而不是使用构建包/部署脚本)。 /jhd

标签: version-control build-automation teamcity


【解决方案1】:

我们使用 CruiseControl.net 和 SVN。我们以另一种方式驾驶它。我们在 MSBuild 脚本中使用 MSBuildCommunityTasks Version 任务来增加 CI 构建的版本号,并使用该版本号来标记源代码。

编辑: 询问有关 MSBuild 目标的更多详细信息...
我们使用单独的脚本用于 CI 构建,而不用于开发人员构建。我们尝试在 Studio 用作项目文件的 MSBuild 文件中使用不同的目标,但这让人头疼,并且需要手动编辑 Studio 生成的文件。
MSBuild 文件的结构非常简单:

  1. 导入额外的部分

    <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
    <!-- contains some variables that set project names, paths etc. -->
    <Import Project="Properties.msbuild"/>

  2. BeforeBuild:设置新版本号并重写AssemblyInfo文件

    <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' " />

  3. Build:在release模式下构建实际项目文件MSBuild脚本

  4. AfterBuild:我们运行我们的单元测试项目(以防止在接下来的步骤中为损坏的构建创建标签),使用 SvnInfo 任务和一些 RegexReplace 任务来设置一些带有路径和标签名称的变量,以及使用 SvnCopy 任务来创建标签。

<SvnCopy UserName="username"
Password="password"
SourcePath="@(SvnTrunkPath)"
DestinationPath="@(SvnTagsPath)/BUILD-$(TargetAssembly)-$(Major).$(Minor).$(Build).$(Revision)" Message="Tagging successful build" />

【讨论】:

  • 是否可以稍微扩展一下这个答案?例如,MSBuild 目标是什么样的?
  • 恕我直言,问题不在于使用什么 CI 系统,而在于如何在 TeamCity 中实施特定任务。
  • @arconaut:谢谢。我的回答中没有说@Tim Long 应该使用 CC.NET,我只是用我正在使用的工具作为答案的开头,以便清楚为什么答案不是专门针对 TeamCity。
【解决方案2】:

我建议使用 TeamCity 的 AssemblyInfo 修补程序构建功能:

http://confluence.jetbrains.net/display/TCD65/AssemblyInfo+Patcher

只需从 VisualStudio 创建您的项目,在 BuildSteps 页面中配置构建功能(请参阅http://confluence.jetbrains.net/display/TCD65/Adding+Build+Features),只要您保留默认的 AssemblyInfo.cs 文件,它就可以工作。

这种方法对我很有效。

优点:

  • 开发人员可以在他们的机器中构建解决方案。
  • 您无需接触 .sln 或 .csproj 文件。它只是工作。
  • 通过使用 TeamCity 变量,您可以轻松地使版本号与其他项目的版本等匹配。

缺点:

  • 您无法轻松地从 TeamCity 切换到另一个 CI 服务器,因为您没有构建脚本(但切换 CI 服务器就像切换 ORM 或数据库:这不太可能,而且无论如何都需要大量工作)。

【讨论】:

    【解决方案3】:

    我将 Hamish 的答案作为已接受的答案,但为了完整起见,我认为值得记录我们最终采用的方法。

    我在 TeamCity 中维护 2 个单独的构建配置,一个是 CI 构建,另一个是每周运行(或手动)有任何更改时运行的构建,并且是我们的正式发布构建。我选择了两次构建方法,因为端到端构建可能需要 40 分钟,而且我希望开发人员在提交更改时能够快速获得有关任何构建问题的反馈。因此,CI 构建是完整版本构建的子集,但它确实构建了所有代码。两个版本之间的版本控制也不同:

    • CI 版本的版本号为 {Major.minor.BuildCounter.SvnRevision}
      • BuildCounter 从 0 开始
      • 不标记 svn 存储库
    • Weekly/Release 版本具有类似的版本控制系统,但
      • 构建计数器从 (Major * 1000) 开始,因此如果 Major 为“8”,则构建计数器从 8000 开始。
      • 在 svn 存储库中创建一个名为“Build_{Version}”的标签

    这种有点武断的选择的原因是为了让我们能够清楚而简单地区分 CI 构建和 Release 构建。

    我们有一个名为 AssemblyVersionInfo 的解决方案范围的文件,该文件包含(软链接)在解决方案的每个项目中。该文件(本质上)包含以下内容:

    using System.Reflection;
    // Revision and Build both set to 9999 indicates a private build on a developer's private workstation.
    [assembly: AssemblyFileVersion("6.0.9999.9999")]        // Win32 File Version (not used by .NET)
    

    因此,所有开发人员构建都使用相同的静态且易于识别的版本号,该版本号高于构建服务器生成的任何版本,因此在版本控制冲突中,开发人员的文件胜出。

    在构建服务器上,我们使用 MSBuild 社区任务来生成覆盖默认内容的新 AssemblyVersionInfo 文件。我们使用 TeamCity 构建字符串作为新版本。这样,我们就很容易区分以下3种情况:

    • 在开发人员的工作站上执行的私有构建
    • 在构建服务器上执行但不应发布的 CI 构建
    • 官方认可的发布版本,标记在 Svn 存储库中

    另外,请注意我设置的是AssemblyFileVersion,而不是AssemblyVersion。我们强制我们的程序集版本是“Major.Minor.0.0”的静态、固定版本字符串。我们这样做是为了能够发布错误修复版本,而不必担心版本控制问题。 AssemblyFileVersion 让我们能够确定用户安装了哪些构建,而不会将它作为程序集身份的一部分。

    【讨论】:

    • @RobBird +1 为您评论 AssemblyFileVersion 提示 ;) 否则会错过它。
    • @TimLong 你如何用更新的 AssemblyVersionInfo 标记代码? teamcity 仅来自主干的标签。
    【解决方案4】:

    即使这已经有一个公认的答案,我想添加一个我们使用过的想法。

    对于大型项目,可能有许多程序集信息文件需要更新,并且随着不断重构,构建脚本始终存在构建脚本不知道需要更新的新文件的风险。

    出于这个原因,我们创建了一个简单的代码文件,它为实际版本定义了一个常量,然后所有项目都继承了这个常量,我们在程序集信息文件中继承了这个常量。那么构建脚本只需要更新一个文件。

    这里的另一个好处是,这也在一定程度上加快了构建过程,因为它不需要遍历许多文件和更改。

    【讨论】:

      猜你喜欢
      • 2010-10-01
      • 1970-01-01
      • 2018-06-16
      • 1970-01-01
      • 1970-01-01
      • 2011-01-02
      • 1970-01-01
      • 1970-01-01
      • 2013-02-21
      相关资源
      最近更新 更多