相信大家看完了上篇文章(http://gull.iteye.com/blog/1137200),会对自动化编译,部署和测试的过程与实现细节有所了解。那么我们稍微总结下就会发现其实现的实质就是一系列linux shell命令组成,且都是很常见的,如maven, ssh, scp, unzip, cp, mv, delete, kill, sed, awk等.
我们回想下——项目是采用maven2构建的,而我们CI自动化job的阶段也是借鉴maven2中默认的phases,因此我们做了下映射, 如下图:

此时你会有什么样的想法? —— 我们能否扩展maven2的生命周期,将我们不同流程的脚本嵌入到maven2的各个生命周期中,这样就可以直接使用原生的maven2命令来完成CI自动化流程了。![]()
所幸的是maven2已经提供了这样的机制和插件,在实践中我们主要用到了下面这2个插件:
- maven-antrun-plugin: 自定义ant task来完成代码同步(p4 sync),参数替换,打包上传(scp),集成测试(ant-jmeter)等操作
- maven-sshexec-plugin:主要是用来执行远程服务器命令来完成清理和部署(ssh, del, unzip, scp, kill, java)等操作
这2个插件如何操作可以查看相关手册:
http://maven.apache.org/plugins/maven-antrun-plugin/
http://evgeny-goldin.com/wiki/Maven-sshexec-plugin
maven-antrun-plugin这个插件官方介绍得比较简单,远不能达到我们的需要,因此我们需要扩展ant task来完成CI流程的定制化。
如何扩展?我们将以code sync和test为例来介绍。
code sync&test stage
- 实现org.apache.tools.ant.Task接口
public class CodeSync extends Task {
//todo
public void execute() throws BuildException {
//todo prepare some parameters
try {
//sync the application code
sync(depot, p4ClientRoot, p4ClientFolder);
} catch (Exception e) {
e.printStackTrace();
throw new BuildException(e);
}
}
private void sync(String depotRoot, String clientRoot, String folderPath) throws Exception {
String depotPath = depotRoot + "/" + folderPath + "/...";
IServer server = ServerFactory.getServer("p4java://p4host:p4port", null);
server.connect();
server.setCharsetName(p4Charset);
server.setUserName(p4User);
//login the p4 server
server.login(p4Passwd);
IClient client = server.getClient(p4Client);
server.setCurrentClient(client);
List<IFileSpec> fileSpecs = server.getDepotFiles(FileSpecBuilder.makeFileSpecList(new String[] { depotPath }), false);
log("sync "+fileSpecs.size()+" flies");
client.sync(fileSpecs, true, false, false, false);
server.logout();
}
}
- 创建taskdef.properties文件
codesync=com.xxx.ant.tasks.CodeSync
- 配置pom插件
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <version>1.6</version> <executions> <execution> <id>initialize</id> <phase>initialize</phase> <configuration> <target> <echo message="**************************"/> <echo message="** A P P S CODE SYNC "/> <echo message="**************************"/> <typedef file="$typedef.properties" /> <codesync> <parameter name="maven">xxx.xxx.xxx</parameter> <parameter name="xxxx">yyyy</parameter> </codesync> <echo message="**************************"/> <echo message="** END CODE SYNC *********"/> <echo message="**************************"/> <echo message=""/> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> <execution> <id>compile-skip-unittest</id> <phase>test</phase> <configuration> <target if="maven.test.skip"> <echo message="*****************************************"/> <echo message="===== BEGIN COMPILE(TEST) ===="/> <echo message="*****************************************"/> <exec dir="/xxx/yyy/sourceFolder" executable="mvn"> <arg line="clean compile -Dmaven.test.skip=true -Ddependency.locations.enabled=false"/> </exec> <echo message= "***************************************"/> <echo message= "===== END COMPILE(TEST) ===="/> <echo message= "***************************************"/> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> <execution> <id>compile-unit-test</id> <phase>test</phase> <configuration> <target unless="maven.test.skip"> <echo message="***********************************"/> <echo message="===== BEGIN COMPILE ===="/> <echo message="***********************************"/> <echo message="//TODO: prepare unittest environment "/> <exec dir="/xxx/yyy/sourceFolder" executable="mvn"> <arg line="clean compile -Ddependency.locations.enabled=false"/> </exec> <echo message="***********************************"/> <echo message="===== BEGIN COMPILE ===="/> <echo message="***********************************"/> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>com.xxxx</groupId> <artifactId>ci-anttasks</artifactId> <version>1.0.0</version> </dependency> </dependencies> </plugin> </plugins> </build>
在这个配置文件中,我们扩展了maven2的initialize和test周期,并通过ant来执行我们想要的操作。
Deploy Stage
对于deploy过程也是比较杂的,也需要按照相同的方式来扩展,并且还要配合maven-sshexec-plugin插件来完成部署操作。
pom.xml配置片段
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>upload package</id>
<phase>pre-integration-test</phase>
<configuration>
<target>
<mkdir dir="..."/>
<!-- upload package to the remote server-->
<scp todir="deployserver:path"
keyfile="$keyfile" trust="true"
failonerror="false">
<fileset dir="$buildFolder/">
<include name="*.zip"/>
</fileset>
</scp>
...
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.xxxx</groupId>
<artifactId>ci-anttasks</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>com.goldin.plugins</groupId>
<artifactId>maven-sshexec-plugin</artifactId>
<executions>
<!-- Run commands on each remote server -->
<execution>
<id>do deploy</id>
<phase>pre-integration-test</phase>
<goals>
<goal>sshexec</goal>
</goals>
<configuration>
<location>scp://$deployserver/uploadFolder</location>
<keyfile>$keyFile</keyfile>
<commands>
<command>echo '********************************'</command>
<command>echo '==== { Run Remote Commands} ===='</command>
<command>echo '********************************'</command>
<command>
unzip xx.zip
</command>
<command>echo ''</command>
<command>echo '==== END Run Remote Commands ===='</command>
<command>echo '*********************************'</command>
<command>echo ''</command>
</commands>
</configuration>
</execution>
</executions>
</plugin>
Integration Test Stage
目前integration test我们主要是采用jmeter来进行完成API测试的,因此我们需要配置ant jmeter task.
<execution>
<phase>integration-test</phase>
<configuration>
<target>
<echo message="******************************************"/>
<echo message="==== { Run Integration test Scripts } ===="/>
<echo message="******************************************"/>
<path id="jmeter.classpath">
<fileset dir="$jarFolder">
<include name="ant-jmeter*.jar"/>
</fileset>
</path>
<taskdef name="jmeter" classpathref="jmeter.classpath" classname="org.programmerplanet.ant.taskdefs.jmeter.JMeterTask"/>
<property name="transformation.xsl" value="$resourcesFolder/jmeter-results-detail-report.xsl" />
<property name="resourcesFolder" value="$resourcesFolder" />
<ant antfile="$jmeter.integration.testscript" />
<echo message=""/>
<echo message="=====END Integration Test====="/>
<echo message="******************************"/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
到此maven2生命周期的扩展算是结束了,但如果子项目比较多的话,每一个这样配置很是麻烦,可以通过下面2种手段解决:
- 构建maven parent project: 通过继承和参数覆盖的方式简化配置,具体方式可参考maven手册。
- 编写pom生成工具: 通过简单的配置参数和文件模板生成目标pom,如图所示

——全文完
本文介绍了如何通过扩展Maven2的生命周期,利用anttask和sshexec插件实现CI自动化流程,包括代码同步、打包上传、集成测试和部署等步骤。详细展示了配置文件的扩展方法和实例。
597

被折叠的 条评论
为什么被折叠?



