基於 CruiseControl 和 Rational 統一變更管理實現的軟體開發中的自動化持續構建

myattitude發表於2009-12-25
轉自:http://www.ibm.com/developerworks/cn/rational/r-cn-cruisecontrolucm/
本文介紹了持續構建工具 CruiseControl 和 IBM Rational 統一變更管理整合的解決方案。通過本文中的解決方案,可以儘早的發現和規避程式碼中存在的風險,遵守統一的流程及時獲取可釋出的軟體,確保敏捷開發的速度和質量。

統一變更管理系統中持續整合的必要性

使用 IBM Rational ClearCase 和 IBM Rational ClearQuest 實現的統一變更管理軟體將配置管理和變更管理緊密結合起來,尤其針對大中型專案,實現軟體開發生命週期的流程控制和管理。在這個過程中,面向變更所做的代 碼在開發流上被不斷的檢入和交付到整合流。可能在交付前,開發人員已經在個人開發流上對程式碼進行過編譯和單元測試。然而由於在交付過程中可能發生的程式碼衝 突和歸併,或者由於構建環境改變,導致整合流上的構建和測試失敗。為了儘早發現和規避交付後產生的風險,加快構建和釋出的速度,程式碼需要不斷被整合,所以 持續整合構建工具是必不可少的。同時為了減少在構建過程中人工干預所帶來的錯誤,對所有釋出遵守統一的構建流程,我們希望程式構建工具儘可能做到自動化。

CruiseControl 正是這樣一個提供了自動化的可持續整合和構建流程管理的工具。CruiseControl 是基於 Ant 技術實現的,它實現的 plug-ins 提供了對不同的原始碼管理工具和構建工具的整合,並且實現了構建結果 email 通知和構建 artifacts 統一 web 介面管理。此外,CruiseControl 是 Java 語言實現的開放原始碼,所以使用者可以通過修改程式碼或者安插指令碼實現構建過程個性化。

本文主要介紹了 CruiseControl 和基於 IBM Rational ClearCase 和 ClearQuest 實現的統一變更管理的整合方案,通過個性化的指令碼將 CruiseControl 融入軟體生命週期管理,實現整個開發流程的自動化。

兩種構建模式 -- 單元構建和每日構建

基於 IBM Rational ClearCase 和 ClearQuest 實現的統一變更管理主要應用於大中型團隊專案。為了儘早發現交付中程式碼歸併產生的問題,頻繁的交付和整合是關鍵。對於大中型專案,如果每人每天都進行一次 交付,為了儘可能快速發現問題並且縮小問題範圍,整合構建工具需要儘快對每次交付進行整合構建。然而,一般的專案可能需要幾個小時完成構建。為了縮短構建 時間同時儘可能發現問題,這裡引入了單元構建和每日構建的概念。

單元構建

為了達到儘早發現問題的目的,我們設計了單元構建。單元構建是基於前一次成功構建,僅對修改的原始碼進行編譯和單元測試的構建過程。 CruiseControl 提供的與 ClearCase 整合的功能可以監控 UCM 專案的整合流,當基於變更請求的程式碼被交付到整合流,新的元素版本在流上被建立,CruiseControl 這時啟動單元構建程式。這個構建可以採用增量編譯,目的在於迅速發現被交付的程式碼與整合流上的程式碼歸併後是否存在錯誤。當然有些問題只有在完全編譯中才能 被發現,但是考慮到這種問題如果不是經常發生,而且為了達到短時間完成單元構建,然後可以對其他被交付的程式碼進行檢查的目的,我們可以將完全構建發生的問 題留到每日構建中解決。此外,為了儘早發現整合的程式碼中存在的問題,也可以在構建指令碼中加入基本的自動測試指令碼。指令碼中的任何測試用例的執行失敗都會直接 導致單元構建失敗。


圖 1. 持續整合中單元構建的典型流程
持續整合中單元構建的典型流程

每日構建

不管是使用敏捷開發還是瀑布開發模式的專案,最好每天至少完成一次完全構建。和單元構建相比,每天進行的完全構建產生可以用來測試和釋出的 artifacts,並且在統一變更管理系統中建立和維護基線,記錄當前構建是否成功。通過基線,開發人員可以回溯專案的歷史版本重新建構歷史釋出,也可 以重構失敗構建的程式碼環境來分析和解決問題。和單元構建一樣,在構建 artifacts 產生後,也可以在構建指令碼中加入基本的自動測試。如果自動測試中的任何測試用例執行失敗,那麼每日構建也標記為失敗。由於每日構建是完全構建,並且呼叫的 測試用例可能也比單元構建多,所以需要較長時間完成。為了不佔用白天的伺服器資源,我們可以設定在晚上的某一時間啟動每日構建。


圖 2. 每日持續整合構建的典型流程
每日持續整合構建的典型流程

在 CruiseControl 中實現與 UCM 整合的持續整合構建

通過配置 CruiseControl 安裝目錄下的檔案 config.xml,可以實現專案的持續整合構建。上一章節介紹了單元構建和整合構建的典型構建流程,在這一章節我們詳細介紹如果在 CruiseControl 中通過配置 XML 元素和屬性實現這兩種流程。

在 CruiseContrl 與 UCM 整合環境實現單元構建

首先設定監控任務,透過事先建立的整合檢視監控整合流上是否有新的交付版本,決定是否啟動單元構建。在下面的示例程式碼中 schedule 任務每 120 秒檢查一次,查詢整合流上是否有新的版本,然後執行單元構建指令碼 cc-build-unit.xml。在所有新的版本建立後等待 300 秒啟動單元構建,這樣做的目的是防止單元構建在交付的途中(部分程式碼被檢入的時候)就被啟動。


清單 1. 配置監控任務
<!-- Defines where cruise looks for changes, to decide whether to run the build --&gt

viewPath="C:/TestProject_int_view/Test.CompVOB"
contributors="true"/>


<!-- Configures the actual build loop, how often and which build file/target --&gt

buildfile="cc-build-unit.xml"
target="build">





接下來的任務是在檔案 cc-build-unit.xml 中配置的。首先更新構建用的整合檢視,裝入整合流上最新的程式碼版本。


清單 2. 更新構建區域原始碼
 








程式碼更新後啟動專案的構建指令碼,對剛才交付的程式碼進行增量編譯和測試


清單 3. 啟動構建指令碼


編譯和測試結束後,指令碼 cc-build-unit.xml 的任務也都完成。單元構建通過 config.xml 中的 任務將編譯和測試產生的日誌檔案合併到 CruiseControl 為本次構建產生的日誌檔案,通過 web 控制檯釋出。


清單 4. 合併單元構建指令碼的日誌檔案和 CruiseControl 的日誌檔案





此外,為了將構建結果及時通知給交付程式碼的開發人員以及其他專案相關人員,可以通過 email 的方式,將構建結果和日誌內嵌到 email 中通知專案組成員。這裡 子元素定製在構建失敗後,除了進行程式碼交付的可發人員,其他人是否收到 email 通知。


清單 5. 通過 email 通知構建結果
<!-- Publishers are run *after* a build completes --&gt

buildresultsurl="http://build-server:8080/cruisecontrol/buildresults/${project.name}"
mailhost="mail-server"
returnaddress="CruiseControl@build-server "
returnname="CruiseControl"
subjectprefix="[CruiseControl]"
xsldir="webapps/cruisecontrol/xsl"
css="webapps/cruisecontrol/css/cruisecontrol.css"
skipusers="false">





在 CruiseContrl 與 UCM 整合環境實現每日構建

與上一章節介紹的單元構建不同,每日構建是每天定時啟動的。如果在規定的啟動時間之前整合流上有程式碼交付,CruiseControl 啟動構建。下面的設定在晚上 9 點啟動任務,如果有新的版本在整合流 TestProject_Integration 上建立,CruiseControl 執行每日構建指令碼 cc-build-nightly.xml。


清單 6. 配置定時啟動任務
 <!-- Defines where cruise looks for changes, to decide whether to run the build --&gt

viewPath="C:/TestProject_int_view/Test.CompVOB"
contributors="true"/>


<!-- Configures the actual build loop, how often and which build file/target --&gt

buildfile="cc-build-nightly.xml"
target="build"
time="2100">






接下來的構建任務是在 cc-build-nightly.xml 中完成的。每日構建中產生的 artifacts 可以用來發布給測試團隊和客戶,所以在執行構建的時候需要更嚴格。為了確保構建區域程式碼的穩定和乾淨,我們需要在指令碼中給整合流加鎖,清空構建區域的所有 檔案,重新裝載整合流上的最新程式碼到構建區域。


清單 7. 清空和裝載構建區域原始碼





















這之後和單元構建一樣,執行清單 3 中的構建指令碼進行完全編譯和自動測試。結束後返回到 config.xml,和清單 4 一樣,將編譯和測試產生的日誌檔案合併到 CruiseControl 日誌檔案,通過 web 控制檯釋出。

不管 cc-build-nightly.xml 執行的編譯和測試是否成功,都需要在整合流上建立基線。通過基線可以重建構建的程式碼環境,便於以後對成功的構建進行重構,或者對失敗的構建進行除錯。這個任務在 config.xml 的 任務中完成。


清單 8. 建立構建成功後的基線


buildfile="cc-build-nightly.xml"
target="make-success-baseline">






在 cc-build-nightly.xml 中加入 make-success-baseline 任務:


清單 9. 加入 make-success-baseline 任務










這裡我們假設 ClearCase 專案使用的 projectname_basename_date 格式的基線模板,所以上面的建立基線操作只需要輸入 basename 部分就夠了。

對於構建成功後建立的基線,我們用 ${label} 作為基線的 basename。這個變數是 CruiseControl 提供的對成功構建的標識,預設的第一次成功構建的標識是 build.1,專案每次構建成功後”.”後面的數字依次加 1。也可以通過 修改構建標識的格式。在這裡生成的基線名稱是 TestProject_build.1_20090724。

如果構建失敗,我們可以使用不同的 basename 建立失敗的基線。


清單 10. 建立構建失敗後的基線


buildfile="cc-build-nightly.xml"
target="make-failed-baseline">






在 cc-build-nightly.xml 中加入 make-failed-baseline 目標:


清單 11. 加入 make-failed-baseline 目標









CruiseControl 為每個產品的每個構建建立單獨的目錄,用於釋出構建產生的 aritfacts。測試人員通過 web 控制檯可以下載 build artifacts 用於測試,釋出經理可以將這些 artifacts 打包給客戶。在構建成功後,使用 將構建產生的 aritifacts 拷貝到 CruiseControl 提供的釋出目錄。


清單 12. 釋出構建產生的 artifacts


dir="C:/TestProject_int_view/artifacts"
dest="artifacts/${project.name}" />



此外,在構建開始整合流被加鎖,現在構建結束,我們還要對整合流解鎖。這個工作也在 config.xml 的 部分中完成。


清單 13. 對整合流解鎖

buildfile="cc-build-nightly.xml"
target="unlock-stream">




在 cc-build-nightly.xml 中加入 unlock-stream 目標:


清單 14. 加入 unlock-stream 目標
 





通過 CruiseControl 和 UCM 整合的功能進行進一步優化

ClearCase 和 ClearQuest 本身都提供對 Perl 指令碼語言的支援,CruiseControl 是基於 Ant 實現的,通過 Ant 也很容易可以執行構建伺服器上和隨 ClearCase 安裝的 ccperl 編譯器,通過呼叫 Perl 指令碼,可以在 CruiseControl 中完成任何對 UCM 系統的操作。下面舉兩個具體的例子。

在單元構建產生構建目標加速構建

前面的章節提到在單元構建中採用了增量編譯和自動測試。為近一步縮短時間加速構建完成,我們可以根據構建中修改的程式碼所屬的模組進行部分模組編譯,然後選擇相關測試用例進行測試。

為達到這一目的,首先構建指令碼和自動測試指令碼需要支援模組化編譯和測試,這裡我們對指令碼編寫不作具體的討論。我們需要解決的是如何在 CruiseControl 中得到本次構建中哪些程式碼被修改,從而產生構建目標。

首先在 cc-build-unit.xml 更新構建區域原始碼(清單 2)後,啟動構建之前,插入下面的程式碼呼叫 Perl 指令碼生成構建目標。


清單 15. 生成構建目標
 



這裡 ucmlastbuild 變數是 CruiseControl 提供的,代表前一次成功構建的發生時間,格式是 dd-MMMM-yyyy.HH:mm:ss。根據這個時間,我們可以在指令碼 getBuildTargetFromCC.pl 中利用 ClearCase lshistory 命令得到本次構建中哪些檔案被修改,產生構建目標。


清單 16. 產生本次構建所有修改檔案列表
 my $full_list = `cleartool lshist -branch $cc.stream -r -nco -fmt 
"%o~#~%n\\n" -since $ucmlastbuild $cc.viewroot/test.CompVOB`;

my @lines = split(/\n/, $full_list);
foreach my $line (@lines)
{
my ($type, $version) = split(/~#~/, $line);

// Not consider operation like mkbranch, rmbranch or rmver
if ($type ne "mkbranch" && $type ne "rmbranch" && $type ne "rmver")
{
push @change_list, $version;
}
}
...

構建成功後在 ClearQuest 資料庫中記錄構建資訊

統一變更管理系統中,ClearQuest 資料庫中維護變更請求的詳細資訊。通過 CruiseControl 對 Perl 指令碼的呼叫,可以自動更新某一變更請求是在哪個構建中修復的。

假設在 ClearQuest schema 中為變更請求加入 FixedInBuild 屬性。我們可以通過 ClearQuest 提供的 Perl API 將 CruiseControl 產生的構建標識加入到被交付的變更請求的 FixedInBuild 屬性。

首先在 cc-build-nightly.xml 的目標 make-success-baseline 建立基線(清單 8)成功後加入下面的程式碼 :


清單 17. 在 ClearQuest 資料庫中記錄構建資訊




在 add_build_to_cq.pl 中通過 ClearCase diffbl 命令比較本次構建和前一次構建建立的基線的區別,得到本次構建包含的被交付變更請求,然後將構建標識 ${label} 更新到變更請求的 FixedInBuild 屬性。


清單 18. 更新變更請求的 FixedInBuild 屬性
// Get the baseline created by CruiseControl, which is the latest baseline 
// on integration stream
my $baseline = `cleartool desc -fmt "%[latest_bls]p" stream:$cc.stream`;

// Get activities contained in the baseline, the list is same as the ChangeRequests
// delivered in the build
my $activities = `cleartool diffbl -activities -predecessor $baseline;
@activities = split(/\n/,$activities);

// Add build label (build.1) to CR’s FixedInBuild field
my $session = CQSession::Build();
foreach my $CR (@activityset)
{
my $CR_entity = $session->GetEntityById("ChangeRequest", $CR);
$session->EditEntity($CR_entity, "Modify");
$CR_entity->SetFieldValue("FixedInBuild", $label);
$CR_entity ->Validate();
$CR_entity ->Commit();

總結

本文介紹了通過對指令碼的開發,將持續整合工具 CruiseControl 和統一變更管理系統 ClearCase/ClearQuest 相結合,建立一個有效的持續整合環境的全過程。通過在軟體開發生命週期管理中加入自動構建和釋出以及資訊反饋,為實現敏捷開發提供基礎,確保敏捷開發的速 度和質量。在現實環境中,讀者可以結合自己的配置管理系統和專案需要,對配置檔案和指令碼進行定製,實現滿足專案需求的持續整合系統。

}

上面只是介紹了兩個典型應用,通過 CruiseControl 對指令碼的呼叫,可以將構建的很多相關資訊加入到 UCM 系統,通過對變更請求生命週期的管理實現開發流程的自動,避免人工干預帶來的錯誤。同時對基於同一程式碼庫的不同專案提供統一的構建流程管理,加速釋出速 度。

 

最後,和單元構建一樣,在 config.xml 通過 email 的形式可以快速通知相關開發人員構建結果。這個部分通過在 中直接呼叫清單 5 種定義的 實現。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14780914/viewspace-623551/,如需轉載,請註明出處,否則將追究法律責任。

相關文章