[原创]Maven 打包时自动生成包含 SVN 时间戳 的版本号

目标

使用mvn install时修改/config/env.properties中的buildCode 格式是
buildCode=Build1038 rev3083 @2021/12/27 16:42:15
build是自增版本号,rev是svn版本

所以一共有以下几个步骤
1、生成新的buildCode----获取SVN版本号和打包时间,想办法生成一个每次打包自增的版本号
2、打包时修改env.properties,把新的buildCode写入其中

生成新的buildCode

此处使用的是插件buildnumber-maven-plugin,它可以获取SVN版本号,构造时间戳和自增版本号。

获取SVN版本号

按照Maven和buildnumber-maven-plugin的官方文档构造的POM并不能获取到SVN版本号,以下说说自己的步骤和POM。
  • 检查SVN环境,在项目根目录下cmd运行svn info,查看是否有正确输出,若没有,检查SVN环境变量是否配置,若已有环境变量,应该是没安装svn的命令行客户端,重新安装一遍即可。
  • 我的项目是一个parent下面有很多子工程,一开始buildnumber-maven-plugin完全没生效,原因是只在parent的POM中配置了插件,还需要再Child中也声明一遍,这样才会在打包时调用插件
<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
  • 官方文档中没有配置scm的相关配置,在parent的POM中添加了scm。如果只是想要获取SVN版本号,这里就已经完成了,后续和文档一样,通过${buildNumber}调用即可。
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<scm>
		<connection>scm:svn:https://xxxxxx:8888/java</connection>
	</scm>
	<build>
		<plugins>
	      <plugin>
	        <groupId>org.codehaus.mojo</groupId>
	        <artifactId>buildnumber-maven-plugin</artifactId>
	        <version>1.4</version>
	        <executions>
	          <execution>
	            <phase>validate</phase>
	            <goals>
	              <goal>create</goal>
	            </goals>
	          </execution>
	        </executions>
	        <configuration>
	          <doCheck>false</doCheck>
	          <doUpdate>false</doUpdate>
	        </configuration>
	      </plugin>
	    </plugins>
	</build>
</project>

获取日期

这里可以直接参考官方的POM样例,后续通过${buildTime}调用

<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>buildnumber-maven-plugin</artifactId>
	<version>1.4</version>
	<executions>
		<execution>
			<id>create-timestamp</id>
			<phase>process-resources</phase>
			<goals>
				<goal>create-timestamp</goal>
			</goals>
			<configuration>
				<timestampFormat>yyyy/MM/dd HH:mm:ss</timestampFormat>
				<timestampPropertyName>buildTime</timestampPropertyName>
			</configuration>
		</execution>
	</executions>

</plugin>

获取自增版本号

官方文档其实有提及这个部分,只是说得很简单

When you specify the special items of “buildNumber\d*” or “timestamp”, then some magic is performed. For each unique buildNumber, a properties file ( see buildNumberPropertiesFileLocation ) will be created (or read if it exists) which holds an integer, starting at 1. That number will be incremented on each access. Of course, the given example is somewhat non-sensical, since it will increment all 3 numbers on each build, but it shows the type of flexibility available. For each timestamp, you simply get the current date and time.

简单来说就是在<goal>create</goal>中创建buildNumber时,若配置了<format>,且<item>中有buildNumber这样的的项,会自动生成一个properties文件,以此维护一个自增的build号。这里直接放上我的POM来举例。

解释一下{0,number,#}是什么意思,调用<items>中的第一个item,视作number且去除千位后面的","。具体可以参考MessageFormat class的文档。

<items>中的buildNumber0插件会自己去<buildNumberPropertiesFileLocation>下面创建/读取properties文件,用于维护自增版本号。

<buildNumberPropertyName>是配置输出的buildNumber属性名,因为我同时需要SVN版本号和一个自增版本号,所以有两个<execution>,第一个<execution>获取SVN版本号,并存到${svnNo}中。

参考文档可以看出在使用<format>时可以直接生成时间戳,所以去掉了上面生成时间戳的<execution>

<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>buildnumber-maven-plugin</artifactId>
	<version>1.4</version>
	<executions>
		<execution>
			<phase>process-resources</phase>
			<goals>
				<goal>create</goal>
			</goals>
			<configuration>
				<doCheck>false</doCheck>
				<doUpdate>false</doUpdate>
				<useLastCommittedRevision>true</useLastCommittedRevision>
				<buildNumberPropertyName>svnNo</buildNumberPropertyName>
			</configuration>
		</execution>
		<execution>
			<id>buildnumberFromPropertiesFile</id>
			<phase>process-resources</phase>
			<goals>
				<goal>create</goal>
			</goals>
			<configuration>
				<format>Build{0,number,#} rev${svnNo} @{1,date,yyyy/MM/dd HH:mm:ss}</format>
				<items>
					<item>buildNumber0</item>
					<item>timestamp</item>
				</items>
				<doCheck>false</doCheck>
				<doUpdate>false</doUpdate>
				<buildNumberPropertiesFileLocation>${project.basedir}/conf/build.properties</buildNumberPropertiesFileLocation>
			</configuration>
		</execution>
	</executions>
</plugin>

更新properties文件

要直接读取并修改properties很困难,起码我还没找到一个简单的办法,现在的实现是使用maven-resources-pluginfiltering功能实现的。

首先是通过<resource>标签将properties引入,注意配置<filtering>

然后设置newBuildSVNVersion属性

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<resources>
		<resource>
			<directory>${project.basedir}/conf</directory>
			<filtering>true</filtering>
		</resource>
	</resources>
	<properties>
		<newBuildSVNVersion>${buildNumber}</newBuildSVNVersion>
	</properties>
	<build>
	...
	</build>
</project>

最后在原始的properties文件中存入一个占位符,例如

buildCode=${newBuildSVNVersion}

这样Maven在<phase>process-resources</phase>中复制资源的时候会用<newBuildSVNVersion>属性去替换占位符。

好的,之前每一步都没有问题,但是为什么最后输出的properties文件内容是buildCode=${buildNumber}

原因是Maven处理资源是调用的插件maven-resources-plugin的<goal>resources</goal>,该阶段bind到了<phase>process-resources</phase>,且是在再上一层的parent中,导致处理资源的时候我们创建BuildNumber的插件还没被调用,即便是把BuildNumber插件也配置到<phase>process-resources</phase>。
解决方法是在当前POM中再配置一次maven-resources-plugin的<goal>resources</goal>,并放到BuildNumber插件的phase之后。

通过配置<id>default-resources</id>,该execution会覆盖parent中的execution,这样当拷贝资源的时候BuildNumber已经生成,自然就可以获取到正确的版本号了

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-resources-plugin</artifactId>
	<executions>
		<execution>
			<id>default-resources</id>
			<phase>compile</phase>
			<goals>
				<goal>resources</goal>
			</goals>
			<configuration>
				<outputDirectory>${project.build.outputDirectory}/resource</outputDirectory>
			</configuration>
		</execution>
	</executions>
</plugin>

猜你喜欢

转载自blog.csdn.net/jiangyv1718/article/details/122367588