I'm an Infrastructure Specialist at
ThoughtWorks. In my role I
make sure that we are building our software so it can successfully be
deployed to production. In this series of blog posts I hope
to
pass on my top ten tips for using CruiseControl Enterprise
effectively. I'm writing these with the developers or systems
administrators in mind: the people who most often manage
CruiseControl. However, I hope that anybody who is interested
in
Continuous Integration will get something from these articles.
平均規模的Java項目會有很多依賴: 開源的工具和框架, 第三方的庫, 你的項目或組織內部開發的庫...等等等等.
我數了數我目前項目中依賴的(或者可能依賴的 :) ) jar 文件, 有 84 個. 更多的痛苦來自于你管理這些依賴的方式.
讓你的軟件能夠編譯或執行通常比你想象的要困難的多, 如果這些依賴不清楚的話. 加入一個新項目,
然后用一天的時間讓你的代碼從不清楚的代碼或環境依賴中成功編譯真是充滿了痛苦.
讓CruiseControl Enterprise和它的依賴 從 你自己的項目和項目依賴中清楚地分離出來, 是一個很好的主意. 最基本的例子, 可以讓你的CruiseControl Enterprise安裝像下面這樣布局:
|-- cruise
| |-- 2.7.0
| |-- 2.7.1
|-- logs
| |-- blowfish
| |-- scorpion
|-- projects
| |-- blowfish
| |-- scorpion
這樣升級 CruiseControl
Enterprise 應該只是幾分鐘的事. 如果你發現你需要往CCE本身加入額外的庫, 通常這是一個警告信號,
意味著你的項目不能滿足自我依賴. 僅有的例外是當你用自定義的 bootstrapper 或 publisher 等來擴展 CCE
自身的時候.
這里有兩點尤其需要注意: 日志文件和 '.ser' 文件. 日志文件代表了你的項目的歷史,
這就是我為什么一直努力把它們保存在與CruiseControl安裝目錄不同的目錄層次中. 另外, 缺省情況下,
CruiseControl 還把項目的狀態信息持久化到后綴名為 '.ser' 的文件中. 確保升級的時候你保留了它們.
如果你這么做了, 你的項目又不依賴于CCE, 那么就能很容易的升級CCE.
接下來, 考慮一下那些熔入到你的構建工具中的依賴. 有一個常用的模式是把依賴都放到你的 Apache Ant 的 'lib' 目錄中. 這樣做對諸如 Junit
之類一般不會被你的產品代碼依賴的庫沒問題. 但如果你的產品代碼或構建腳本依賴的庫實際上貯存于你的構建工具內部時, 你就有麻煩了. 它今天可能還工作,
但明天就不一定了. 如果你升級了構建工具中你的代碼依賴的那些庫, 有可能你就構建不了以前的代碼了. 這讓事情變得很"有趣",
尤其是當你正試圖通過升級依賴庫解決一個產品中的Bug時. (升級后能構建最新的代碼, 但不能構建以前的代碼)
好消息是, 這很容易解決: 讓你的項目包含自己的依賴. (讓你的構建腳本顯式的引用包含在項目內部的依賴, 而不是隱式的讓構建工具來包含那些依賴). 比如說,
如果你的Ant腳本依賴于Oracle, 而你的項目使用的Ant包含了Oracle的驅動, 那么你的腳本看起來像這樣:
<target name="drop_all_tables">
<sql driver="oracle.jdbc.driver.OracleDriver" userid="user"
password="donttell" url="jdbc:oracle:thin:@localhost:1521:orcl" delimiter=";">
<transaction src="${sql.dir}/drop_all_tables.sql" />
</sql>
</target>
在這個例子中, 對于Oracle驅動的依賴沒有被明確的聲明, Ant 只會從缺省classpath中尋找
"oracle.jdbc.driver.OracleDriver".
第一件要做的事就是把驅動所在的jar文件扔到project內部并設置一個classpath:
lib/
`-- ojdbc14.jar
<path id="buildtime">
<pathelement location="${lib.dir}/ojdbc14.jar"/>
</path>
<target name="drop_all_tables">
<sql driver="oracle.jdbc.driver.OracleDriver" userid="user"
password="donttell" url="jdbc:oracle:thin:@localhost:1521:orcl" delimiter=";" classpathref="buildtime">
<transaction src="${sql.dir}/drop_all_tables.sql" />
</sql>
</target>
注意'sql'元素中這個額外的 'classpathref' 屬性. 這個有用的屬性允許你引用腳本中在別處定義的路徑, 減少了重復代碼.
當你把一個依賴移到項目內部時, 要在可以刪除的時候正式的刪除這個依賴. 在我最近采用這種過程的一個項目中, 我很幸運的能夠以我喜歡的方式進行定期發布.
我修復了trunk中的依賴, 并且幾周后進行了重新檢查. 以前那種依賴于項目外部某些東西的 release branches 沒有被使用.
因此概括的說, 考慮一下你項目的依賴項, 包括那些只是湊巧被滿足的依賴項. 如果你讓那些依賴都很清楚直觀, 我保證你會更少的被你的同事追問為什么他們不能編譯!
如果你有許多工程有相同的依賴, 我希望在后續的文章中會解決一些問題.