熟悉.NET Framework的人知道,我们可以通过指定AssemblyVersion为10.0.*来让编译器自增版本号。但是.NET Core和.NET Standard不行。即使有MSBump这样的开源项目,也有一定的缺陷。一般这样的需求会出现在CI/CD服务器上。我们来看看如何用Azure DevOps轻松搞定。
关于.NET Core应用版本号
我曾经谐过一篇详细的.NET Core应用版本号的文章:https://edi.wang/post/2018/9/27/get-app-version-net-core有兴趣的可以先阅读一下,因为本文的内容会基于文中的知识。(域名可能被HX,微信用户可以复制到浏览器打开)我们这次要控制的,是Version字段。
就是它
使用.NET Core CLI的build命令直接编译出来的DLL会显示这个版本。
但其实,build命令是可以加参数的,想要在不更改csproj文件的情况下build一个自定义版本可以加个/p参数,指定Version,这样搞:
dotnet build /p:Version=10.0.8888.1234
基于这个原理,我们就能控制.NET Core应用程序在编译环境的版本号。
为毛不用 MSBump
可能有朋友知道这么一个项目:MSBump,也能用来在编译时改变版本号。但是,它在编译时候会去改csproj文件,对于代码来说是一次更改。而传统.NET Fx的编译系统不会改代码。这对于我来说是无法接受的,因为引入了不可控的因素。在多人团队本地build完竟然还要签入仅仅是更改了版本号的csproj文件,不是一种好方法。并且它的默认规则,不是根据时间戳来增加版本号的,而是根据本机当前工程文件的版本。所以在多人协作的代码库里对导致版本混乱。因此我决定放弃MSBump,尽量用微软自家技术,解决自家问题。
自动生成版本号
在全自动的CI环境,我们不可能每次手工干预指定版本号。我需要一种规则和方法去生成每次都不一样,并且一眼就能判断新旧的版本号。
我个人使用的规则是:主.次.距2000年1月1日的天数.幸运数字
其中要计算的是距2000年1月1日的天数。可以用Windows计算器按出来,也可以写程序算。但在自己动手造轮子之前,一个好习惯是看看微软是否已经有现成的工具可以完成。当然,微软一定是有的:PowerShell
PowerShell计算两个日期之间相差的天数,非常简单:
$baseDate = [datetime]"01/01/2000"
$currentDate = $(Get-Date)
$interval = NEW-TIMESPAN –Start $baseDate –End $currentDate
$days = $interval.Days
配置 Azure DevOps
有了以上的知识。我们要做的,就是让Azure DevOps在编译时,自动计算出版本号,然后给build命令加上/p:Version参数。怎么做呢?很简单!
环境变量
首先,我们需要一个变量,比如叫做 buildNumber
在编译定义的variables里可以添加。随便指定一个版本号就行。
PowerShell 任务
我们要使用PowerShell计算版本号,并给刚才那个 buildNumber 变量赋值。所以,添加一个PowerShell任务,放在最前面。
给Azure DevOps编译管线里的变量赋值,有个神奇的技巧,就是用Write-Host就可以了:
##vso[task.setvariable variable=变量名称]变量值
所以最终我们的脚本是
Write-Host "Generating Build Number"
$baseDate = [datetime]"01/01/2000"
$currentDate = $(Get-Date)
$interval = NEW-TIMESPAN –Start $baseDate –End $currentDate
$days = $interval.Days
Write-Host "##vso[task.setvariable variable=buildNumber]10.0.$days.1024"
在任务属性里选择inline,复制粘贴了这段代码。 //能跑就行,实在不行,删库跑路,也挺省心。
更改.NET Core任务参数
在Build及Publish任务的Arguments后面都加上:
/p:Version=$(buildNumber)
注意/p的前面有个空格
重跑编译,大功告成
触发一个CI/CD管线,可以看到日志中已经输出了正确的版本和参数。
并且部署完后,也能得到正确的版本了: