使用 GitVersion 在编译或持续构建时自动使用语义版本号(Semantic Versioning)
我们在之前谈过 语义版本号(Semantic Versioning),在项目中应用语义版本号能够帮助库的开发者在发布包时表明更多的语义信息。这是趋势,从微软的博客 Versioning NuGet packages in a continuous delivery world 三部曲中可以看出,从 NuGet 4.3.0 以及 Visual Studio 2017 15.3 以上版本开始支持语义版本号 2.0 也能看出。
本文将从持续集成的角度来说语义版本号,告诉大家如何自动生成包含语义的版本号,并在发布库时采用。
安装 GitVersionTask
微软工程师在博客 Versioning NuGet packages in a continuous delivery world: part 3 – Microsoft DevOps Blog 中推荐的语义版本号生成工具是 GitVersion。从实际寻找来看,这似乎也是唯一一个能够让 NuGet 包支持语义版本号的工具。
去 NuGet.org 上为我们的库项目安装 GitVersionTask 即可开始我们的语义版本号。
请特别注意:
- 目前只有 GitVersionTask 4.0 以上的版本(目前都是 beta)才支持 .NET Core 那样新格式的 csproj。
- 目前即便是最新测试版的 GitVersionTask 也不支持使用基于 .NET Core 的
dotnet build编译,原因和解决方案我已经提交给 GitTools 团队了(详见:dotnet buildcommand always fails with GitVersionTask 4.0.0-beta · Issue #1399 · GitTools/GitVersion),临时方案是使用 .NET Framework 版本的msbuild。
配置 GitVersion
特别吐槽一下 GitVersion 的官方文档,把功能堆积得很多很强大,却忽视了面向新手的入门教程。
GitVersion 的配置文件名为 GitVersion.yml,要求放到仓库的根目录下。官方文档对于配置文件的解释非常抽象,看完也不知道值应该写成什么样,也不知道每个值代表什么意义。于是我基本上是通过阅读它的源码来了解配置文件的实际含义的。
经过一番折腾,我把配置文件改成了下面这样。
next-version: 1.0
mode: ContinuousDelivery
increment: Inherit
tag-prefix: '[vV]'
source-branches: ['master', 'develop', 'hotfix']
ignore:
sha: []
commits-before: 2018-01-01T00:00:00
branches:
master:
regex: master$
mode: ContinuousDelivery
tag: ''
increment: Patch
prevent-increment-of-merged-branch-version: true
track-merge-target: false
tracks-release-branches: false
is-release-branch: true
release:
regex: r(elease$|(eleases)?[-/])
mode: ContinuousDelivery
tag: beta
increment: Patch
prevent-increment-of-merged-branch-version: true
track-merge-target: false
tracks-release-branches: false
is-release-branch: true
feature:
regex: f(eatures)?[-/]
mode: ContinuousDeployment
tag: alpha
increment: Minor
prevent-increment-of-merged-branch-version: false
track-merge-target: false
tracks-release-branches: false
is-release-branch: false
▲ 别看这配置文件写得这么长,但其实官方的默认配置文件更长!
好了不开玩笑了,这配置文件分两部分来看:1. branches 之前;2. branches 之后。
写在 branches 之前的为全局配置,写在 branches 之后的是按分支分类的配置;它们的配置键值其实都是一样的。分支里的配置优先级高于全局配置。也就是说,如果编译打包的分支名能被 regex 正则表达式匹配上,那么就使用匹配的分支配置,否则使用全局配置。
举例,假设我们现在的版本库是这样的:

分支名称匹配 regex
那么当我们在 release 分支的 f 提交上编译,使用的配置将是 release 分支的配置。
由于我将 release 分支的正则表达式写成了 r(elease$|(eleases)?[-/])(注意,我们不需要加行首标记 ^,因为 GitVersionTask 里会为我们在最前面加一个),所以类似这样的分支名也是使用 release 分支的配置:
r/1.2.0releases/1.2.0release
但是,这样的分支名将采用默认的全局配置(因为不符合正则表达式):
rreleases
以上配置中我只列举了三组分支,但其实在 一个成功的 Git 分支流模型 中,还有 hotfix develop 这样更多的分支。如果你的项目足够大,建议自己参考其他分支写出这两个分支的配置出来。
预发布标签 tag
我们的 release 配置中,会为版本号加一个 beta 预发布标签,所以可能打出 2.0.0-beta 这样的包出来,或者 2.0.0-beta+3。但在全局配置下,默认打出的包会加一个以分支名命名的预发布标签;像这样 2.0.0-r(在 r 分支),或者 2.0.0-temp-walterlv-custombranch(在 temp/walterlv/custombranch 分支)。
继续看以上的配置,在 f/blog 或 features/new 分支上将采用 alpha 预发布标签。
我们在 master 分支的配置上
版本号递增规则 increment
increment 这一项的可选值有 Major、Minor、Patch、None 和 Inherit 五种。
Major如果此前在 Git 仓库此分支前有一个 1.2.0 的 Tag,那么现在将打出 2.0.0 的包来(无论此分支当前距离那个 Tag 有多少个提交,都只加 1)Minor如果此前在 Git 仓库此分支前有一个 1.2.0 的 Tag,那么现在将打出 1.3.0 的包来(无论此分支当前距离那个 Tag 有多少个提交,都只加 1)Patch如果此前在 Git 仓库此分支前有一个 1.2.0 的 Tag,那么现在将打出 1.2.1 的包来(无论此分支当前距离那个 Tag 有多少个提交,都只加 1)None如果此前在 Git 仓库此分支前有一个 1.2.0 的 Tag,那么现在将打出 1.2.0 的包来Inherit如果此分支上没有发现能够确认版本号的线索(例如一个 Tag),那么将自动寻找此分支的来源分支,继承来源分支的版本号递增规则。注意我在全局配置中加了一个source-branches配置,用于指定如果要自动寻找来源分支,请去这个集合中指定的分支名称里找。
下图是 release 分支上打包的版本号。

版本号递增的方式 mode
mode 可选的值有三种:
continuous-delivery持续交付,临近产品发布时使用,详细信息可阅读Continous delivery - GitVersioncontinuous-deployment持续部署,日常使用,详细信息可阅读Continuous deployment - GitVersionMainline传统的(官方文档没有说明,代码中没有注释,但阅读代码发现其策略是从上一个 Tag 递增版本号)
语义版本号使用教程
在了解了以上的配置之后,使用 GitVersionTask 才不会显得版本号的规则诡异。
我们从简单的使用开始,逐步向难演进。学习规则为:单个 master 分支 -> Git 分支流与预发布版本
单个 master 分支
如果我们只在 master 上开发,那么上手就非常容易了。
如果我们刚开始接触 GitVersionTask,那么我们在上一个发布包的提交上新建一个标签(Tag),命名为 v1.2.0,那么此标签之后的版本号打包将自动变为 1.2.1。Git 提交每次增多,那么构建号将加 1。下图中的版本号是 1.2.1+3。(注意:加号是语义版本号 2.0 的新特性,重申需要 NuGet 4.3.0 以及 Visual Studio 2017 15.3 以上版本。)

Git 分支流与预发布版本
当使用 Git 分支流时,版本号的递增方式其实与前面配置章节和单个 master 章节讲的时一致的。如下图。

但是,我们需要学习如何充分利用这样的分支流,以便让语义版本号充分发挥它的作用。
假设:我们最近发布了 1.1.0 正式版。
- 如果我们正在为库添加新功能,则新建一个
feature分支,一直开发,直到认为开发完毕(功能实现完成,单元测试全绿) - 如果此时有打包需求临时内测,则直接在
feature分支打包,这样能打出1.2.0-alpha的包(后面的 + 取决于相对于此前发布多了多少个提交) - 如果内测差不多了,则合并到
develop分支确认这个内侧包 - 如果准备发布这个功能了,那么从
develop分到release分支 - 这时如果有打包需求,则应该在打包之前新建一个标签(Tag)
v1.2-beta,这样能打出1.2的beta包(而不是1.1的) - 如果在此
beta的基础上出现持续打包,那么需要持续新建标签(因为自动新建的标签只会增加一次 Patch 号) - 如果确认可正式发布,则
release合并到master,新建v1.2标签
参考资料
- Versioning NuGet packages in a continuous delivery world: part 1 – Microsoft DevOps Blog
- Versioning NuGet packages in a continuous delivery world: part 2 – Microsoft DevOps Blog
- Versioning NuGet packages in a continuous delivery world: part 3 – Microsoft DevOps Blog
- C#/.NET - How to generate and increase package version automatically especially via CI? - Stack Overflow
- GitTools/GitVersion: Easy Semantic Versioning (http://semver.org) for projects using Git
- GitVersion
- Gitversion Task for VS2017-style csproj · Issue #1349 · GitTools/GitVersion
- Change Assembly Version - Jenkins - Jenkins Wiki
- Not working in .NET Core v2.0 project · Issue #15 · jeffkl/RoslynCodeTaskFactory
- NuGet Gallery - RoslynCodeTaskFactory 1.2.1
dotnet buildcommand always fails with GitVersionTask 4.0.0-beta · Issue #1399 · GitTools/GitVersion- .NET Core MSBuild cannot load tasks built against MSBuild 4.0 · Issue #2111 · Microsoft/msbuild
- Should the SDK include Microsoft.Build.Utilities.v4.0? · Issue #1870 · dotnet/sdk
使用 GitVersion 在编译或持续构建时自动使用语义版本号(Semantic Versioning)的更多相关文章
- 使用DaoCloud持续构建docker镜像,自动化部署
我们学会了在主机上安装部署docker,也学会了构建自己的docker镜像和容器,启停也都会用了,下一步就需要持续构建发布docker的技能了. 我们希望能在代码提交后,有个远程服务能自动开始构建项目 ...
- 正确理解java编译时,运行时以及构建时这三个概念
Java中的许多对象(一般都是具有父子类关系的父类对象)在运行时都会出现两种类型:编译时类型和运行时类型,例如:Person person = new Student();这行代码将会生成一个pers ...
- 获取hudson持续构建编译结果的一种方法
作者:朱金灿 来源:http://blog.csdn.net/clever101 很多时候使用hudson结合VisualStudio进行持续构建后需要获取持续构建的编译结果,通过编译结果来知道哪些项 ...
- 个人环境搭建——搭建jenkins持续构建集成环境
---恢复内容开始--- 搭建jenkins持续构建集成环境 要搭建jenkins持续构建集成环境,首先要安装tomcat和JDK: 第一部分,基本说明: 敏捷(Agile) 在软件工程领域 ...
- Jenkins持续构建打包后端服务流程详解
背景运用场景及思路 1.为响应后端开发人员需求,提升项目开发过程效率,选择Jenkins持续构建,进行导包启动一键持续集成 思路: 使用jenkins自带,立即构建->SVN拉取代码,通过Jen ...
- 【转】获取Jenkins构建时Git Change Log
原文:https://www.jianshu.com/p/513ab6915dbd 在基于Jenkins进行CI持续集成的工作,在构建后上传蒲公英时想将本次版本的git commit信息同步到蒲公英的 ...
- 使用MSBUILD 构建时出错 error MSB3086: Task could not find "sgen.exe" using the SdkToolsPath的解决方法
如果项目有添加有WB引用,比如引用其它网站的WEB服务等,那么VS在编译时会自动生成个 [项目名称].Serializers.dll的文件,就是把引用服务中的相关对象信息生成硬编码的程序集,以提高效率 ...
- [原]项目进阶 之 持续构建环境搭建(四)Jenkins环境搭建
在之前的几篇文章中,我给大家分别介绍了这次的持续化构建环境搭建的相关前提内容.如果说前面的文章都是小菜的话,那么今天的这篇文章就是我们这个系列文章的主菜. 1.前提 安装jenkins需要安装JDK. ...
- [原]项目进阶 之 持续构建环境搭建(三)Maven环境搭建
上次的博文项目进阶 之 持续构建环境搭建(二)Nexus私服器中,我们搭建了一个Nexus的maven私服,这次我们来重点讲解一下Maven的安装和配置.这里说明一下这次的环境搭建,比较基础,但却非常 ...
随机推荐
- Codeforces Round #341 (Div. 2) C. Mike and Chocolate Thieves 二分
C. Mike and Chocolate Thieves time limit per test 2 seconds memory limit per test 256 megabytes inpu ...
- 分布式系统中的幂等性-zookeeper与dubbo
现如今我们的系统大多拆分为分布式SOA,或者微服务,一套系统中包含了多个子系统服务,而一个子系统服务往往会去调用另一个服务,而服务调用服务无非就是使用RPC通信或者restful,既然是通信,那么就有 ...
- RedLock 实现分布式锁
J并发是程序开发中不可避免的问题,根据系统面向用户.功能场景的不同,并发的重视程度会有不同.从程序的角度来说,并发意味着相同的时间点执行了相同的代码,而有些情况是不被允许的,比如:转账.抢购占库存等, ...
- iOS 和Android客户端测试区别整理ing
区别很多,慢慢发现整理,注重细节,避免遗漏 消息推送区别: 1.推送渠道: 1.1 iOS走iOS自带的渠道进行系统内推送,应用内和应用外推送无明显差别,均可以收到push信息. 1.2 安卓由于谷歌 ...
- 【hive】多表插入
from or_table insert overwrite table1 name1 select … insert into table2 name2 select … 注意:select 后边不 ...
- USB events thread - failed to set priority
ubuntu + openni + nite,出现 Warning:USB events thread - failed to set priority xn::ImageGenerator imag ...
- 【zznu-夏季队内积分赛3-F】学无止境
题目描述 “别人总说我瓜,其实我一点也不瓜,大多数时候我都机智的一批“ACM程序设计竞赛是一个团体项目.宝儿姐作为其中优秀的一份子,每天好好学习天天向上.曾经宝儿姐给自己定了一个计划,刷穿bzoj.于 ...
- 【微软混合现实】开始使用Unity-第一章:创建一个新的项目
使用Unity开发App,第一步需要创建一个项目.项目具有一系列组织好文件夹,其中最重要的是你的附件文件夹(Assets folder).在这个文件夹中,存储了从其他工具中创建的数字内容,比如Maya ...
- RabbitMQ(6) 集群部署
单节点部署 rabbitmq单节点部署比较简单,可以使用apt-get等工具快速安装部署. wget -O- https://www.rabbitmq.com/rabbitmq-release-sig ...
- 转载-lvs官方文档-Linux服务器集群系统(二)
Linux服务器集群系统(二) LVS集群的体系结构 章文嵩 (wensong@linux-vs.org) 2002 年 4 月 本文主要介绍了LVS集群的体系结构.先给出LVS集群的通用体系结构,并 ...