持續集成
持 續 集 成
編寫:jerry 創建日期:2005-04-21 最后更新:2005-04-22 版次:1.0
本文針對Java項目的持續集成而編寫,描述了Java項目持續集成中采用的工具、工具的簡介以及簡單的一個持續集成的實例。
1. 概述
持續集成作為軟件開發過程中的重要項,為軟件質量的保證提供了基礎,并起到了保證軟件構建的頻率以及及早發現錯誤的可能性,減少了排錯的成本、減少或者說免除了集成人員在系統集成、部署上的工作量,使得之前噩夢般的集成工作能夠自動的得以進行,不僅僅如此,持續集成還使得軟件進度可以一目了然的為眾人所知。
項目的持續集成主要需要實現的是項目的自動編譯、代碼檢查、自動測試、自動集成與部署、集成狀態的通知、本次集成的改變項(即俗稱的changelog)甚至是項目網站的生成。持續集成包括了日構建和感知版本工具(例如CVS)的變化進行實時集成兩種,對于Java項目為實現持續集成通常采用的工具是CruiseControl+Maven(或Ant)。
2. 持續集成工具
2.1. CruiseControl
簡稱CC,持續集成工具,主要提供了基于版本管理工具(如CVS)感知變化或每天定時的持續集成,并提供持續集成報告、Email、Jabber等等方式通知相關負責人,同時也可通過網站查看持續集成的狀況,其要求是需要進行持續集成的項目已編寫好全自動的項目編譯腳本(可基于Maven或Ant)。
CruiseControl為通過編寫腳本的方法實現,其腳本通常由一個xml文件組成。
可去官方網站查看更為詳細的關于CruiseControl的信息,官方網站為:CruiseControl.sf.net。
2.2. Maven
項目編譯、集成、部署腳本工具,可稱為ant的升級版,較之ant提供了更為方便的對于多項目(項目依賴性的編譯)的支持,基于插件機制,提供了眾多的插件(諸如代碼檢查工具、War生成工具、Jar生成工具、項目網站生成工具等等)以幫助腳本編寫人員完成項目集成腳本的編寫,并提供了Eclipse Plugin使得腳本的編寫更加的簡便。
通常采用編寫Maven腳本的方法來實現項目的自動編譯、集成和部署,Maven腳本通常包含四個文件:project.xml、build.properties、project.properties以及maven.xml。project.xml中描述當前項目的一些元數據信息,如項目名、項目的開發者、項目網站、項目的源碼目錄、項目中所引用的包等等;build.properties中通常描述當前項目在進行自動編譯時用到的一些Maven性質的屬性,如maven包倉庫的路徑,遠程Maven包倉庫的url等;project.properties通常用于描述項目編譯過程時的一些項目屬性信息;maven.xml作為項目編譯的腳本,包含了項目在進行自動集成時所做的步驟的描述,如編譯、運行單元測試、打包等,在腳本中調用的通常為Maven已提供的插件,當然,也可根據需要編寫自己的插件以支持特殊的集成的要求。
可去官方網站查看更為詳細的關于Maven的信息,官方網站為:maven.apache.org。
3. 實現
l 搭建CruiseControl、Maven環境。
l 制定項目中各工程的源碼結構規范。(方便項目集成腳本的編寫)
l 根據項目需求編寫項目集成腳本。(Maven腳本)
l 根據持續集成需求編寫持續集成腳本。(CruiseControl腳本)
l 部署腳本,啟動CruiseControl,進行持續集成。
4. 示例
我們以一個Web應用系統為例說明整個持續集成的實現過程。
4.1. 背景
此Web應用系統的分為三個工程,分別為Container、Util、DemoPortlet共同組成,各工程的結構為src/java,src/test,src/java中放置了工程的源碼、配置文件、圖片等等,src/test中放置了工程的單元測試代碼、功能測試代碼,所引用的包均放入Maven的repository(關于此部分可參見Maven網站的簡介)中,Container中包含了web應用目錄,放置在webapp目錄下。
4.2. 需求
l 持續集成需求
u 感知版本管理工具(CVS)的變化,如發現有變化,則進行集成。
u 調用項目編譯腳本進行項目集成。
u 合并項目編譯腳本產生的單元測試、功能測試的日志。
u 將集成報告發布至網站中。
u 將集成的結果以郵件方式通知相應的負責人。
l 項目集成需求
u 編譯util工程,運行其中的單元測試代碼并最終打成jar包放入Maven的repository中。
u 編譯Container工程,運行其中的單元測試代碼并最終打成war包放入應用服務器(Tomcat)中,啟動Tomcat,運行功能測試。
u 編譯DemoPortlet工程,運行其中的單元測試代碼并最終打成Portlet插件包部署至位于Tomcat下的Container中,運行功能測試。
4.3. 實現
l 搭建CruiseControl、Maven環境。(這個就不在這講了,請參看官方網站的文檔)
l 編寫項目集成腳本并測試。
根據項目集成需求中的描述,分別對三個工程編寫腳本(Maven.xml)。
u Util工程
1) 編寫project.xml,或者可在Eclipse中利用Maven Plugin圖形化的編輯方式生成project.xml。project.xml(詳細信息見官方網站的文檔)如下:
<project>
<pomVersion>1</pomVersion>
<artifactId>util</artifactId>
<id> util </id>
<name> util </name>
<groupId>jite</groupId>
<currentVersion>1.0</currentVersion>
<organization>
<name>Jite</name>
<url>www.jite.net</url>
</organization>
<inceptionYear>2004</inceptionYear>
<package>net.jite.demo</package>
<description>Demo Util</description>
<issueTrackingUrl>bugs.jite.com</issueTrackingUrl>
<repository/>
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>2.1</version>
<jar>commons-collections-2.1.jar</jar>
<type>jar</type>
<properties/>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>
<jar>commons-logging-
<type>jar</type>
<properties/>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>
<jar>junit-
<type>jar</type>
<properties/>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/java</sourceDirectory>
<unitTestSourceDirectory>src/test</unitTestSourceDirectory>
<unitTest>
<includes>
<include>**/*Test.java</include>
</includes>
</unitTest>
</build>
<properties/>
</project>
2) 編寫build.properties。build.properties如下:
## Maven遠程包倉庫URL
maven.repo.remote = http://public.planetmirror.com/pub/maven,http://mirrors.sunsite.dk/maven
## 本地Maven環境路徑
maven.local.home = D:/Maven
## 本地Maven包倉庫路徑
maven.repo.local = ${maven.local.home}/repository
3) 編寫maven.xml。maven.xml如下:
<?xml version="1.0" encoding="GBK"?>
<project default="util:build" xmlns:maven="jelly:maven" xmlns:ant="jelly:ant"
xmlns:j="jelly:core" xmlns:util="jelly:util">
<!-- 項目自動集成:初始化、打包發布-->
<goal name="util:build">
<attainGoal name="util:init"/>
<attainGoal name="util:package"/>
<echo>+---------------------------------------------+</echo>
<echo>| 已完成自動集成 </echo>
<echo>+---------------------------------------------+</echo>
</goal>
<!--
完成一些初始化工作
1. 清空編譯文件夾
2. 同步eclipse,在eclipse中建立MAVEN_REPO變量
-->
<goal name="util:init">
<echo>+---------------------------------------------+</echo>
<echo>| Build System </echo>
<echo>| ------- </echo>
<echo>+---------------------------------------------+</echo>
<attainGoal name="clean"/>
</goal>
<!--
自動設置eclipse project 屬性
1. 添加 MAVEN_REPO 變量
2. 同步 dependencies 與 eclipse build path
-->
<goal name="util:eclipse">
<attainGoal name="eclipse:add-maven-repo"/>
<attainGoal name="eclipse:generate-classpath"/>
</goal>
<!--
打包為jar,并install到maven的repository中
-->
<goal name="util:package">
<attainGoal name="jar:install"/>
</goal>
</project>
u Container工程
Container工程基本同Util工程相應的編寫project.xml、project.properties、build.properties以及maven.xml,不同的在于maven.xml的編寫時需要生成的為war包(Maven已提供此插件),在Maven的官方網站上均可找到相似的示例。
u DemoPortlet工程
DemoPortlet工程的腳本的編寫方法和Util工程也基本相同,不同之處在于需要將DemoPortlet工程按照項目的插件機制要求打包發布至Tomcat的相關目錄中。
在編寫完畢上述三個工程的Maven腳本后,在Util、Container、DemoPortlet的上一級目錄編寫一個project.xml和Maven.xml以支持此項目的多工程自動集成。
Project.xml:
<project>
<pomVersion>1</pomVersion>
<name>MultiProject</name>
<groupId>MultiProject</groupId>
<organization>
<name>jite.net</name>
</organization>
<inceptionYear>2005</inceptionYear>
<properties/>
</project>
Maven.xml:
<?xml version="1.0" encoding="gb2312"?>
<project default="demo:allbuild" xmlns:maven="jelly:maven" xmlns:ant="jelly:ant"
xmlns:j="jelly:core" xmlns:util="jelly:util">
<goal name="demo:allbuild">
<!-- 部署util-->
<maven:reactor
basedir="${basedir}"
includes="util 1.0/project.xml"
goals="util:build"
banner="install util"
postProcessing="false"
ignoreFailures="false"/>
<!-- 部署Container-->
<maven:reactor
basedir="${basedir}"
includes="Container 1.0/project.xml"
goals="container:build"
banner="install Container"
postProcessing="false"
ignoreFailures="false"/>
<!-- 部署DemoPortlet-->
<maven:reactor
basedir="${basedir}"
includes="DemoPortlet 1.0/project.xml"
goals="DemoPortlet:build"
banner="install DemoPortlet"
postProcessing="false"
ignoreFailures="false"/>
</goal>
</project>
在此目錄下運行maven,如編譯過程順利執行完畢則表明項目自動集成腳本已編寫完畢并且確認當前的CVS環境是可被自動集成的。
l 編寫持續集成腳本并測試。
建立一個持續集成目錄為ContinuousIntegration,從CVS下載一份項目目錄至此目錄中,假設此目錄名為Demo。
根據持續集成的要求編寫持續集成腳本如下:
<?xml version="1.0" encoding="UTF-8"?>
<cruisecontrol>
<project name="demo" buildafterfailed="true">
<!-- 每次檢測是否有變化時先運行此處 -->
<bootstrappers>
<currentbuildstatusbootstrapper file="logs/demo/buildstatus.txt"/>
</bootstrappers>
<!-- 檢測是否有變化,如有變化則開始集成 -->
<modificationset quietperiod="10">
<!-- 基于cvs的檢測 -->
<cvs localworkingcopy="demo"/>
</modificationset>
<!-- 持續集成-->
<schedule interval="18">
<!-- 項目的編譯腳本 -->
<maven mavenscript="D:/tools/maven/bin/maven.bat"
projectfile="demo/project.xml"
goal="demo:allbuild"/>
</schedule>
<!-- 持續集成過程的日志記錄以及需要合并的日志 -->
<log dir="logs/demo">
<!-- 合并項目編譯腳本中產生的單元、功能測試日志 -->
<merge dir="demo/util/target/test-reports"/>
<merge dir="demo/container/target/test-reports"/>
<merge dir="demo/demoportlet /target/test-reports"/>
</log>
<!-- 持續集成后結果的公布 -->
<publishers>
<currentbuildstatuspublisher file="logs/demo/buildstatus.txt"/>
<!-- 郵件通知相關的負責人 -->
<email mailhost="smtp.yourdomain.com"
returnaddress="buildmaster@yourdomain.com"
skipusers="true"
reportsuccess="fixes"
subjectprefix="[CruiseControl]"
buildresultsurl="http://buildserver:8080/cruisecontrol/buildresults">
<failure address="developers@yourdomain.com" />
<success address="developers@yourdomain.com" />
</email>
</publishers>
</project>
</cruisecontrol>
將此腳本文件放入ContinuousIntegration目錄中,在此目錄下運行cruisecontrol或cc,提交一文件至cvs檢查持續集成的執行是否如需求中所預期的,如不正確則直至調為正確為止。
l 進行持續集成。
在ContiuousIntegration目錄下運行cc,從此以后將會根據需求中所描述的一樣進行項目的自動集成和部署。
通過以上示例大致的描述了持續集成實現的一些步驟,當然,在實際的項目持續集成實現的過程中腳本的編寫必然比上述的更為復雜,這就要求了腳本編寫人員需要對CruiseControl、Maven有足夠的了解,但相對于持續集成所帶來的好處這些都是值得的。
posted on 2005-05-19 21:55 BlueDavy 閱讀(962) 評論(0) 編輯 收藏 所屬分類: 系統過程優化