一.何为版本管理
版本管理( Version Management )是指项目整体版本的演变过程管理,如从 1.0.0-SNAPSHOT 到 1.0.0 。版本控制( Version Control )是指借助版本控制工具(subversion)追踪代码的每一个变更。
理想的发布版本应该对应项目某个时刻比较稳定的状态,应满足以下条件:
1)所有自动化测试应通过
2)项目没有快照版本的依赖
3)项目没有配置快照版本的插件
4)项目包含的代码已全部提交到版本控制系统中。
在 svn中使用标签可以明确地将某个源码版本(也就是项目的某个状态)从主干中标记出来,这样在之后的任何时刻,我们都能够快速地得到发布版本的源代码,从而能够比较各个版本的差异,甚至重新构建一个同样版本的构件。
从快照版本更新至发布版本之后,应该再执行一次 Maven 构建,确保项目状态是健康的,再将更新提交到 svn 的主干中。接着再为当前主干的状态打上标签。
二.Maven的版本号定义约定
Maven 的版本号定义为:
< 主版本 >.< 次版本 >.< 增量版本 >-< 里程碑版本 >
1)主版本:项目重大架构变更
2)次版本:较大范围功能变化及 Bug 修复
3)增量版本:重大 Bug 修复
4)里程碑版本:一个版本的 milestone ,表示不是非常稳定,还需要很多测试
一般主版本和次版本都会声明,增量版本和里程碑版本不一定会声明。
Maven 对前三者的比较是基于数字的,对里程碑版本只进行简单的字符串比较,因此会得到如1.2-beta-3 >1.2=beta11的结果。
三.主干、标签与分支
使用版本控制工具都会遇到以下概念:
1) 主干( trunk ):项目开发代码的主体,从项目开始直到当前都处于活动状态,可以获得项目最新源码及所有变更历史。
2) 分支( branch ):从主干的某个点分离出来的代码拷贝,通常是为了在不影响主干的前提下进行重大 Bug 的修复或做些实验性质的开发,当分支达到预期的目的后,分支上的变更会被合并到主干上。如下图中为了不影响1.2.0 的开发,从 1.1.0 分了一个分支出来进行 Bug 修复。
3) 标签( tag ):用来标识主干或者分支的某个点的状态,以某个稳定状态(通常是版本发布时的状态)
四.自动化版本发布
1.Maven Release Plugin概述
Maven Release Plugin 能完成所有版本发布所涉及的操作,它主要有三个目标:
1) release:prepare :准备版本发布,主要执行以下操作:
a) 检查项目是否有未提交代码
b) 检查项目是否有快照版本依赖
c) 根据用户输入将快照版升级为发布版
d) 将 POM 中的 SCM 信息更新为标签地址
e) 基于修改后的 POM 执行 Maven 构建
f) 提交 POM 变更
g) 基于用户输入为代码打标签
h) 将代码从发布版升级为新的快照版
i) 提交 POM 变更
2) release:rollback :回退 release:prepare 所执行的所有操作,提交回退后的 POM ,但不会删除标签
3) release:perform :执行版本发布。签出 release:prepare 生成的标签中的源代码(注意:这里是按标签地址签出原代码, POM 中的版本还是发布版本 ) ,并在此基础上执行 mvn deploy 。
2.为项目发布版本
要为项目发布版本,首先需要为其添加正确的版本控制系统信息,Maven Release Plugin需要知道版本控制系统的主干、标签等地址信息后才能执行相关操作。
1) 配置项目的SCM信息,告诉maven当前代码的位置(主干)。
<scm> <connection>scm:svn:http://192.168.1.103/app/trunk</connection> <developerConnection>scm:svn:https://192.168.1.103/app/trunk</developerConnection> <url>http://192.168.1.103/account/trunk</url > </scm>
Connection元素表示一个只读的scm地址。
developerConnection元素表示可写的scm地址。
url元素表示可以在浏览器中访问的scm地址。
Connection和developerConnection为了能让maven识别,必须以scm打头,
冒号之后代表版本控制工具类型(其他还有cvs、git等),接下来就是scm实际地址。
2) 配置Maven Release Plugin,告诉其标签的基础目录。
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-release-plugin</artifactId> <version>2.0</version> <configuration> <tagBase>https://192.168.1.103/app/tags/</tagBase> </configuration> </plugin>
3) 执行 mvn release:prepare 命令
执行该命令前,需注意:
第一,系统必须要提供svn命令行工具;
第二,POM必须配置了可用的部署仓库。
在项目根目录执行命令:mvn release:prepare,如果项目有未提交的代码或者有快照版本依赖,则会提示出错。
如果一切正确,则会提示用户输入发布版本号、标签名以及新的快照版本号。
4) 执行mvn release:rollback回退发布
执行该回退命令后,Maven Release Plugin会将POM中的配置回退到release:prepare之前的状态。但是,版本控制系统中的标签并不会被删除,用户需要手动删除该标签。
5) 将所有模块的发布版本和新的快照版本都保持一致
在多模板项目中执行mvn release:prepare时,默认会提示用户设定每个模块发布的版本号及新的开发版本号。但是很多情况下我们希望所有模块的发布版本以及新的SNAPSHOT开发版本都保持一致。
运行以下命令,插件自动为所有子模块使用与父模块一致的发布版本和新的SNAPSHOT开发版本:
mvn release:prepare -DautoVersionSubmodules=true
如果坚持release:prepare的结果没问题,则执行如下发布命令:
mvn release:perform
该命令将标签中的代码签出,执行mvn deploy命令构建刚才准备的版本,并部署到仓库。
至此,版本正式发布完成。
6) 在超级POM中配置信息,使打包类型为jar的主构件的-sources.jar和-javadoc.jar也会生成并发布。
<profiles> <profile> <id>release-profile</id> <activation> <property> <name>performRelease</name> <value>true</value> </property> </activation> <build> <plugins> <plugin> <inherited>true</inherite> <artifactId>maven-source-plugin</artifactId> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <inherited>true</inherited> <artifactId>maven-javadoc-plugin</artifactId> <executions> <execution> <id>attach-javadocs</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <inherited>true</inherited> <artifactId>maven-deploy-plugin</artifactId> <configuration> <updateReleaseInfo>true</updateReleaseInfo> </configuration> </plugin> </plugins> </build> </profile> </profiles>
这个 profiler 配置了三个插件,分别用来为项目生成 -source.jar ,为项目生成 -javadoc.jar 以及更新仓库中的元数据,告诉仓库该版本是最新的发布版。每个插件中值为 true 的 interited 元素表示该插件配置可以被子 POM 继承。而这个 profile 的激活条件是运行环境中有名为 performRelease 属性且值为 true 。而 release:perform 会自动生成-DperformRelease=true 参数。由于这种隐式的配置十分令人费解,会在后面版本的 Maven 中去除,让用户自己在 POM 中显示配置这些插件。
一.自动化创建分支
Maven Release Plugin 的 branch 目标会执行以下操作:
1) 检查本地有无未提交代码
2) 为分支更改 POM 的版本
3) 将 POM 中的 SCM 信息更新为分支地址
4) 提交以上更改
5) 将主干的代码复制到分支中
6) 修改本地代码使其回退到分支之前的版本(用户可以指定新的版本)
7) 提交本地更改
为此我们还需要在 POM 中配置为 Maven Release Plugin 用 <branchBase> 元素配置分支地址。
执行 release:branch –DbranchName=1.1.1 –DupdateBranchVersions=true –DupdateWorkingCopyVersions=false 会提示用户输入新的 branch version 。
最后一个参数表示不更新本地代码(即主干)版本。
二.GPG签名
1.GPG及其基本使用
GnuPG(简称 GPG ,来自http://www.gnupg.org )是 PGP ( Pretty Good Privacy )标准的一个免费实现,无论类 UNIX 平台还是 Windows 平台都可使用它。 GPG 能帮助我们为文件生成签名、管理密钥以及验证签名等。
使用 gpg –gen-key 生成 GPG 密钥对。使用 gpg –list-keys 可以查看本机的所有公钥。使用 gpg –list-secret-keys可以查看本机的所有私钥。
使用 gpg –ab temp.java 可以为文件创建一个 ASCII 码的签名文件: temp.java.asc 。 -a 表示生成 ASCII 格式的输出, -b 表示创建一个独立的签名文件。将这两个文件及公钥一起给用户,用户可以用 gpg –verify temp.java.asc 来验证该文件。
运行如下命令可以将公钥发布到公钥服务器中:
gpg –keyserver hkp://pgp.mit.edu –send-keys C6EED57A
这里 C6EED57A 就是用 —list-keys 看到的公钥 ID 。公钥会自动在各个服务器中被同步。
可以用如下命令获得公钥:
gpg –keyserver hkp://pgp.mit.edu –recv-keys C6EED57A
2.Maven GPG plugin
可以在 POM 中配置 Maven GPG Plugin (但命令行 gpg 需要自己安装):<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-gpg-plugin</artifactId> <version>1.0</version> <executions> <execution> <id>sign-artifacts</id> <phase>verify</phase> <goals> <goal>sign</goal> <goals> </execution> </executions> </plugin>
用命令行 mvn clean deploy –Dgpg.passphrase=yourpassphrasesk 可以对你发布的构件进行自动签名。Yourpassphrase 是你的私钥的密码(你在创建私钥的时候可以选择是否设一个密码。)
用如下命令可以对已经发布的构件进行签名:
mvn gpg:sign-add-deploy-file –DpomFile=target/myapp-1.0.pom –Dfile=target/myapp-1.0.jar –Durl=http://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype_oss
该命令指定了要签名的 POM 及相关文件、 Maven 仓库的地址和 ID 。
只有在项目正式发布的时候才需要签名,对日常的 SNAPSHOT 构件签名只会增加耗时。所以可以在 settings.xml文件中新增一个 profile 来配置 GPG 插件,而 profile 的激活条件同样中 performRelease 为 true 。这样就能在执行release:perform 时自动执行 GPG 插件了。但由于一个已知的 Maven Release Plugin 的 Bug ,执行 release:perform过程中签名可能会 hung 住,所以需要为其在 confiuration 元素中增加:
< mavenExecutorId >forked-path </ mavenExecutorId >