如何在TeamCity中自动实现C#/.Net/NuGet项目的版本管理?
解决TeamCity .NET/NuGet版本自动化的最佳实践
一、统一构建编号(BuildNum)同步
要解决stable和experimental构建编号不同步的问题,核心是让两个任务共享同一个构建编号序列,而不是各自维护独立计数器。这里分享两种实用方案:
方案1:TeamCity共享项目参数(快速落地)
- 在TeamCity中创建项目级别的计数器参数,比如
project.globalBuildNum,设置初始值为你当前的buildnum。 - 让stable和experimental两个构建任务都引用这个参数作为buildnum来源。
- 每次触发构建(无论stable还是experimental),TeamCity都会自动递增这个共享计数器,确保两个任务的buildnum完全同步。
- 版本格式处理:stable版本直接用
%major%.%minor%.%project.globalBuildNum%,experimental版本拼接为%major%.%minor%.%project.globalBuildNum%-Experimental。
方案2:仓库存储版本文件(更灵活,适配后续自动更新)
把版本信息(major、minor、buildnum)放在仓库的可编辑文件中,比如.NET项目友好的Version.props:
<Project> <PropertyGroup> <VersionMajor>1</VersionMajor> <VersionMinor>2</VersionMinor> <BuildNumber>45</BuildNumber> </PropertyGroup> </Project>
- 所有.NET项目的csproj中引用该文件,自动同步版本:
<Import Project="..\Version.props" /> <PropertyGroup> <Version>$(VersionMajor).$(VersionMinor).$(BuildNumber)</Version> <AssemblyVersion>$(Version)</AssemblyVersion> <FileVersion>$(Version)</FileVersion> </PropertyGroup> - 在TeamCity构建的第一步添加PowerShell脚本:
- 读取
Version.props中的当前BuildNumber - 将BuildNumber递增1
- 写回文件
- 读取
- 这样不管是stable还是experimental构建,都会基于同一个仓库中的BuildNumber递增,彻底解决同步问题。
二、自动更新Minor版本并推送仓库(不触发新构建)
当stable构建完成后自动递增Minor版本,更新仓库版本文件,且推送时不触发新构建,可按以下步骤实现:
步骤1:编写stable构建的版本更新脚本
在stable构建的最后添加PowerShell脚本步骤,完成以下操作:
# 读取Version.props文件 $propsPath = ".\Version.props" $xml = [xml](Get-Content $propsPath) # 递增Minor版本,重置BuildNumber为0(可选,根据你的版本规则调整) $currentMinor = [int]$xml.Project.PropertyGroup.VersionMinor $xml.Project.PropertyGroup.VersionMinor = $currentMinor + 1 $xml.Project.PropertyGroup.BuildNumber = 0 # 写回文件 $xml.Save($propsPath) # 提交并推送变更 git config user.name "TeamCity Build Agent" git config user.email "build-agent@yourcompany.com" git add $propsPath git commit -m "Auto-update minor version to $($xml.Project.PropertyGroup.VersionMajor).$($xml.Project.PropertyGroup.VersionMinor).0" git push origin master
步骤2:避免推送后触发新构建
在stable构建任务的「触发器」设置中,给VCS触发器添加排除规则:
-:Version.props
这样当版本文件的变更被推送时,不会触发新的stable构建,避免循环触发。
步骤3:配置仓库权限
确保TeamCity构建代理拥有仓库的读写权限(可通过SSH密钥或Personal Access Token实现),才能顺利提交并推送版本文件的变更。
三、完整流程梳理
- 日常开发:feature分支提交代码后触发experimental构建,脚本读取仓库版本文件、递增BuildNumber,生成
major.minor.buildnum-Experimental版本的NuGet包。 - stable发布:master-dev合并到master后触发stable构建:
- 读取版本文件、递增BuildNumber,生成正式版
major.minor.buildnum的NuGet包并发布。 - 执行版本更新脚本,递增Minor版本、重置BuildNumber(可选),提交并推送到仓库。
- 由于触发排除规则,这次版本提交不会触发新的stable构建。
- 读取版本文件、递增BuildNumber,生成正式版
- 后续构建:下一次experimental或stable构建,都会基于更新后的版本文件继续递增版本号。
额外优化建议
- 废弃AssemblyInfo修补:如果使用SDK风格.NET项目,已经通过csproj引用Version.props生成版本信息,无需再用TeamCity的「AssemblyInfo patcher」功能。
- 版本校验:在脚本中添加格式校验逻辑,确保版本号符合规则后再提交,避免错误修改。
- 测试验证:先在测试环境验证脚本的递增、提交推送逻辑,确保稳定后再应用到生产环境。
内容的提问来源于stack exchange,提问作者Sebastian P.
相关产品推荐
相关产品推荐

