本文將介紹如何利用 Rational Team Concert(RTC)在敏捷開發過程中進行持續集成。詳細說明了如 何在 RTC 中通過采取一系列的步驟和腳本開發,來保證持續集成過程的連續性和提高整個項目的效率。 同時還闡述了每一步可以利用的工具和最佳實踐,從而使開發過程更加規范化,高效化。
概述
Rational Team Concert(RTC)是 Jazz 產品中最重要的一個,是一個可以任務分解集成,源代碼版 本控制,進行自動構建和報告的工具。Jazz 做為 IBM 下一代的軟件交付平台,為 RTC 提供了更加協作 化,更高效率和無縫鏈接的可擴展框架。RTC 提供了一系列向導,幫助開發團隊,建立自己的開發計劃, 並根據敏捷開發的過程進行迭代的劃分和工作項的跟蹤。RTC 也提供了源代碼的版本控制功能,讓開發人 員進行無縫的代碼交付的同時,還可以和工作項進行綁定。在源代碼控制的基礎上,RTC 提供了自動構建 的工具,從搭建構建服務器,到日常定期的自動構建,都提供了配置模塊。RTC 還提供了豐富的報告體系 ,從工作計劃,工作項,到源代碼,自動構建,都有專業的報告限制,幫忙開發團隊快速了解項目狀態。 下圖 1 展示了 RTC 相關的主要功能。
圖 1. Rational Team Concert 的整體功能概覽
在項目敏捷開發中,選擇好正確的工具,並根據自己的項目進行自動設計定制,把持續集成的實踐經 驗運用到項目中,會加速項目的開發和測試。
在本文中,將詳細介紹如何在 RTC 中進行源代碼管理,版本控制,搭建項目的構建服務器,進行腳本 的定制配置來自動定時構建版本,將工作項,源代碼和構建版本進行自動綁定,在構建版本後進行自動的 單元測試,定制各種要求的構建版本,並且得到構建版本報告。
整個過程是一個項目的持續集成過程,開發人員可以自動快速的得到最新代碼的構建,並且進行檢查 和測試,以便最快的得到用戶的反饋。每天的改動都可以通過快速構建和自動單元測試來保證完整性和基 本正確性,盡可能地開發人員在構建和設計變更上的精力。
第一部分:源代碼管理和版本控制
源代碼管理和版本控制是持續集成的基礎。在新項目的起始階段,項目組首先需要對 stream, workspace 和 component 進行規劃,並在開發過程中進行持續的代碼版本管理。
Component 是項目源代碼存儲的基礎對象。任何一個項目都可以建立一個或多個 component,並允許 隨著項目的演進而不斷完善。但在實際應用中,我們不建議頻繁的進行 component 再劃分,這需要所有 項目組成員進行工作空間的重新加載和代碼整合。因此,合理的 component 劃分在項目初期十分重要。 以下幾點經驗供大家參考:盡可能降低 component 間的依賴;預先考慮代碼組織結構的可擴展性;集中 管理公共代碼,避免重復。此外,依據功能獨立的 Eclipse 工程來劃分 component 也是很好的借鑒,這 種方法與實際開發相結合,有益於提高開發效率。
Stream 是一個或多個 component 的存儲對象,主要用於工作空間內的工作整合。他類似於其他源碼 管理系統中的分支概念,一個 Stream 僅存儲 component 的一個版本,Team 成員通過 stream 來共享代 碼的變更並進行統一的版本控制。因此建議一個相對獨立的 scrum 項目組創建一個單獨的 stream,有益 於降低組間依賴,並降低代碼管理控制的復雜性。當然,項目組內還可以使用多個 Stream 來進行軟件的 多版本管理。注意:RTC 對於 Stream 下的 component 刪除沒有用戶權限管理,因此,項目組成員切忌 隨意操作,在項目組中建議指定一名系統管理員進行此類維護操作。
項目組的每個成員都需要基於 scream 創建自己的私有工作空間,並在工作空間中加載所需要的 component。下圖 2 展示了 RTC 代碼變更提交和共享的原理。
圖 2. RTC 代碼變更提交和共享機制
每個成員擁有自己的 Eclipe 本地 workspace,並在此工作空間上進行開發工作。同時,大家還都各 自擁有私有的 RTC workspace,用於在 RTC 服務器上進行代碼存儲。代碼 checkin 到 RTC 存儲工作空 間時,其他組員不會看到代碼的變更,只有在 deliver 到 Stream 之後才會共享給他人。
在介紹完以上基本概念之後,再向大家介紹一個 RTC 中很重要的概念:Snapshot。它存儲了工作空間 中所有 component 的鏡像。在持續集成過程中,我們可以通過 Snapshot 進行針對特定構建的代碼版本 管理。如圖 3 所示:
圖 3. 構建報告的詳細信息
打開某一個日構建,你會看到關於這個構建的時間,代碼變更,構建引擎等詳細信息。其中,點擊 Snapshot 鏈接,如圖 4 所示:
圖 4. 特定構建的 Snapshot
圖 4 的下半部分展示了此 Snapshot 上所有 component 的鏡像信息。如果你想在一個新的 workspace 中管理這個版本,那麼點擊左上角的 Create a new repository workspace 鏈接,一個全新 的 workspace 就生產了,所有 component 將被自動加載。另外一種方法是通過新 Stream 來進行代碼版 本的管理,點擊 Create a new stream 鏈接,從而生產新的 stream。前者適用於開發成員本人,通過多 個私有 workspace 來達成多版本管理的目的。後者則更適用於整個項目組,或者不同項目組之間通過不 同 stream 來進行代碼的多版本管理。任何 Snapshot 都可以在浏覽構建歷史列表時找到。當然,項目組 也可以脫離 RTC,通過構建腳本進行實時的源碼下載,壓縮並進行代碼的存儲。大家可以根據實際需要選 擇適合的方法。
第二部分:構建服務器和自動構建
在第一部分中,我們了解到每一個 Snapshot 是和一個構建報告關聯在一起的。RTC 提供了專門的功 能來搭建構建服務器,通過簡單的安裝和配置,幫忙開發人員快速搭建起來自己的構建環境。在一個項目 的構建環境中,允許用戶采用不止一個構建引擎和構建腳本來保證提供持續不斷的構建功能。RTC 的構建 引擎是一個可以用於啟動構建腳本,以及收集構建結果的過程。
創建一個新的 RTC 構建首先要求在 RTC 中創建一個構建引擎和一個構建定義。構建引擎是用來定義 采用哪一個構建服務器來運行構建的過程。構建定義則是用來設定編譯哪些模塊的代碼,調用哪個 ANT 文件來啟動編譯,和一些編譯過程中的參數設定。當這些都准備好了,構建對於項目而言,就變成一個簡 單的事情了。
先在 RTC 中新建一個構建引擎,如圖 5 所示。新建一個構建引擎的時候,需要填一些配置,其中 ID 是最重要的,這個既用來標示這個引擎,並且可以把構建服務器和構建定義關聯起來。根據項目所在的 Team Area 進行浏覽選擇後,由於並沒有先創建構建定義,所以右側的構建定義可以先不選擇。等構建定 義創建好後,可以再次編輯構建引擎來進行關聯配置。
圖 5. 創建新的構建引擎
記下了新的構建引擎的 ID,我們就開始創建新的構建定義。選擇新建一個構建定義後,會啟動一個向 導,其中,我們一定要在一開始選擇好 Project Team Area,然後可以選擇新建一個構建定義,還是復制 一個已有的構建定義,並在其基礎之上進行修改。如圖 6 所示,其中 ID 是這個構建定義的標示,可以 選擇用上步創建的構建引擎來支持新的構建定義。
圖 6. 構建定義
在構建定義上,通過指定調用項目代碼中的 ANT 文件,可以啟動整個構建過程。在做完這些初步的配 置後,就可以通過在構建服務器上運行一個 RTC 提供的命令行應用把這個構建服務器啟動起來。這個應 用可以在 RTC 的安裝包中找到,或者在 RTC-BuildSystemToolkit-*.zip 這樣的工具包中解壓得到。命 令是在安裝目錄或者解壓目錄 buildsystem/buildengine/eclipse 下面的 jbe. 運行命令最簡單的一種 方式是:
jbe -repository https://localhost:9443/jazz -engineId default -userId myUser -pass myPass
其中 URL 是 RTC 服務器的連接方式,default 是指構建引擎 ID,後面的兩個參數是用來做構建的用 戶名和密碼。這裡推薦,在 RTC 服務器中,創建一個專門賬戶來進行構建管理。RTC 的構建模式,是構 建服務器,利用這個賬戶,登錄到 RTC 服務器上,把最新的項目代碼拉到自己這裡,再根據本地的環境 ,運行腳本進行構建。
當運行起來這個命令後,可以看到有“Waiting for request”的字樣,證明構建服務器已經正確的連 接到 RTC 服務器上,並且為構建做好准備。
圖 7. 構建服務器狀態
同時,在新建的構建引擎後,可以發現構建引擎的狀態從 waiting 變成了 idle,再次表明 build 服 務器和 RTC 服務器的連接是成功的。通過對構建引擎的狀態監控,也可以知道構建服務器的狀態。
環境准備好了,就可以進行構建了。手動構建是最基本的一種方式。通過在構建定義上,點擊請求構 建,就可以觸發一次構建過程。選擇需要的構建參數,這個過程就會在後台運行。每一個開發人員,做了 任何的代碼改變和提交,都可以觸發新的構建過程,來保證代碼的有效性和正確性。申請一個新的構建的 過程如圖 8、圖 9 所示。
圖 8. 申請一個新的構建
圖 9. 構建申請界面
當構建結束後。RTC 服務器會提供構建結果報告,如圖 3 所示。開發人員可以查詢到這次構建的詳細 信息。整個開發過程中,對代碼進行構建的次數是沒有限制的,通過每次構建,都可以得到當時代碼的編 譯情況,並且可以得到一個可運行的軟件版本。在持續集成中,定時的構建更是必不可少。在構建定義上 ,RTC 支持設置構建計劃來定時自動的觸發一次構建。
圖 10. 定時調用構建定義
第三部分:自動構建測試
開發過程中,不同模塊的單元測試用例常常為不同的開發人員所寫,每個成員都需要保證自己的代碼 改動不會使其他開發人員的單元測試失敗,為了達到這個目標,可以在使用 RTC 進行自動構建的時候, 增加一個構建屬性 report,如圖 9 所示。當需要產生報告的時候,將 report 的值設為 true,這時 RTC 構建引擎在進行自動構建的時候,會通過 ANT 腳本調用 JUnit 對項目的所有單元測試用例自動進行 單元測試,並生成測試報告,這樣就可以在最短的時間內發現因為代碼改動而產生的問題。此外可以在此 基礎上將測試覆蓋率分析工具 EMMA 和靜態代碼分析工具 FindBugs 一起集成起來,方便提高代碼質量。
為了能在 ANT 腳本中調用 EMMA 生成測試覆蓋率報告,需要先將相關的類庫文件 emma.jar、 emma_ant.jar 下載到本地,並在 ANT 腳本中設置相應的路徑並引入 EMMA 任務定義,從而使 ANT 知道 這些類庫的位置。如清單 1 所示:
清單 1. 在 ANT 中引入 EMMA 任務
<path id="emma.lib" >
<pathelement location="${emma.dir}\emma.jar" />
<pathelement location="${emma.dir}\emma_ant.jar" />
</path>
<taskdef resource="emma_ant.properties" classpathref="emma.lib" />
在源代碼編譯完成後,在需要測試的類中注入 EMMA 字節碼。如清單 2.
清單 2. 注入 EMMA 字節碼
<target name="instrument" depends="compile">
<emma enabled="yes">
<instr instrpath="${classes.dir}" destdir="${instr.dir}"
metadatafile="${emma.report.dir}\metadata.emma" merge="true">
</instr>
</emma>
</target>
然後調用 JUnit 任務進行單元測試,在測試前需要設置正確的 jvmarg。如清單 3 所示。
清單 3. 運行測試用例
<target name="test" depends="instrument">
<junit dir="${classes.dir}" printsummary="on" fork="true" >
<classpath refid="classpath" />
<jvmarg value="-Demma.coverage.out.file=${emma.report.dir}\coverage.emma" />
<jvmarg value="-Demma.coverage.out.merge=true" />
<formatter type="xml" />
<batchtest todir="${junit.report.dir}">
<fileset dir="${classes.dir}">
<include name="**/*Test.*" />
</fileset>
</batchtest>
</junit>
</target>
最後生成 EMMA 測試覆蓋率報告,ANT 腳本如清單 4 所示。
清單 4. 生成測試覆蓋率報告
<target name="coverage_report" depends="test">
<emma enabled="true">
<report sourcepath="${src.dir}" encoding="utf-8">
<fileset dir="${emma.report.dir}">
<include name="*.emma" />
</fileset>
<xml outfile="${emma.report.dir}/coverage_report.xml" />
</report>
</emma>
</target>
FindBugs 是一款靜態代碼分析工具,同樣也可以在 ANT 腳本中調用 FindBugs 來生成靜態代碼分析 報告,作為持續集成的一部分。
清單 5. 生成 FindBugs 代碼靜態分析報告
<path id="findbugs.lib" >
<pathelement location="${findbugs.dir}/lib/findbugs-ant.jar" />
</path>
<taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask"
classpathref="findbugs.lib" />
<target name="findbugs" >
<mkdir dir="${findbugs.report.dir}"/>
<findbugs home="${findbugs.dir}" output="xml"
outputFile="${findbugs.report.dir}/findbugs.xml">
<auxClasspath refid="findbugs.classpath" />
<class location="${bin.dir}" />
</findbugs>
</target>
為了方便查閱,可以搭建一個 Hudson 服務器,將 JUnit、EMMA 和 FindBugs 結果通過 Hudson 以 Web 的形式展現出來,利用 Hudson 還可以很方便的了解到整個項目的趨勢。如圖 11 所示。
圖 11. 利用 Hudson 集成展示報告
第四部分:自動報告,保證持續集成過程
前面介紹了 RTC 的很多功能,和利用 ANT 進行自動構建的實踐,為的是保證持續集成的開發過程順 利的進行。開發人員通過查看報告可以及時了解到每次構建的狀態,修正存在的問題,從而保證了整個項 目的開發進度和質量。
在 RTC 中,點擊構建定義,就可以看到利用這個構建定義做出的構建結果。每一次的構建都有一個唯 一的標示就是構建標識,這個標識是每次啟動構建時的時間戳,這樣就可以保證構建標識是唯一的。在一 個構建服務器上,同時只能運行一個構建,這樣就有了構建隊列,也同時保證了構建的唯一性。在構建結 果這裡,可以詳細的檢查到每次構建的狀態,開始的時間,運行的時間等詳細的信息。
圖 12. 構建結果
在每個構建結果上雙擊,可以打開構建的詳細信息,如圖 3 所示。選擇 Logs,就可以看到這次構建 的日志文件,如圖 13 所示。點擊日志文件,就可以查詢到詳細的構建過程信息。
圖 13. 構建日志文件
同樣,在 Hudson 服務器上展示的報告中,點擊每一個詳細的項目,都可以找到具體的錯誤和正確的 信息。這樣的持續集成的過程,幫忙開發人員快速的得到構建,並且為方便的查看報告提供了一個途徑。 同時加快了開發過程,保證了代碼質量。
結論
持續集成是敏捷開發過程中的重要環節,可以幫助項目盡早發現和規避風險,持續提高項目質量。 Rational Team Concert 為在敏捷開發中進行持續集成提供了有力的支持,允許用戶對持續集成過程進行 定制和擴展,本文介紹了使用 RTC 進行持續集成的步驟和方法,希望可以幫助 RTC 用戶在最短的時間內 搭建高效的持續集成系統。