淺談CruiseControl的部署

ANT是用過的最好的Build工具.CruiseControl則通過不斷檢查SCM (VSS, ClearCase, StarTeam, etc), 一旦發現改動, 調用ANT進行編譯, 部署, 實現即時的集成. 一旦編譯失敗, 則立刻自動發Email給"始作俑"者, 提醒其修正代碼. CC自帶了一個Web應用, 可是隨時查看編譯狀況和歷史狀況(包括自從前一次Build, 有哪些文件,是誰做了改動, Build失敗的原因, Build的成果(自定義的, 比如最後的打包文件, 自動生成的JavaDoc) 總之, 通過集成Ant和CC, 儘量避免了Daily Build容易Broken的缺點, 而且自動化程度更高. 另外Ant和CC都分別有.net版本, 在下一個.net項目中, 還打算使用它們來進行集成控制. 安裝CruiseControl 和AntHill一樣,使用CruiseControl構建持續集成系統,需要Tomcat,Ant,CVSNT和WinCVS的支持(參見AntHill:構建Nightly Build系統)。安裝CruiseControl很簡單,下載cruisecontrol-2.2.zip(參見持續集成資源),解壓到安裝目錄C:/BuildServer,即可完成安裝。 安裝Tomcat4.1到C:/BuildServer目錄,並在C:/BuildServer目錄創建workingCopy子目錄,作爲CruiseControl的工作目錄。BuildServer的目錄結構如下圖所示,其中CruiseControl的啓動腳本cruisecontrol.bat(或cruisecontrol.sh)位於BuildServer/cruisecontrol-2.2/main/bin目錄下。 準備構建目錄結構 1.創建CruiseControl的日誌目錄:C:/BuildServer/cruisecontrol-2.2/main/logs/frameworkProject。 2.創建CVS的工作目錄:C:/BuildServer/workingCopy/frameworkProject。 3.創建工作目錄的代碼庫目錄:C:/BuildServer/workingCopy/frameworkProject/lib。 4.創建工作目錄的單元測試報告目錄:C:/BuildServer/workingCopy/frameworkProject/reports/junit/data。 5.創建工作目錄的jar文件存放目錄:C:/BuildServer/workingCopy/frameworkProject/dist。 初始化代碼工作目錄 在C:/BuildServer/workingCopy/frameworkProject目錄下,使用WinCVS CheckOut src模塊:cvs co src。 準備項目的依賴代碼庫 把構建項目的依賴代碼庫複製到C:/BuildServer/workingCopy/frameworkProject/lib。完成之後的目錄結構如上圖所示。 編寫項目構建腳本 構建腳本build.xml和build-cc.xml位於C:/BuildServer/workingCopy/frameworkProject目錄下。其中build.xml是項目的Ant構建腳本,而build-cc.xml負責幫助CruiseControl從CVS服務器上update源代碼到本地的工作目錄,然後調用build.xml構建項目。 build-cc.xml
<?xml version="1.0"?>
<project name="CruiseControlWrapperForFrameworkProject" default="build" basedir=".">
 <target name="update">
  <!-- update the working copy from the cvs -->
  <exec executable="cvs">
   <arg line="-d :pserver:talent:talent @10.75.140.128:/cvsroot update src"/>
  </exec>
 </target>
  <target name="build" depends="update">
  <!-- invoke the project's build script -->
  <ant antfile="build.xml" target="jar"/>
 </target>
</project>
build.xml
<?xml version="1.0"?>
<project name="frameworkProject" default="compile">
    <description>
        This is our framework project which we're putting on CruiseControl
    </description>
        <target name="setup" depends="setup.properties, setup.paths" />
    <target name="setup.properties">
        <property name="src.main" value="src" />
        <!--<property name="src.test" value="src/test" />-->
        <property name="classes" value="classes"/>
        <property name="classes.main" value="${classes}/main" />
        <!--<property name="classes.test" value="${classes}/test" />-->
        <property name="libs" value="lib" />
        <property name="dist" value="dist" />
        <property name="reports" value="reports" />
        <property name="reports.junit.data" value="${reports}/junit/data" />
    </target>
    <target name="setup.paths">
        <path id="classpath.main">
            <pathelement location="${classes.main}" />
        </path>
        <path id="classpath.lib">
         <fileset dir="${libs}">
          <include name="**/*.jar" />
         </fileset>
        </path>
    </target>
    <target name="clean" depends="setup">
        <delete dir="${classes}" failοnerrοr="false" />
        <delete dir="${reports}" failοnerrοr="false" />
        <delete dir="${dist}" failοnerrοr="false" />
    </target>
    <target name="compile" depends="setup, compile.main" />
    <target name="compile.main" depends="setup">
        <mkdir dir="${classes.main}" />
        <javac srcdir="${src.main}" destdir="${classes.main}">
         <classpath refid="classpath.lib" />
        </javac>
    </target>
    <target name="compile.tests" depends="setup">
        <mkdir dir="${classes.test}" />
        <javac srcdir="${src.test}"
               destdir="${classes.test}"
               classpathref="classpath.lib" />
    </target>
    <target name="test" depends="compile">
        <delete dir="${reports.junit.data}" failοnerrοr="false" />
        <mkdir dir="${reports.junit.data}" />
        <junit printsummary="yes" haltonfailure="no" 
               failureproperty="tests.failed">
            <classpath refid="classpath.lib" />
            <formatter type="xml" />
            <batchtest fork="yes" todir="${reports.junit.data}" 
                       failureproperty="tests.failed">
                <fileset dir="${src.test}">
                    <include name="**/*Test*.java" />
                    <exclude name="**/AllTests.java" />
                </fileset>
            </batchtest>
        </junit>
        <fail if="tests.failed" message="Some unit tests failed" />
    </target>
    <target name="jar" depends="compile, test">
        <mkdir dir="${dist}" />
        <jar destfile="${dist}/framework.jar" basedir="${classes.main}" />
    </target>
    <target name="all" depends="jar" />
</project>
配置CruiseControl config.xml 下面以一個簡單的config.xml文件爲例,說明CruiseControl的配置方法。配置文件config.xml位於C:/BuildServer/cruisecontrol-2.2/main/bin目錄下,和啓動腳本cruisecontrol.bat放在一起。
<?xml version="1.0"?>
<cruisecontrol>
 <project name="frameworkProject">
  <dateformat format="yyyy/MM/dd HH:mm:ss" />
  <bootstrappers>
   <currentbuildstatusbootstrapper file="../logs/currentbuild.txt" />
  </bootstrappers>
  <modificationset quietperiod="60" >
   <cvs LocalWorkingCopy="../../../workingCopy/frameworkProject/src"/>
  </modificationset>
  <schedule interval="3600" >
   <ant antWorkingDir="../../../workingCopy/frameworkProject" buildfile="build-cc.xml" />
  </schedule>
  <log dir="../logs/frameworkProject">
   <merge dir="../../../workingCopy/frameworkProject/reports/junit/data"/>
  </log>
  <publishers>
   <currentbuildstatuspublisher file="../logs/currentbuild.txt" />
   <artifactspublisher dir="../../../workingCopy/frameworkProject/dist" dest="../logs/frameworkProject" />
   <htmlemail mailhost="talenttech.com.cn"
    returnaddress="[email protected]" 
    subjectprefix="[Talent Build Server]"//自己替換[]
buildresultsurl="http://10.75.140.128:9000/cruisecontrol/buildresults/ ;frameworkProject"
logdir="C:/BuildServer/cruisecontrol-2.2/main/logs/frameworkProject"
            xsldir="C:/BuildServer/cruisecontrol-2.2/reporting/jsp/xsl"
css="C:/BuildServer/cruisecontrol-2.2/reporting/jsp/css/cruisecontrol.css">
    <failure address="[email protected]" />
    <success address="[email protected]" />
    <success address="[email protected]" />
    <success address="[email protected]" />
    <success address="[email protected]" />
   </htmlemail>
  </publishers>
 </project>
</cruisecontrol>
<cruisecontrol> <cruisecontrol>是配置文件的根元素,它可以擁有一個或多個<project>子元素。本例中它擁有一個項目名爲frameworkProject。 <project> <project>元素是一個完整的build任務,包括檢查配置管理庫是否有新的修改,構建項目併發布項目構建結果。它告訴CruiseControl構建什麼,何時構建,如何構建以及如何發佈構建報告。它有一個必需的屬性name和一個可選屬性buildafterfailed。 屬性buildafterfailed定義了當構建失敗時,是否要繼續進行,缺省是"true"。 <project>元素的子元素包括,<bootstrappers>,<modificationset>,<schedule>,<log>,<publishers>,<dateformat>和<plugin>,其中<modificationset>和<schedule>是必需的元素。 <dateformat> <dateformat>用於定義日期的格式,缺省格式是:MM/dd/yyyy HH:mm:ss。 <bootstrappers> <bootstrappers>元素是啓動任務Plugin的容器,用於定義構建任務啓動前需要執行的任務。常用的Plugin包括: 1. <currentbuildstatusbootstrapper>,定義一個CruiseControl的構建狀態信息文件。CruiseControl的Build Result JSP從該文件讀取狀態信息並顯示在頁面上。屬性file用於指定構建狀態文件目錄和文件名。 2. <cvsbootstrapper>,用於在項目構建開始前從CVS服務器上update指定的文件。通常可以用於更新項目的構建腳本。屬性localWorkingCopy指定CVS本地工作目錄,屬性file指定需要update的文件名,相對於屬性localWorkingCopy指定的目錄。 <modificationset> <modificationset>元素用於告訴CruiseControl是否需要構建項目,即配置管理庫的代碼是否存在更新。它擁有兩個可選屬性requiremodification和quietperiod。 屬性requiremodification告訴CruiseControl,在配置管理庫沒有代碼更新的情況下,是否需要構建。缺省爲"true",即沒有更新則無須進行構建。 屬性quietperiod告訴CruiseControl,最新一次代碼提交後CruiseControl需要等待的時間(秒)。用於防止CruiseControl在開發人員提交代碼時進行項目構建。缺省爲"60"秒。 在本例中使用<cvs>來檢查和工作目錄相關的代碼在CVS配置管理庫是否有更新。<cvs>使用"cvs log"命令來檢查最新更新工作目錄和當前代碼庫的差異。 <schedule> 到目前爲止,以上的配置文件內容已經定義了CruiseControl構建什麼以及何時構建。<schedule>元素告訴CruiseControl每隔多長時間(秒)啓動一次構建任務。它有一個可選的屬性interval,用於定義以秒爲單位的時間間隔。缺省爲"300"秒。 在本例中,屬性interval設爲"3600",這意味着CruiseControl每隔一個小時使用<modificationset>定義的任務檢查一次代碼庫。 <schedule>元素擁有三個子元素<ant>,<maven>和<parse>。 <ant>子元素告訴CruiseControl何時或每隔幾次運行Ant來構建項目。 在本例中,antWorkingDir屬性設定Ant的工作目錄,buildfile屬性設定構建腳本build file的目錄。 屬性multiple告訴CruiseControl每隔幾次執行一次本<ant>任務。 除此之外,還可以指定Ant的運行時間(time屬性),build file的target(target屬性,不設定則爲build file的缺省target)。 請參見CruiseControl的配置文檔(位於${CruiseControl_Home}/main/docs目錄下)。 <log> <log>元素設定CruiseControl日誌文件的存放目錄,並通過<merge>子元素指定合併什麼樣的XML文件(構建過程中產生的文件)到CruiseControl的日誌文件中。 <merge>子元素的pattern屬性定義匹配的文件名模式,缺省爲".xml";dir屬性用於指定一個目錄,這個目錄下所有匹配模式的文件將合併到CruiseControl的日誌文件中。 <publishers> <publishers>元素用於指定構建任務結束後,CruiseControl如何發佈項目構建結果。項目構建結果的發佈方式可以是Email,網頁,複製代碼庫到指定的目錄,或是發佈代碼庫到FTP服務器。 在本例中,共有<currentbuildstatuspublisher>,<artifactspublisher>和<htmlemail>三個publisher。 <currentbuildstatuspublisher> publisher把下次構建的時間寫入指定文件,文件名由file屬性設定。 <artifactspublisher> publisher元素把項目構建產品複製到指定的目錄,dir屬性定義源目錄,dest定義目標目錄的父目錄(實際目錄還要加上構建時的時間戳,如:父目錄/19890604203828)。 <htmlemail> publisher把構建結果以HTML格式通過Email發佈。缺省情況下,HTML格式的Emai和CruiseControl Web應用的構建結果JSP頁面相同。 本例中<htmlemail>的屬性和子元素的作用很容易理解,更多的配置項參見聯機文檔。 創建CruiseControl的Web應用 1. 在C:/BuildServer/cruisecontrol-2.2/reporting/jsp目錄下運行build war命令; 2. 提示設置user.log.dir屬性時,輸入C:/BuildServer/cruisecontrol-2.2/main/logs; 3. 提示設置user.build.status.file屬性時,輸入currentbuild.txt; 4. 提示設置cruise.build.artifacts.dir屬性時,輸入/artifacts/frameworkProject; 5. Web應用構建完成後,可以在C:/BuildServer/cruisecontrol-2.2/reporting/jsp/dis目錄下找到cruisecontrol.war文件; 6. 把cruisecontrol.war複製到tomcat的webapps目錄下,發佈CruiseControl的Web應用; 啓動CruiseControl 使用C:/BuildServer/cruisecontrol-2.2/main/bin目錄下cruisecontrol.bat啓動CruiseControl。用法如下: C:/BuildServer/cruisecontrol-2.2/main/bin>cruisecontrol [options] 命令cruisecontrol的選項包括: -port [number] JMX服務器的Http Controller的端口;缺省爲8000 -rmiport [number] JMX服務器的RMI Controller的端口;缺省爲1099 -xslpath directory JMX的XSL文件存放目錄; -configfile file 配置文件的路徑;缺省爲當前目錄下的config.xml文件 -debug 將CruiseControl內部的日誌級別調整到DEBUG 只有指定port和/或rmiport屬性時,JMX服務器才啓動。如果要修改port參數(不使用缺省的8000端口),必須要修改reporting/jsp目錄下的controlpanel.jsp文件,然後再重新創建和發佈CruiseControl的Web應用;也可以直接修改Tomcat/webapps/cruisecontrol目錄下的controlpanel.jsp頁面。 CruiseControl的Web界面 在瀏覽器地址欄輸入:http://BuildServer-IP:9000/cruisecontrol/,可以訪問CruiseControl的Web應用,如下圖所示: 在左側區域,按時間順序列出最新Build結果的連接。如果Build結果超過10個,左側區域只顯示10個連接,其餘的Build結果可以在下面的下拉框中找到。上圖中因爲Build結果少於10個,所以下拉框是空的。 當點擊右上角的Control Panel按鈕時,如果出現錯誤,則是因爲沒有使用CruiseControl的JMX支持。要啓動JMX支持,請看下節內容。 使用JMX控制檯 要使用CruiseControl的JMX控制檯很簡單,只需在啓動cruisecontrol時指定JMX Server的Http Controller端口即可:cruisecontrol -port 8000。 進入CruiseControl的Web應用界面,點擊右上角的Control Panel按鈕,則出現CruiseControl的"JMX Control Panel"。 可以通過JMX控制面板在運行時修改配置,而不需要重啓CruiseControl。點擊CruiseControl Project MBean,嘗試它的管理功能。 例如,可以修改MBean的"BuildInterval"屬性,來更改項目構建的時間間隔;修改ConfigFileName,則可以更改CruiseControl的配置文件;點擊MBean的build操作"invoke"按鈕,則可以強制啓動項目構建任務。 持續集成資源 1. 持續集成:http://www.martinfowler.com/articles/continuousIntegration.html 2. AntHill:http://www.urbancode.com/projects/anthill/ 3. CruiseControl:http://cruisecontrol.sourceforge.net/ 4. CVSNT:http://www.cvsnt.org/ 5. WinCVS中文版:http://www.8848software.com/wincvs/ 6. Driving On CruiseControl Part1: http://www.javaranch.com/journal/200409/DrivingOnCruiseControl_Part1.html 7. Driving On CruiseControl Part2: http://www.javaranch.com/journal/200410/DrivingOnCruiseControl_Part2.html 8. Scheduled Builds:http://www.pragmaticprogrammer.com/starter_kit/au/scheduled.pdf Java代碼規範檢查工具很多,CheckStyle是其中最有名的,它的Eclipse插件,使用非常方便。我在最近的項目中,之所以選擇JCSC,是因爲JCSC不但可以檢查代碼規範,而且給出了NCSS(Non Commenting Source Statements)和CCN(Cyclomatic Complexity Number),前者近似等於Java的有效代碼行,後者則用於評價類方法的複雜度。 下面的安裝配置延續我的Blog,CruiseControl:持續集成工具的例子。 安裝JCSC 1、從SourceForge下載JCSC.zip 2、將JCSC.zip解壓到D:/BuildServer目錄 3、添加JCSC_HOME系統環境變量,本例中爲D:/BuildServer/jcsc 4、添加JCSC_HOME/bin到系統路徑 配置ANT 1、把JCSC_HOME/jcsc/lib的jar文件複製到/ANT_HOME/lib 配置CruiseControl 1、把JCSC_HOME/lib的jar文件複製到DEFAULT_CCDIR/main/lib 2、修改cruisecontrol.bat,在cruisecontrol.jar之前添加%LIBDIR%/JCSC.jar,在類路徑後面添加%LIBDIR%/xercesImpl.jar 3、複製/JCSC_HOME/html/xml/xsl/cruisecontrol/jcsc.xsl文件到TOMCAT_HOME//webapps/cruisecontrol/xsl目錄 4、修改TOMCAT_HOME//webapps/cruisecontrol/xsl/jcsc.xsl文件,把JCSC Details的鏈接改成"/cruisecontrol/jcsc/index.html" 5、在TOMCAT_HOME/webapps/cruisecontrol/buildresults.jsp頁面中添加 6、在webapps/cruisecontrol目錄下創建jcsc目錄 7、複製JCSC_HOME/html/xml目錄下的xsl子目錄和index.html文件到webapps/cruisecontrol/jcsc目錄 8、複製JCSC_HOME/html/web/jcsc-result/rules.jcsc.xml文件到webapps/cruisecontrol/jcsc目錄 9、把JCSC生成的overview.xml合併到CruiseControl的log.xml文件。修改CruiseControl的config.xml文件,如 <log dir="../logs/frameworkProject"> <merge dir="../../../workingCopy/frameworkProject/reports/junit/data" /> <merge file="D:/BuildServer/tomcat-4.1.31/webapps/cruisecontrol/jcsc/overview.xml" /> </log> 修改ANT的構建腳本build.xml 1、添加JCSC屬性
   <!-- jcsc home config -->
    <property name="jcsc.home" value="D:/BuildServer/jcsc" />
    <property name="jcsc.log.dir" value="D:/BuildServer/tomcat-4.1.31/webapps/cruisecontrol/jcsc" />
    <property name="jcsc.rules.dir" value="D:/BuildServer/tomcat-4.1.31/webapps/cruisecontrol/jcsc/rules.jcsc.xml" />
2、定義JCSC的ANT Task
<taskdef name="jcsc" classname="rj.tools.jcsc.ant.JCSCTask" />
3、<target name="clean">中添加刪除JCSC日誌文件的任務
<delete failοnerrοr="false">
        <fileset dir="${jcsc.log.dir}" includes="*.xml" excludes="xsl,rules.jcsc.xml,index.html" />
</delete> 4、添加JCSC Target
<target name="jcsc">
  <jcsc rules="${jcsc.rules.dir}" destdir="${jcsc.log.dir}">
   <fileset dir="${src.main}" includes="**/*.java" />
  </jcsc>
 </target>
5、調用JCSC Task
<target name="all" depends="clean, jar, test, coverage.report, jcsc" />
使用Rules Editor修改Rules文件 1、運行JCSC_HOME/bin/ruleseditor.bat命令,使用Rules Editor編輯Rules定義文件,可以編輯Open Brace'{' On New Line,Class/I-Face Header等選項 2、也可以直接修改rules.jcsc.xml文件 集成在CruiseControl的JCSC報告如下圖所示。 在htmlmail郵件中集成JCSC報告 要在CruiseControl的htmlmail郵件中集成JCSC報告,需要修改CruiseControl的代碼。在HTMLEmailPublisher類的String[] xslFileNames變量中加入jcsc.xsl,即可在htmlmail中包含JCSC報告的概要部分。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章