经过自动化持续集成工作之后,一般会产生两类重要成果:
1、提供给用户使用的软件产品
2、软件设计、开发时产生的文档
毋庸置疑,软件产品本来就是我们工作的目标物。在实际工作中,尤其是在给企业做定制化的MIS系统时,很难说只给用户一次性提供产品,往往需要不断升级,从而向客户提供多个版本的产品(其实商业软件、开源软件、网站等也是如此)。在配置管理中,版本号是管理软件产品发布、部署(上两篇笔记已经探讨了如何实现自动化部署的问题)、回溯等工作的关键线索。其实,在SCM中,版本号是一个极重要但又比较复杂的问题,幸好实际工作中我们不用涉及太深。
基于此,本文主要针对如何自动化地生成产品版本号进行了探讨。只要版本号的自动生成原理搞清楚了,其它象分支的生成、主干线与分支的合并、版本回溯等问题则就是简单地输入命令的事情了。
一、两类版本号的区别与联系
在持续集成中,实际上会涉及到两类版本号:
l 版本控制库里,由于源代码不断提交所产生的版本号。在SVN中,文档(源代码等)版本号是按自然数增长,从1开始,到10、122、329……等
l 软件Release时设定的版本号。我们常见的形式是1.0版、2.3.7版……等等。在本文中,由Maven生成Release版本号---实际就是将项目POM.xml中artifactId对应的快照方式(x.x.x- SNAPSHOT)的版本号转化成release方式(x.x.x)的版本号
虽然版本号形式不同,但其背后都是同一套源代码。所以,决定我们生成、管理版本号的关键因素就是:建立release版本号与SVN仓库文档版本号之间的对应关系。
解决这个问题的思路其实也比较明确,就是在SVN\trunk中某个版本号的源代码执行构建任务成功后,利用maven的插件,将这个版本号的源代码copy到SVN\Tags中的以release 版本号命名的子目录下。见下面的对应关系示意表。
工作日期 | SVN\trunk源代码版本号(每天可能有N次提交,也就有N个版本号) |
| release 版本号(假设每天进行一次构建、发布) |
| (发布时在SVN中打个tag)SVN\Tags中的源代码版本号 |
Day1 | 1 |
| 构建成功 |
| 存放目录为SVN\tags\ release-1.1,对应的trunk下源代码版本号为32 |
……. |
|
| |||
32 |
| 1.1版 |
| ||
Day2 | 33 |
| 构建成功 |
| 存放目录为SVN\tags\ release-1.2,对应的trunk下源代码版本号为54 |
…… |
|
| |||
54 |
| 1.2版 |
| ||
Day3 | 55 |
| 构建不成功,无release版本发布 |
| 无内容 |
…… |
|
| |||
82 |
|
| |||
Day4 | 83 |
| 构建成功 |
| 存放目录为SVN\tags\ release-1.3,对应的trunk下源代码版本号为106 |
…… |
|
| |||
106 |
| 1.3版 |
|
maven通过maven-release-plugin插件可以和SVN进行协作,以命令行形式进行Release版本号的生成。相关参考资料见http://juvenshun.iteye.com/blog/376422,这是笔者目前见到的写得较有水准的一篇讲解材料。当然,如果E文很好的话,也可以参考官方文档:http://maven.apache.org/plugins/maven-release-plugin/
但上述材料讲的是如何通过命令行实现,期间还要经过人机交互操作才能生成Release版本号。对于笔者来说,是想把版本号的生成纳入到日常性的持续集成工作中(比如每日生成一个发布版),这显然就需要版本号的自动化生成,于是,就该Jenkins登场了。
二、版本号的自动生成
版本号的自动生成主要依靠一个maven插件,就是上面提到的maven-release-plugin。
相应的操作步骤如下:
1、在pom.xml中设置maven-release-plugin
2、建立一个Jenkins job,并进行设置
3、执行构建任务
(一)、设置maven-release-plugin
以学习笔记(5)中提到的DEMO为例,在pom.xml中设置两部分内容:SCM设置和插件configuration设置。这些设置和命令行执行方式下没有区别。注意,目前版本号为0.1.1-SNAPSHOT。具体设置内容和说明如下:
<groupId>DEMO</groupId>
<artifactId>DEMO</artifactId>
<!--貌似SNAPSHOT必须要大写字母-->
<version>0.1.1-SNAPSHOT</version>
<packaging>jar</packaging>
<!--必须明确设置SCM,否则maven-release-plugin找不到SVN源代码仓库-->
<scm>
<connection>scm:svn:file:///C:/DEMO/trunk</connection>
<developerConnection>scm:svn:file:///C:/DEMO/trunk</developerConnection>
</scm>
……
<build>
……
<plugins>
……
<!-- 设置maven-release-plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<!--tags目录位置。如果是https:,则格式为https://192.168.1.100:8443/svn/myapp/tags/-->
<tagBase> file:///C:/DEMO/tags</tagBase>
</configuration>
</plugin>
……
</plugins>
……
</build>
可以看到,设置本身不算复杂。但要想顺利地执行,一定要保证几个关键前提条件。其实,笔者多次试验均未成功,最后发现原因就是违反了以下的某个前提条件:
1、确保所有代码都提交到SVN仓库,本地没有未提交代码。如果本地有更新过的文件,但没有提交到SVN仓库,执行release插件就会报错。
这个前提很重要。建议:设立一个空的文件夹作为CI工作空间,里面只放入pom.xml;而这个pom.xml也需要提交至SVN\trunk目录下,以保证pom.xml也在SVN管辖范围内。再进行release的构建时,就会严格的符合CI工作空间没有’未提交代码’的条件了。这种情况下,也不影响其它POM.xml中设置好的插件、依赖的执行。
2、POM.xml中所设置的dependency必须是发布版本, 不能使用SNAPSHOT版本
3、保证命令行形式下的SVN命令得以执行。实际上就是要事先安装好支持命令行形式的SVN服务器。如果只安装了tortoiseSVN,那就惨了。
4、Maven Release在运行过程中,会修改POM.xml中scm的connection设置。如果release异常中止的话, 需要恢复原来的pom文件,才能再次运行. 因此在试验阶段, 最好准备一个POM.xml的备份
5、如果想执行release:perform命令,即要让Maven自动发布生成后的jar,就先要设置好maven的远程分发仓库。
(二)、设置Jenkins job
在Jenkins中新建一个job。在“配置”中,设置好自定义空间、源码管理相应选项,并在“构建”的Goals下放入release:clean 和release:prepare两条命令,然后执行立即构建。这样,在命令行下需要人机互动的环节就能以默认选择方式自动进行了。
我们可以对比一下变化:
Ø 构建前
Ÿ POM的artifactId版本号为0.1.1-SNAPSHOT
Ø 构建后
Ÿ 本地以及SVN\trunk目录下的pom.xml中,artifactId版本号变为0.1.2-SNAPSHOT
Ÿ SVN\tags目录下生成一个DEMO-0.1.1的目录,其中包含了源代码以及pom.xml
二、分支的版本号管理
要想进行分支的版本号管理,首先要生成一个分支。因为这里我们主要关注release版本,所以使用mvn命令(如何用SVN命令进行分支管理,请见《学习笔记(4)》中推荐的教程)。比如说从主干线版本1.1.0分出支线,可以通过下面的命令行执行:
mvn release:branch -DbranchName=1.1.1 -DupdateBranchVersions=true -DupdateWorkingCopyVersions=false
此时,在SVN\branches下,会生成一个1.1.1-SNAPSHOT 的目录,而SVN\branches下的pom.xml中,artifactId版本号会自动变为1.1.1-SNAPSHOT。
然后,要想实现分支的release版本号自动生成,方法其实与主干线的一样,区别仅仅在于:源代码来源目录不一样。
何时进行分支操作,何时进行分支、主干线的合并,是需要人工干涉的,这种事不应该实现自动化:因为机器无法判断应该在什么条件下去做这些事情。