CruiseControl服务器安装配置
来源:互联网 发布:移动公司大数据岗位 编辑:程序博客网 时间:2024/06/05 06:45
1. 认识CruiseControl
CruiseControl是CI服务器的老者,诞生已是多年,在许多方面,CruiseControl服务器已经成为持续集成实践的同义词。而现在,CruiseControl已发展成为一个家族式系统,包括CruiseControl.java、CruiseControl.net、CruiseControl.ruby等适应不同语言环境的实现,其强大的插件和扩展能力也是诸多同类系统无法比你的。而在这里,我只介绍该家族的本家CruiseControl.java,即CruiseControl。
下图是CruiseControl系统的架构图:
CruiseControl系统架构图
图中我们可以看到,CruiseControl系统的主体是Build Loop机制,它采用了Source Code轮询机制,对持续集成环境的状态进行定时检测,并根据config.xml配置信息做出相应处理。CruiseControl服务器则使用HTTP和RMI机制将持续集成服务公开到Reporting模块,同时使用XML数据格式对每次集成的数据进行归档。同时CruiseControl还可以集成了RSS、IM、E-MAIL等信息发布机制,最大程度将信息广播到团队的每个成员。
CruiseControl系统集成循环的流程图见下图,图中显示了CruiseControl使用轮询机制对版本库进行检测,并对发生变更的代码进行预定操作的流程:
CruiseControl系统运行流程图
2. CruiseControl的安装
CruiseControl的安装有许多方式。例如,如果使用Windows,会发现最简单的方式是下载二进制可执行文件,当然下载最新版本,然后运行它。要是高兴想研究,还可以下载源代码。
安装之后,CruiseControl预先配置了一个配置文件,轮询SVN(或其它版本控制系统)存储库并执行ANT构建脚本。服务环境不需要安装Web服务器,CruiseControl已经内嵌了Jetty web服务程序。
3. CruiseControl的配置
当CruiseControl服务器启动时,会自动检测配置信息中的任务信息,并对其进行校验和初始化,之后所有的工作,都是依据该配置信息进行的。
CruiseControl的配置使用了其安装目录下的config.xml文件,我们可以通过任一文本编辑器打开该配置文件,编辑各种配置信息。配置信息的定义遵循了标准XML文件格式,同时遵循了ANT自动构建配置信息的规则,因此建立一个普通工程的配置信息并非难事。
config.xml的节点配置说明如下:
<?xml version='1.0' encoding='gb2312'?>
2<cruisecontrol>
3 <project name="projectName">
4
5 <!-- 用于处理一些项目有关的事件 -->
6 <listeners>
7 <!-- 用来访问项目当前创建的状态 file: 指定了状态文件的位置 -->
8 <currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
9 </listeners>
10
11 <!-- 在 CC 进行创建之前运行,是创建前的准备工作 -->
12 <bootstrappers>
13 <!-- 从源码控制系统更新本地文件: cvsbootstrappers、vssbootstrappers、svnbootstrapper -->
14 <svnbootstrapper localWorkingCopy="projects/${project.name}" />
15 </bootstrappers>
16
17 <!-- 检查各个源码控制系统中是否发生变化;quietperiod: 单位为秒 设定等待的时间 -->
18 <!-- 第一次的取出工作为手动执行 -->
19 <modificationset quietperiod="300">
20 <svn localWorkingCopy="projects/${project.name}"/>
21 </modificationset>
22
23 <!-- 指定了构建的时间间隔 单位为秒-->
24 <schedule interval="60">
25 <ant anthome="apache-ant-1.7.0" buildfile="projects/${project.name}/build.xml"/>
26 </schedule>
27
28 <!-- 指定项目日志保存的地点 -->
29 <log>
30 <!-- 通常是指定 CC 的合并日志的目录 -->
31 <merge dir="projects/${project.name}/test-reports"/>
32 </log>
33
34 <!-- 在 build loop 结束之后运行,发布 build 的结果 -->
35 <publishers>
36 <!--onsuccess-->
37 <!--用于对创建过程中产生的人工制品进行发布-->
38 <!--artifactspublisher dest="artifacts/${project.name}" file="projects/${project.name}/target/${project.name}.jar"/>
39 </onsuccess-->
40
41 <!--
42 mailhost=邮件主机
43 returnname=发件人
44 returnaddress=发件地址
defaultsuffix=默认邮件后缀
45 -->
46 <htmlemail
47 charset="UTF-8"
48 mailhost="test163.com"
49 defaultsuffix="@xxx.com"
50 username="xxx@163.com"
51 password="xxx"
52 returnname="CruiseControl"
53 returnaddress="xxx@163.com"
54 subjectprefix="构建日志"
55 xsldir="webapps/cruisecontrol/xsl"
56 css="webapps/cruisecontrol/css/cruisecontrol.css">
57 <always address="xxx@xxx.com.cn"/>
58 <failure address="xxx@xxx,yyy@yyy.com.cn"/>
59
60 </htmlemail>
61
62 </publishers>
63
64 </project>
65</cruisecontrol>
配置文件有一个cruisecontrol根结点,其下则是代表一个项目的project子节点,再下层是项目的具体配置,在此示例中,存在了listeners、bootstrappers、modificationset、schedule、log几个节点,分别代表了监听器、本地目录、变更目录、构建任务、日志工作。
3.1.创建一个项目
<project name="CMAssess">
<listeners>
<currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
</listeners>
...............
</project>
项目工程下的build.xml说明:
<?xml version="1.0" encoding="UTF-8" ?>
2
3<!-- Continuous Integration 工程名称 Gms 默认任务 CI -->
4<project default="CI" name="xxx" basedir=".">
5
6
7 <!-- 特性文件 在特性文件中 注意路径的正反斜杠问题 -->
8 <property file="build.properties"/>
9
10 <!-- ================================ 工程参数 ================================ -->
11
12 <!-- 工程中文名称 -->
13 <property name="projectName_CN" value="xxx"/>
14 <!-- 工程目录 -->
15 <property name="projectFolder" value="${projcet.path}/${projcet.name}"/>
16
17 <!-- 源程序目录 -->
18 <property name="sourceFolder" value="${projectFolder}/src/main/java"/>
19 <!-- 配置文件目录 -->
20 <property name="configFolder" value="${projectFolder}/src/main/config"/>
21 <!-- 测试程序目录 -->
22 <property name="testFolder" value="${projectFolder}/src/test/java"/>
23 <!-- lib目录 -->
24 <property name="libFolder" value="${projectFolder}/WebRoot/WEB-INF/lib"/>
25 <!-- 编译程序目录 -->
26 <property name="classFolder" value="${projectFolder}/WebRoot/WEB-INF/classes"/>
27
28 <!-- 单元测试报告目录 -->
29 <property name="reportFolder" value="${projectFolder}/test-reports"/>
30 <!-- 单元测试报告文件名 -->
31 <property name="reportFileName" value="junit-noframes.html"/>
32
33 <!-- ================================ 发布设置 ================================ -->
34
35 <!-- 生成war文件 -->
36 <property name="warFile" value="${projectFolder}/${projcet.name}.war"/>
37 <!-- web.xml文件 -->
38 <property name="webFile" value="${projectFolder}/WebRoot/WEB-INF/web.xml"/>
39 <!-- 生成war文件的基础路径 -->
40 <property name="warSource" value="${projectFolder}/target/classes"/>
41
42 <!-- ================================ 路径设置 ================================ -->
43
44 <!-- 编译过程中用到的路径 -->
45 <path id="compilePath">
46 <!-- 编译程序目录 -->
47 <pathelement path="${classFolder}" />
48 <!-- 编译时lib路径 -->
49 <path refid="libPath" />
50 </path>
51
52 <!-- 单元测试时用到的路径 -->
53 <path id="jUnitPath">
54 <!-- 编译程序目录 -->
55 <pathelement path="${classFolder}" />
56 <!-- 编译时lib路径 -->
57 <path refid="libPath" />
58 </path>
59
60 <!-- 编译时lib路径 -->
61 <path id="libPath">
62 <!-- lib目录 -->
63 <fileset dir="${libFolder}">
64 <include name="**/*.jar" />
65 </fileset>
66 </path>
67
68 <!-- ================================ 持续集成 ================================ -->
69
70 <!-- 集成流程 暂时没有加入 Test -->
71 <target name="CI" depends="init,compile,test,makewar,deploy-catalina" description="持续集成"/>
72
73 <!-- 1.初始化目标目录, class ; report -->
74 <target name="init" description="初始化">
75
76 <echo>正在删除编译程序目录</echo>
77 <delete dir="${classFolder}" />
78 <echo>正在创建编译程序目录</echo>
79 <mkdir dir="${classFolder}" />
80
81 <echo>正在删除单元测试报告目录</echo>
82 <delete dir="${reportFolder}" />
83 <echo>正在创建单元测试报告目录</echo>
84 <mkdir dir="${reportFolder}" />
85 </target>
86
87 <!-- 2.编译程序生成目标类 -->
88 <target name="compile" depends="init" description="编译">
89 <echo>编译源程序</echo>
90 <!-- classpathref="编译路径" destdir="${编译程序目录}" -->
91 <javac classpathref="compilePath" fork="true" memorymaximumsize="128m"
92 destdir="${classFolder}" debug="true" deprecation="false"
93 failonerror="false" verbose="false">
94 <!-- 源程序目录 -->
95 <src path="${sourceFolder}" />
96 <!-- 测试程序目录 -->
97 <src path="${testFolder}" />
98 <!-- 配置文件目录 -->
99 <src path="${configFolder}" />
100
101 <include name="**/*.java" />
102 </javac>
103 <copy todir="${classFolder}">
104 <fileset dir="${configFolder}">
105 <include name="**/*.*"/>
106 </fileset>
107 <fileset dir="${sourceFolder}">
108 <include name="**/*.xml"/>
109 </fileset>
110 </copy>
111 </target>
112
113 <!-- 3.运行JUnit测试 -->
114 <target name="test" description="执行单元测试">
115 <echo>运行单元测试用例</echo>
116 <!-- haltonfailure="true" 出现fail即终止build -->
117 <junit printsummary="true">
118 <classpath refid="jUnitPath" />
119 <!-- 指定测试结果类型 -->
120 <formatter type="xml"/>
121 <!-- 批量测试集 todir="${reportFolder}" 单元测试报告目录 -->
122 <batchtest todir="${reportFolder}">
123 <!-- dir="${classFolder}" 编译程序目录 -->
124 <fileset dir="${classFolder}">
125 <!-- 包含 -->
126 <include name="**/*Test.class"/>
127 </fileset>
128 </batchtest>
129 </junit>
130
131 <echo>生成单元测试报告</echo>
132 <!-- XSLT格式化XML,生成HTML的报告 todir="${reportFolder}" 单元测试报告目录 -->
133 <junitreport todir="${reportFolder}" description="生成单元测试报告">
134 <fileset dir="${reportFolder}">
135 <!-- formatter生成报告文件的默认命名规范是TEST-*.xml -->
136 <include name="TEST-*.xml" />
137 </fileset>
138 <!-- format="frames" 生成有框架 noframes 无框架-->
139 <report format="frames" todir="${reportFolder}" />
140 </junitreport>
141 </target>
142
143 <!-- 4.打包成war文件 -->
144 <target name="makewar" depends="" description="发布WAR文件">
145 <echo>打包成war文件</echo>
146 <war destfile="${warFile}" webxml="${webFile}">
147 <!-- 添加web文件,过滤web.xml与测试类 -->
148 <fileset dir="${projectFolder}/WebRoot" excludes="WEB-INF/web.xml,WEB-INF/classes/**/*Test.class"/>
149 </war>
150 </target>
项目工程下的build.xml说明:
<?xml version="1.0" encoding="UTF-8" ?>
2
3<!-- Continuous Integration 工程名称 Gms 默认任务 CI -->
4<project default="CI" name="xxx" basedir=".">
5
6
7 <!-- 特性文件 在特性文件中 注意路径的正反斜杠问题 -->
8 <property file="build.properties"/>
9
10 <!-- ================================ 工程参数 ================================ -->
11
12 <!-- 工程中文名称 -->
13 <property name="projectName_CN" value="xxx"/>
14 <!-- 工程目录 -->
15 <property name="projectFolder" value="${projcet.path}/${projcet.name}"/>
16
17 <!-- 源程序目录 -->
18 <property name="sourceFolder" value="${projectFolder}/src/main/java"/>
19 <!-- 配置文件目录 -->
20 <property name="configFolder" value="${projectFolder}/src/main/config"/>
21 <!-- 测试程序目录 -->
22 <property name="testFolder" value="${projectFolder}/src/test/java"/>
23 <!-- lib目录 -->
24 <property name="libFolder" value="${projectFolder}/WebRoot/WEB-INF/lib"/>
25 <!-- 编译程序目录 -->
26 <property name="classFolder" value="${projectFolder}/WebRoot/WEB-INF/classes"/>
27
28 <!-- 单元测试报告目录 -->
29 <property name="reportFolder" value="${projectFolder}/test-reports"/>
30 <!-- 单元测试报告文件名 -->
31 <property name="reportFileName" value="junit-noframes.html"/>
32
33 <!-- ================================ 发布设置 ================================ -->
34
35 <!-- 生成war文件 -->
36 <property name="warFile" value="${projectFolder}/${projcet.name}.war"/>
37 <!-- web.xml文件 -->
38 <property name="webFile" value="${projectFolder}/WebRoot/WEB-INF/web.xml"/>
39 <!-- 生成war文件的基础路径 -->
40 <property name="warSource" value="${projectFolder}/target/classes"/>
41
42 <!-- ================================ 路径设置 ================================ -->
43
44 <!-- 编译过程中用到的路径 -->
45 <path id="compilePath">
46 <!-- 编译程序目录 -->
47 <pathelement path="${classFolder}" />
48 <!-- 编译时lib路径 -->
49 <path refid="libPath" />
50 </path>
51
52 <!-- 单元测试时用到的路径 -->
53 <path id="jUnitPath">
54 <!-- 编译程序目录 -->
55 <pathelement path="${classFolder}" />
56 <!-- 编译时lib路径 -->
57 <path refid="libPath" />
58 </path>
59
60 <!-- 编译时lib路径 -->
61 <path id="libPath">
62 <!-- lib目录 -->
63 <fileset dir="${libFolder}">
64 <include name="**/*.jar" />
65 </fileset>
66 </path>
67
68 <!-- ================================ 持续集成 ================================ -->
69
70 <!-- 集成流程 暂时没有加入 Test -->
71 <target name="CI" depends="init,compile,test,makewar,deploy-catalina" description="持续集成"/>
72
73 <!-- 1.初始化目标目录, class ; report -->
74 <target name="init" description="初始化">
75
76 <echo>正在删除编译程序目录</echo>
77 <delete dir="${classFolder}" />
78 <echo>正在创建编译程序目录</echo>
79 <mkdir dir="${classFolder}" />
80
81 <echo>正在删除单元测试报告目录</echo>
82 <delete dir="${reportFolder}" />
83 <echo>正在创建单元测试报告目录</echo>
84 <mkdir dir="${reportFolder}" />
85 </target>
86
87 <!-- 2.编译程序生成目标类 -->
88 <target name="compile" depends="init" description="编译">
89 <echo>编译源程序</echo>
90 <!-- classpathref="编译路径" destdir="${编译程序目录}" -->
91 <javac classpathref="compilePath" fork="true" memorymaximumsize="128m"
92 destdir="${classFolder}" debug="true" deprecation="false"
93 failonerror="false" verbose="false">
94 <!-- 源程序目录 -->
95 <src path="${sourceFolder}" />
96 <!-- 测试程序目录 -->
97 <src path="${testFolder}" />
98 <!-- 配置文件目录 -->
99 <src path="${configFolder}" />
100
101 <include name="**/*.java" />
102 </javac>
103 <copy todir="${classFolder}">
104 <fileset dir="${configFolder}">
105 <include name="**/*.*"/>
106 </fileset>
107 <fileset dir="${sourceFolder}">
108 <include name="**/*.xml"/>
109 </fileset>
110 </copy>
111 </target>
112
113 <!-- 3.运行JUnit测试 -->
114 <target name="test" description="执行单元测试">
115 <echo>运行单元测试用例</echo>
116 <!-- haltonfailure="true" 出现fail即终止build -->
117 <junit printsummary="true">
118 <classpath refid="jUnitPath" />
119 <!-- 指定测试结果类型 -->
120 <formatter type="xml"/>
121 <!-- 批量测试集 todir="${reportFolder}" 单元测试报告目录 -->
122 <batchtest todir="${reportFolder}">
123 <!-- dir="${classFolder}" 编译程序目录 -->
124 <fileset dir="${classFolder}">
125 <!-- 包含 -->
126 <include name="**/*Test.class"/>
127 </fileset>
128 </batchtest>
129 </junit>
130
131 <echo>生成单元测试报告</echo>
132 <!-- XSLT格式化XML,生成HTML的报告 todir="${reportFolder}" 单元测试报告目录 -->
133 <junitreport todir="${reportFolder}" description="生成单元测试报告">
134 <fileset dir="${reportFolder}">
135 <!-- formatter生成报告文件的默认命名规范是TEST-*.xml -->
136 <include name="TEST-*.xml" />
137 </fileset>
138 <!-- format="frames" 生成有框架 noframes 无框架-->
139 <report format="frames" todir="${reportFolder}" />
140 </junitreport>
141 </target>
142
143 <!-- 4.打包成war文件 -->
144 <target name="makewar" depends="" description="发布WAR文件">
145 <echo>打包成war文件</echo>
146 <war destfile="${warFile}" webxml="${webFile}">
147 <!-- 添加web文件,过滤web.xml与测试类 -->
148 <fileset dir="${projectFolder}/WebRoot" excludes="WEB-INF/web.xml,WEB-INF/classes/**/*Test.class"/>
149 </war>
150 </target>
一个持续集成项目是从project节点开始的,可以对该项目进行的操作都会作为子节点存在与该节点之下。对于每一个project节点,CruiseControl系统都会将其当作一个处理单元,并在最初建立该项目的时候进行初始化操作。
name是project节点常用的属性,也是必设且值唯一的属性,该属性的值会在整个CruiseControl系统使用,包括配置文件的${project.name}变量值。
在一个项目节点中,我们可以定义监听器、本地目录位置、变更轮询目录位置、轮询间隔、任务执行、单元测试、日志记录等多种项目操作,同时CruiseControl系统支持插件扩展功能,这些扩展插件可以直接在一个项目中使用。
3.2.轮询版本控制系统
版本库轮询机制是使用modificationset进行配置的。CruiseControl系统内置的轮询模块会根据设定的时间段对版本库进行检测,一旦发现版本库发生变更,就会调用Check OutàBuildàTestàPublish等一系列的操作,对最新的代码进行集成,并运行一系列预先设定的任务。
CruiseControl支持十多种版本控制系统,比如CVS、SVN、Starteam、VSS等,对这些版本控制系统的调用,只需要配置相应的节点名称即可。本文以SVN版本管理系统为例。
在modificationset节中,我们看到唯一的一个子节点:
<svn localWorkingCopy="projects/CM/${project.name}/src/${project.name}"/>
该节点使用了svn关键字,表示当前工程使用的版本控制系统是SVN,localWorkingCopy属性的值是告诉CruiseControl本地的拷贝目录,其余的工作则由CruiseControl内置的操作模块进行。
3.3. 执行构建脚本
实质上,执行构建脚本也是CruiseControl的一个可定制任务,但由于自动构建是持续集成的一个重要组成部分,因此在此单独提出。
CruiseControl的自动构建是使用ANT工具来进行的,当然我们也可以使用其它的自动构建工具来替代(比如Maven),这些的工具仅仅是体现在一个任务配置语句上,在此,以ANT工具为例。
在schedule节,我们同样使用了一个子节点来描述自动构建工作:
<ant anthome="ant6" buildfile="projects/CM/${project.name}/src/${project.name}/build.xml"/>
该节点使用了ant关键字,表示该任务使用了ant来进行自动构建任务,anthome属性则指定了ANT工具的具体位置,buildfile属性则指定了ANT进行自动构建所使用的配置文件Build.xml文件的路径。
这样,在CruiseControl决定进行自动构建任务时,会根据设定找到执行所使用到的信息。
3.4.执行单元测试
CruiseControl可以自动侦测自动构建配置文件中单元测试的任务,并在代码集成完毕将执行结果反馈到相应的模块。
ANT支持xUnit系列的单元测试框架,只需要在配置文件中加入一个target节,即可在自动构建完成之后,进行单元测试工作,有关的详细配置,请参阅ANT官方文档。
4.CruiseControl的使用
4.1.启动CruiseControl服务器
通过上一节的配置,CruiseControl系统已经可以正常运行并管理项目了。我们可以通过执行其安装目录下的cruisecontrol.bat文件来启动CruiseControl。控制台显示“BuildQueue - BuildQueue started”,则说明CruiseControl服务器已成功启动。
在启动服务器之前,我们可以打开cruisecontrol.bat文件并修改倒数第三行相应功能的端口数值来指定服务器占用的系统端口,在本例中我们将-webport指定到了8088端口。
4.2.管理工程
服务器启动之后,我们就可以在浏览器里访问使用了,如 http://127.0.0.1:8088/dashboard/tab/builds 访问CruiseControl的Web服务器。当前CruiseControl系统就会存在一些项目工程,列表中显示了各个工程的相关信息,包括当前状态、上次失败时间、上次成功时间、构建次数等信息,同时Build按钮可以让CruiseControl立即检测工程状态。
点击相应工程名称,则可以进入该工程的详细页面首页,首页清晰明了,主要包括了构建历史信息、最近构建结果、最近构建版本库信息等,该页面可以让我们对当前工程的集成信息一目了然,便于我们对不同的集成结果做出相应的处理。
页面上部的导航按钮可以让我们进入不同信息的查看界面,包括测试结果、XML详细日志文件、状态统计等信息。这些导航按钮根据工程设置的不同扩展任务而有所不同。
5.工作总结
持续集成为我们带来诸多好处,大量降低集成时间的同时,更重要的是它可以迅速对我们的工作做出反馈,保证了项目的质量。持续集成已经不像以前只存在于理论的名词,只要你愿意你都可以实施持续集成。
当然这些好处是建立在制度的遵循和详尽的单元测试的基础上的,持续集成系统仅仅是我们项目过程中的一个工具而已,正如SCM工具、单元测试一样。工具就是工具,而真正默默起作用的则是项目团队人员之间标准制度的完善与执行。
- CruiseControl服务器安装配置
- cruisecontrol 配置
- CruiseControl配置方法
- CruiseControl基础配置
- CruiseControl配置详解
- cruiseControl.net 配置总结
- CruiseControl 配置简述
- (ZT)CruiseControl.NET配置总结
- CruiseControl日构建简单配置
- cruisecontrol + svn + maven2 配置总结
- Cruisecontrol测试工具配置总结
- [CruiseControl]binary安装和启动
- CruiseControl
- 【经验】CruiseControl.Net的安装、配置和遇到的一些问题
- SVN 配置 之四 CruiseControl.NET & CruiseControl.NET CCTray
- 一点不难配置的CruiseControl持续集成
- 配置CruiseControl.Net的问题总结
- Ant、SVN、CruiseControl每日构建 配置方法
- 打印Android程序所占内存
- 原创 Windows Embedded Compact 7平台GPS设计
- Linux路由表的结构与算法分析
- XML文件的解析--libxml库函数解释
- java学习(6)
- CruiseControl服务器安装配置
- 解决 “数据库 'tempdb' 的日志已满。请备份该数据库的事务日志以释放一些日志空间” 的问题
- java学习(7)
- WordPress——Install WEMP(WordPress, nginx, MySQL and PHP)
- poll 的实现
- C++ LOG 通用解决方案
- 写在博客之前
- 【编程语言】Android--eclipse关联android.jar的方法
- linux svn命令大全