本系列文章包含:
[獨孤九劍]持續內建實踐(一)- 引子
[獨孤九劍]持續內建實踐(二)– MSBuild文法入門
[獨孤九劍]持續內建實踐(三)- Jenkins安裝與配置(Jenkins+MSBuild+GitHub)
1、前言
本文是對用“MSBuild和Jenkins搭建持續內建環境(2)”的解讀,原文中一些設定并不能得到作者所描述的結果,是以下文會結合實際部署對原文稍作修改。
第一眼看上去,Jenkins像是一個專為Java項目準備的持續內建工具:有為Maven項目設計的job,有諸多為Java項目提供的預設插件,更不要說那些用Java寫的插件了。
但Jenkins其實是一個非常靈活的工具,它可以結合各種版本管理系統和建構工具,用來建構任何類型的項目。在這篇文章中,我們會利用它的靈活性,從Mercurial中pull代碼,用MSbuild建構項目。首先,我們需要下載下傳并安裝Jenkins,然後安裝Git和MSBuild插件。【原文中使用的是Mercurial,由于我經常使用Git,是以這裡會更改為對Git的配置】
2、配置Jenkins
從官方網站下載下傳安裝程式。它的Windows安裝包很簡單,會把Jenkins安裝成Windows服務。Jenkins的預設的通路路徑是“localhost:8080”,請確定8080端口不要被其他應用占用。
安裝完畢以後就是裝插件。請點選“系統管理”連結,然後再點選“插件管理”。
在“可用插件”标簽頁可以檢視目前可安裝的插件──你需要有一個能上網的環境,才能看到這一頁的内容。用“過濾框”找到Git Plugin、GitHub Plugin和 MSBuild插件,點選插件名稱前面的複選框,進行安裝【在選擇安裝時,會自動關聯一些必要的插件進行安裝,很友善】。
你可以點選“已安裝”标簽頁,來確定這兩個插件已經被安裝成功了。
在安裝過程中,你可能會看到提示資訊說Jenkins需要重新開機才能完成安裝,請讓它重新開機,等重新開機完成後再通路“已安裝”标簽頁,看看是不是安裝成功。
由于将來使用GitHub,是以隻需要知道一個Code的位址即可,配置很友善。回到“系統管理”這一頁上來,點選“系統設定”,找到“Git”這一部分──如果你找不到“Git”的話,就說明Git插件沒有裝好──點選“Add Git”按鈕之後,你需要給這個Git執行個體起個名字(自己用着越友善越好);還需要輸入Git可執行檔案的安裝路徑,這裡用的是git.exe檔案的所在目錄;
3、建立一個Jenkins Job
點選Jenkins的logo,回到控制台上來,然後點選“建立”連結。你會看到一組job類型,選擇“建構一個自由風格的軟體項目”,給它命名為“CIProjectWebDemo1-RunUnitTests”,點選OK。
下一步是job配置頁面。這一頁有很多配置項,而且大多數都帶有詳細的描述資訊,點選右側的幫助圖示就可以看到。
我們現在隻配置兩部分,一是代碼庫所在位置,二是如何用MSBuild建構項目。
找到“源碼管理”,選擇Git。在“Repository URL”輸入框中輸入”你自己的GitHub中的代碼位址”。然後在Credentials中選擇證書【如果沒有就建立一個,一直預設就行,最開始我沒有選擇證書,在執行Job時,有時會卡在GitHub的通信上,可能和這個有關,網上也有說和https協定有關】。最後在Branch中輸入你想跟蹤的分支名,其他的選項看自己喜好。
接下來到“建構”這部分。點選“增加建構步驟”按鈕後,下拉框中就會出現一系列的step類型以供選擇,其中便包括“Build a Visual Studio project or solution using MSBuild”,如果你沒看到這個選項,就說明MSBuild插件沒有正确安裝。
點選“Build a Visual Studio project or solution using MSBuild”之後,在“MSBuild Build File”輸入框中輸入建構腳本的名字:CIProjectWebDemo1.msbuild。我們想讓Jenkins執行“RunUnitTests”這個Target ,如果你沒有把DefaultTargets屬性設成RunUnitTests的話,可以在“Command Line Arguments”中輸入“/t:RunUnitTests”,其中/t是/target的簡寫。
點選“Save”或“Apply”儲存之後,這個job一旦被觸發,就可以pull代碼下來,編譯項目,執行單元測試【這裡感覺Save的提示很醒目,不知道用的那個UI架構,源碼中有看到引用YUI,沒用過不知是不是這個,有知道的朋友請留言給我,不勝感激】。
我們先來手工觸發一次,看看配置是否正确。先回到“控制台”,這時可以在螢幕中央看到我們的job。點選job名字,然後在左側的連結中找到“Build Now”連結,點選它,Jenkins就會開始執行。
在這組連結的下方有一個“Build History”清單,它顯示的是這個job的所有建構曆史,當第一次建構開始運作的時候,你會在清單中看到一個進度條,同時還有一個小圓球顯示建構狀态。圓球閃爍表示建構正在進行中,它停止閃爍的時候一般會是紅色或藍色,紅色表示建構失敗,藍色表示成功。
如果這個job能夠通路GitHub版本庫,找到了CIProjectWebDemo1.msbuild腳本,“RunUnitTest”執行成功,這個圓球應該會變藍。這時候你也就順利完成了第一個Jenkins建構。如果建構失敗,請點選“Build History”對應的編号檢視詳細資訊,然後點選“Console Output”,就可以看到Jenkins所執行的每一個指令和對應結果,從中可以分析出建構失敗的原因。
4、觸發建構
建構成功以後,下一步要做的就是讓Jenkins檢測版本庫的變化,一旦有代碼送出,Jenkins就要pull代碼并執行建構。有好幾種方法可以做到這一點。
最簡單的就是讓Jenkins定時建構,但是如果在這一段時間内沒有代碼送出,這次建構反而是浪費。
另一種方式是讓Jenkins定時輪詢,看看版本庫中是否有代碼送出。這種方法的缺點是當有了代碼送出以後,Jenkins要等到下一個輪詢周期才能執行建構。當然,你也可以讓Jenkins每分鐘都輪詢一次,盡可能縮短等待時間。但我們還有另一種更優雅的方案──給版本庫中放一個post-commit的鈎子,這樣一旦版本庫接受了新代碼,它都會通知Jenkins,讓它立刻開始建構。【原文是使用Mercurial作為版本管理工具的,是以下面的這種方法,我沒有嘗試,有興趣的朋友可以拜讀原文,嘗試一下】
回到job配置頁面,在“Build Trigger”區域選擇“Poll SCM”,在“Schedule”輸入框中輸入輪詢周期。它采用的文法格式是cron的風格。如果要每5分鐘輪詢一次,就輸入“H/5 * * * *”。你可以點選輸入框右側的幫助按鈕,檢視輪詢周期的文法介紹。
5、建構流水線
Jenkins可以在某個建構成功結束之後啟動其他job。于是就有了建構流水線,它的概念就是一個job成功之後觸發其他job。觸發者叫做上遊job,被觸發者被稱作下遊job。
建構流水線的應用場景有很多:讓耗時較長的測試在單元測試結束之後執行;運作靜态代碼檢查;把建構結果部署到試機環境(staging)或者産品環境中。我們下面來示範一下這個功能,讓Jenkins在建構結束後啟動web伺服器,運作CIProjectWebDemo1這款應用。
我們隻需要做三件事情:
1. CIProjectWebDemo1-RunUnitTests job成功之後觸發一個新job;
2. 把CIProjectWebDemo1-RunUnitTests的建構結果拷貝出來;
3. 啟動web伺服器。
在開始之前,你還需要安裝Copy Artifacts插件。回到Manage Plugins頁面,參考之前安裝Mercurial插件的方法安裝Copy Artifacts。在看到重新開機的提示資訊時重新開機Jenkins。【這一階段要連接配接的源有些是國外的,很有可能被Q,導緻安裝失敗,到時自行FQ即可】
建立新job之前,我們需要告訴CIProjectWebDemo1-RunUnitTests job,讓它把建構産物儲存下來,以供新job使用。回到CIProjectWebDemo1-RunUnitTests job的配置界面,找到“增加建構後操作步驟”,選中“Archive the artifacts”,頁面上就會出現一個文本框:“用于存檔的檔案”。
我們要存檔的目錄有兩份,一份是BuildArtifacts目錄,一份是packages目錄,後者是為了讓我們能夠通路NuGet package。如果要指定某個目錄以及目錄下所有内容,就需要在目錄後面跟一個斜杠和兩個星号。不同的目錄或檔案之間用逗号分割。在這裡我們輸入的是“BuildArtifacts/**”。
現在建立一個新job,起名叫“CIProjectWebDemo1-StartWebServer”【選擇“建構一個自由風格的軟體項目”】。在配置頁面上“建構觸發器”那一節裡選中“Build after other projects are built”,把之前那個job配置成要觸發目前job的項目。
接下來給job添加一個build step,讓這個job所做的第一件事情就是拷貝之前job所儲存的建構産物。這裡要用到“Copy artifacts from another project”這個step(它是由Copy Artifacts插件提供的)。我們隻需要填入CIProjectWebDemo1-RunUnitTests job的名字就可以。
最後還要添加一個build step,讓它啟動web server。這裡用的是“Execute Windows batch command”,我們用Visual Studio提供的Cassini來運作應用。
Cassini可以在“C:\Program Files (x86)\Common Files\microsoft shared\DevServer\10.0\WebDev.WebServer40.EXE”找到【我是全盤搜尋找到的】。運作Cassini很簡單,把web應用存放的路徑作為參數傳給它就行,如果沒有指定端口号的話,它就會使用預設的端口号80。
“Execute Windows batch command”step需要一個可以在BuildArtifacts和packages拷貝後的目錄下執行的指令。我們把下面這個指令複制到“Command”輸入框中:
"C:\Program Files (x86)\Common Files\microsoft shared\DevServer\10.0\WebDev.WebServer40.EXE" /port:9988 /vpath:"BuildArtifacts\_PublishedWebsites\CIProjectWebDemo1"
【上面的指令是我自己測試出來的,原文中的指令無法執行,可能是Cassini版本不一樣】
這個指令可以啟動Cassini,把它指向拷貝過來的應用,然後在9988端口啟動伺服器。
所有的配置都已就緒。試着修改一下代碼然後送出。Jenkins應該能夠監聽到變化,運作CIProjectWebDemo1-RunUnitTests。如果代碼編譯成功,所有測試均以通過,Jenkins應該開始運作CIProjectWebDemo1-StartWebServer job,把CIProjectWebDemo1-RunUnitTests的建構産物拷貝過來,在9988端口啟動Cassini。如果這一切都運作無誤,我們的持續內建系統就搭好了。
6、結尾
此配置的結果是網站拷貝完畢後,啟動Cassini,指定網站目錄,然後這個job就一直處在等待的狀态,我覺得這就到結果了吧,相當于在Jenkins的程序中開啟了一個Web服務,此時在浏覽器中輸入http://localhost:9988/main.aspx(這裡我是用的自己的webFrom網站)就可以通路到你的頁面了。
但是,如果不手動結束這個Job,那麼就會一直執行下去,當下一次被CIProjectWebDemo1-RunUnitTests運作結束的消息啟動,除非在配置裡開啟并發執行,否則将會一直等待上一個程序的執行;而并發執行又會由于端口被占用,導緻Cassini無法啟動,并使其崩潰。。感覺好亂。
作者寫這個例子的目的,可能是為了示範Job鍊吧。
後來想到,如果沒有使用Cassini,而是用其他的web伺服器來啟動網站,可能就不會存在這種問題了。
各位看官,請繼續閱讀 [獨孤九劍]持續內建實踐 - 引子