Continuous Integration实践之Implementation(续)

相信大家看完了上篇文章(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"
						 failοnerrοr="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种手段解决:

 

  1. 构建maven parent project: 通过继承和参数覆盖的方式简化配置,具体方式可参考maven手册。
  2. 编写pom生成工具: 通过简单的配置参数和文件模板生成目标pom,如图所示

 

 

 

——全文完

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值