【編者的話】這是持續內建系列的第二篇,在本文中,作者介紹了CI流程的具體實作。
我們還讨論了CI落地到開發流程最常用的一些方式,最終能夠帶來軟體品質上的提高,更快的市場傳遞,更快的回報周期以及更低的開發成本。
如果你還沒有讀過前面一篇文章的話,不妨在繼續閱讀本文之前先翻閱一下!
在本文中,我們會介紹到一些工具,它們将有助于為組織實作一個強大并有價值的CI流程。
實作一個CI流程的唯一必要條件便是得有一個自動建構系統。
然而,實際上,除了自動建構系統外,安裝和配置一個“CI伺服器”也是相當有幫助的。
CI伺服器會扮演核心大腦的角色在幕後工作,将各種行業标準的實踐無縫整合到CI流程的實施中。
下圖展示了一個典型的CI工作流。如圖所示,它涉及了6個階段,從簽入代碼開始一直到最後,向組織裡的不同人群提供該次簽入的回報為止。

通常,當開發者将代碼簽入到源碼倉庫時就會發起一個CI流程。
CI流程的工作流也可以通過其他方式觸發,針對于開發團隊而言,一般來說以下方法均可選用。
手動 —— 無論是通過CI伺服器的管理界面還是腳本,使用者可以手工執行CI工作流
計劃任務 —— 預配置好的計劃,例如一次淩晨的建構
跟蹤觸發式 —— 在每次送出到源碼版本管理系統時觸發
淩晨的建構一般需要針對代碼執行更大規模的檢查,并且花費更長時間來完成檢測。
作為整個流程裡的第二步,CI伺服器會負責從源碼管理拉取最新的代碼。這可以借助poll或者push機制實作。
使用poll機制的話,該CI伺服器會配置一個源碼管理伺服器的位置,以及它的安全證書。它會根據一個時間間隔定期地輪詢指定位置,以檢測是否有發生任何新的簽入以及代碼變更。一旦檢測到有變更,它會從源碼管理伺服器下載下傳代碼最新的副本到本地磁盤。
使用push機制的話,源碼管理系統會配置一個'鈎子'指到CI伺服器。當開發人員送出了一個變更到倉庫時,之前配置的鈎子将會被調起,而它會讓CI伺服器知道,這裡發生了一次變更。
源代碼一般是自包含建構的,即CI流程所需的建構腳本是放在源碼倉庫裡的。正如在之前的步驟裡詳細介紹的那樣,一旦最新的代碼被拉取下來,一個捆綁好的腳本将會被用來觸發該次建構。
在CI流程的這個階段裡,單元測試和內建測試将會被執行。一般來說,這些測試也會被打包到代碼裡。
針對基于Java ™實作的系統而言,這些測試會通過一個像JUnit這樣的測試架構來執行,進而可以輕松模拟它們的一些測試依賴。
某些程式設計技術可能有它們自己的測試運作架構,Spring的Spring Junit Runner,Java EE的Arquillian等。
在CI伺服器上運作測試主要有下面這些好處:
你曾經有沒有遇到過這樣的場景,這些測試在一台機器上是通過的,但是在其他機器上卻失敗了?通過在一台中央伺服器上執行這些測試,我們可以消除一些測試環境方面的問題
針對每一次變更都會立即觸發執行測試,而且如果有任何新的代碼變更打破了預期的行為的話,你能夠馬上知道
大多數團隊都是并行地在開發着許多功能,甚至可能一些團隊成員也是分布在全球各地。每當開發人員送出代碼到倉庫時,任何故障都可以被識别出來并且立即修複。
在CI流程的最後,隻可能存在兩種結果的其中一種 —— 要麼建構和測試失敗了,要麼通過了。
每一次簽入都會被驗證并且確定它不會破壞現有的代碼。代碼在它被合并到主幹分支後不久會被建構和測試。這将可以降低主幹代碼崩潰的頻次。
一般來說,CI伺服器會配置成在遇到故障時發送郵件(發給團隊裡的每一個人或者僅僅單獨抄送負責上一次簽入的相關人員)。通過這種方式,可以快速知曉故障并且盡快采取更正措施。
大多數CI伺服器還會突出展示最近一些建構的狀态而且最近幾次建構的狀态還會用紅-綠-琥珀色訓示燈來标明。舉個例子,Jenkins,使用的是如下訓示燈來顯示建構的情況。
前面一節着重講述了CI的基本工作流。然而,大多數組織也會根據自己的優勢将它用于更多的用途。CI伺服器可以通過安裝各種"插件"來拓展行為,進而實作功能上的擴充。下面介紹的是一些最常見的擴充。
任何引入到軟體裡的變更将導緻系統複雜性的提高以及混亂程度的加深。系統的混亂程度被稱為“技術債”。每當新代碼被引入到系統時,技術債就會相應增加。如果技術債長期不受重視的話,得到控制權的可能性将變得越來越渺茫,畢竟越來越多的功能在緊迫的期限内堆積過來。而這将會對軟體的生産力和可維護性産生負面影響。
疊代開發方法,将測試的執行自動化,以及使用CI來監控每一次簽入的技術債,這些是保證技術債在可控範圍内的不二法門。
我們應當使用一些工具,比如SonarQube,一個分辨代碼品質和跟蹤技術債的開源平台。它可以輕松地內建到任何CI伺服器,并為使用者提供團隊技術債實時資料的展示。
它做的也不僅僅隻是衡量技術債。它衡量并覆寫了代碼品質的7個次元:
SonarQube在一個友好的web界面上展示它的分析結果。這使得它成為一款非常實用的工具,不僅僅是針對開發人員,還包括管理和其他相關的非技術人員。
引申閱讀請轉到:
<a href="http://softwareyoga.com/managing-technical-debt/">Managing Technical Debt</a>
<a href="https://www.sonarqube.org/">Sonarqube</a>
<a href="https://www.codacy.com/">Codacy</a>
對于開發人員而言,引入CI在另外一個重要方面同樣有價值 —— 它可以用于衡量代碼品質 —— 語義,以及一些常見的反模式。
靜态代碼分析工具可以充當CI流程的一部分,以洞察代碼的健康狀況。曆史資料也可以存儲起來,進而提供一個時間段内代碼品質的衡量。使用者可以在兩個送出之間列出比較,以确定每個送出引入的債務度量。
許多現有的工具可以對代碼做靜态分析并且計算出各種度量代碼品質的名額。這些工具可以并入到持續內建伺服器然後自動執行。
一些更加常用的工具有:
Checkstyle
Findbugs
Sonar
正如在前面的文章裡介紹的那樣,開發人員工作在功能分支上,并且會盡可能多地送出代碼。
我們可以在持續內建伺服器裡使用代碼分析工具(例如Sonar)來執行自動代碼審查。随後每個開發者需要負責解決在他們的送出裡生成的評論意見。
自動代碼審查是基于一組預定義好的規則,并且是一個查找潛在技術問題的好辦法。這些規則可以從所有主要的CI供應商處下載下傳,并适用于大多數主流程式設計語言。
一旦自動審查的評論意見提出的問題被修複了,CI伺服器會随即發起一個人工代碼審查,揪出那些自動審查無法找出的問題,即驗證業務需求,架構問題,代碼是否可讀,以及是否易于擴充。
CI伺服器也可以配置成,如果某些人沒有審查代碼便阻止對主幹分支的任何送出。最常見的做法是每個合并到主幹分支的送出至少要有兩個審查人員(reviewer)。在基于Java™的項目裡,針對此用途最常用的工具是Gerrit。
如果要在CI伺服器上運作使用者的UI測試,那麼他必須得依賴無界面測試,因為沒有浏覽器的顯示界面來啟動。無界面測試意味着在沒有圖形使用者界面的情況下運作UI測試。這樣的測試需要一個無界面浏覽器,它和市面上流行的web浏覽器類似,但它是通過一個指令行接口執行的,并且擁有一個UI元素的記憶體模型。該記憶體模型用來模拟和UI的互動,比如在UI上一個按鈕的一次點選,會被模拟成記憶體模型對象的一個行為。
市面上流行的測試工具,比如Selenium可以被用來做無界面測試。像PhantomJS這樣的無界面浏覽器也被廣泛使用。通過在建構裡引入這些測試,CI伺服器将能夠驗證UI方面的故障。
CI伺服器的安裝方式有三種:
單機
托管
私有雲
單機版的CI伺服器安裝即是在一台單個主機上完成。這通常是用于小型項目或者小于10個研發的團隊。
托管的CI伺服器可以在公有雲平台上看到,一般是根據訂閱計價。往往這些是和CI伺服器可以通路的雲端源碼管理系統緊密結合在一起的。這一般被那些不想維持和運維CI基礎設施的企業所采納。對于中型團隊來說,這也是一個非常可行的上手CI的選擇。
一些大型企業以及那些想要完全掌控及安全使用他們自己的基礎設施的組織,選擇的則是私有雲的部署方式。一般來說,他們會配置一組高性能的伺服器用來運作多個CI伺服器的用戶端,以支撐數以百計的開發人員簽入其代碼的繁重工作負載。
一些最廣泛使用的CI伺服器有:
Jenkins
Travis CI
TeamCity
CruiseControl
在這篇文章裡,我們已經介紹了如何使用CI伺服器來創造高品質的産品。CI伺服器可以擴充成自動測量許多名額,例如技術債,代碼語義,測試覆寫率等。
簽入代碼時代碼品質的即時回報確定故障可以更加及時地被發現,進而保證客戶可以獲得一個可靠且正常工作的産品。
将持續內建引入開發過程還有許多其他的好處和出發點。 這裡也有許多其他工具來擴充CI伺服器。靈活軟體開發及DevOps方法與持續內建天然地相輔相成。
那麼,如果你還沒有把持續內建納入到你的開發流程裡的話,現在還為時不晚!
在持續內建系列的下一篇文章裡,我們将介紹到實作CI的一些關鍵模式和反模式。透過這些建議,你将能夠實作适合你所在組織開發目标和政策的最佳流程。
<b>原文釋出時間為:</b>2017-10-15
<b>本文來自雲栖社群合作夥伴Dockerone.io,了解相關資訊可以關注Dockerone.io。</b>
<b></b>
<b>原文标題:</b><b>持續內建(二):CI伺服器 & 工具集</b>