使用 TeamCity 进行程序集版本控制

发布于 2024-07-29 10:27:06 字数 409 浏览 5 评论 0 原文

我正在开发一个使用 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

撧情箌佬 2024-08-05 10:27:07

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

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

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

这里的另一个好处是,这也稍微加快了构建过程,因为它不需要遍历许多文件并进行更改。

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.

寂寞美少年 2024-08-05 10:27:06

我建议使用 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 或数据库:这不太可能,并且无论如何都需要大量工作)。

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:

  • Developers can build the solution in their machines.
  • You don't need to touch the .sln or .csproj files. It just works.
  • By using TeamCity variables you can easily make the version number match some other project's version, etc.

Disadvantages:

  • You can't easily switch to another CI server from TeamCity because you don't have a build script (but switching CI servers is like switching ORM or database: it is very unlikely and will require a lot of work anyway).
方觉久 2024-08-05 10:27:06

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

我在 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 可以让我们了解用户安装的版本,而无需将其作为程序集标识的一部分。

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 CI build has version numbers {Major.minor.BuildCounter.SvnRevision}
    • BuildCounter starts from 0
    • does not tag the svn repository
  • The Weekly/Release build has a similar versioning system, but
    • the build counter starts at (Major * 1000), so if Major is '8', the build counter starts from 8000.
    • Creates a tag called 'Build_{Version}' in the svn repository

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:

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)

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:

  • A private build performed on the developer's workstation
  • A CI build performed on the build server but which should not be released
  • An officially sanctioned release build, which is tagged in the Svn repository

In another twist, note that I am setting AssemblyFileVersion, not AssemblyVersion. 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.

情话墙 2024-08-05 10:27:06

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

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

  1. 导入额外的部分

    <导入项目=“$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets”/>

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

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

  4. 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:

  1. Import extra pieces

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

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

  3. Build: build the actual project file MSBuild script in release mode

  4. 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" />

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文