Maven 和Jenkins下的持续release
我们都知道Maven 支持两种版本发布 snapshot 和release。 我们在开发的时候都是使用snapshot 版本, 如果有里程碑发布就走release 版本。 但是项目中如果用到持续集成的话,我们真的还有必要使用snapshot 吗? 项目中涉及到 DEV, SIT, UAT, PREPROD 和 PROD 这N个不同的环境。 我们的的想法是build 出来的war 包能够先有开发人员在DEV 环境下自我验证通过, 然后相同的文件提交给 QA 来在SIT 环境下做集成测试。如果在SIT环境通过进一步提交相同的文件到UAT 环境做用户接受测试。 这里想要强调的重点是我们需要保持相同的文件。
刚开始我们的做法是在不同的环境都是重新build 出war 包 再运行deploy job。 这样的风险在于重新build 的文件可能跟开始测试的环境下的war 是不一样的。 我们知道svn 下的revision 版本号在同一个仓库中是唯一的。 如果我们能将revision 作为 jar 或者 war 的文件的名一部分,就能保证版本的唯一。
在parent pom 文件中 定义
<version>1.2.0-SNAPSHOT</version>
<properties>
<usecase.version>1.2.0</usecase.version>
<revision>SNAPSHOT</revision>
</properties>
在各个module 的pom 文件中 我们
<version>${usecase.version}-${revision}</version>
<parent> <version>1.2.0-SNAPSHOT</version></parent>
这里其实利用的Maven的child module 可以使用parent pom 中的properties。虽然maven 会给出一个warning说
<version>${usecase.version}-${revision}</version> 最好使用static 量。 我们可以在maven build 的时候通过 -Drevision 来指定svn 的版本号。 这样build 出来的 jar 文件就会形如
myapp-1.2.0-13645.jar
13645 就是 svn的版本号。 我们在Jenkins 中可以利用它的内建系统变量SVN_REVISION来获取revision 比如 -Drevision=${SVN_REVISION}, 这样build 出来的 jar 或者 war 都是 带svn 版本号而不是SNAPSHOT。 当然如果我们不传入这个revision系统变量,build 出来的就是默认的SNAPSHOT。
在Jenkins 中, 我们就不需要deploy 到 nexus 中了, 我们现在的做法是所有build 出来的war 都是通过 scp 插件拷贝到另外一台有比较大空间的server 来备份所有build 出来的war。 这样在后来的发布的job 都需要通过image name 参数指定 war包的文件名。 deploy job 会在这个备份的目录中找到需要deploy的war 文件将它拷贝到相应的tomcat 目录下。
这样做的另外一个好处是 以前有N多的deploy job 现在就简化成一个。 我们只需要一个带3个参数的job:
image name 指定 war 文件名
app 这个可以通过选择来指定我们的六个应用之一。
env 来指定deploy 的环境之一 : DEV, SIT 或者 PREPROD。
要知道以前我们的deploy 需要悲催的 几十个job, 在Jenkins 的job 列表中需要密密麻麻的 一坨。
另外需要说明的是采用了 <version>${usecase.version}-${revision}</version> 的pom 如果有间接依赖。间接依赖的包还是被用的是SNAPSHOT 版本, 我们需要消除这种间接依赖。
比如在我们的 inbound 的pom 中 我们依赖 inbound , inbound 会依赖 usecase-common jar。 这个时候我们发现 最终打出的war 里面包含的 usecase-common 不是 usecase-common-1.2.0-13645.jar , 而是 usecase-common-1.2.0- 加上一长串 timestamp 串, 明显是maven的snapshot过来的。 我们可以通过在inbound war的pom 文件中显示的 依赖 usecase-common 就可以解决这个问题。