目錄html
Jenkins持續集成學習-Windows環境進行.Net開發1
Jenkins持續集成學習-Windows環境進行.Net開發2
Jenkins持續集成學習-Windows環境進行.Net開發3
Jenkins持續集成學習-Windows環境進行.Net開發4
Jenkins持續集成學習-搭建jenkins問題彙總shell
在前面兩篇文章介紹了關於持續集成的完整主流程。windows
在上一篇文章中咱們完成了主流程的持續集成,可是提交代碼仍然須要手動點擊構建,本篇文章就來探究如何作到SVN代碼提交後自動構建。api
在開始以前我須要解決上一篇文章理解有誤的一個問題。
在上一章咱們將單元測試的不穩定錯誤等級設置爲1。跨域
當我添加多個失敗的單元測試時,我發現1次單元測試失敗錯誤等級就會加1,我增長了一共11個失敗的單元測試,所以單元測試失敗返回值爲11。bash
所以上次的邏輯就行不通了,編譯的時候自動建立nuget包,不穩定版本刪除nuget包,這樣只能將錯誤等級設置的很是大。好比int.Max,不然失敗會致使刪除腳本不執行。
所以咱們有兩種選擇:服務器
1. 編譯的時候自動建立nuget包, 單元測試將不穩定的ERRORLEVEL設置的很是大,單元測試失敗均可以認爲是不穩定,而後自動刪除nuget包。 2. 編譯的時候不自動建立nuget包,單元測試經過後再調用腳本建立nuget包。
咱們優化一下使用第二種方法生成nuget包。svn
咱們將項目中自動生成nuget包的勾去除
工具
或者咱們修改csproj
的GeneratePackageOnBuild
節點值,改成false,則編譯的時候也不會自動建立nuget包。
oop
而後咱們修改單元測試ERRORLEVEL,單元測試失敗了就再也不執行後續Build的流程,在單元測試成功時建立Nuget包。
經過nuget pack csproj文件名 -Properties Configuration=Release -OutputDirectory 輸出文件夾
命令建立nuget包
須要加
-Properties Configuration=Release
參數。使用pack建立包的時候會先進行編譯,若沒有指定Release
在默認會生成Debug
版本
須要添加-OutputDirectory XXXX
參數,不然默認會保存到項目的根目錄。
同時咱們刪除了ERRORLEVEL,只要單元測試失敗都算失敗,這樣就不會執行報建立了。
17:53:29 Results (nunit3) saved as TestResult.xml 17:53:29 17:53:29 D:\Program Files (x86)\Jenkins\workspace\unittest>exit 0 17:53:29 [unittest] $ cmd /c call C:\WINDOWS\TEMP\jenkins3052083372263337733.bat 17:53:29 17:53:29 D:\Program Files (x86)\Jenkins\workspace\unittest>E:\開發工具\VS開發工具\VS插件\nuget.exe pack Jenkins.Core/Jenkins.Core.csproj -Properties Configuration=Release -OutputDirectory Jenkins.Core\bin\Release 17:53:29 正在嘗試從「Jenkins.Core.csproj」生成程序包。 17:53:29 MSBuild auto-detection: using msbuild version '15.9.21.664' from 'D:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\bin'. 17:53:31 正在打包「D:\Program Files (x86)\Jenkins\workspace\unittest\Jenkins.Core\bin\Release\net45」中的文件。 17:53:31 警告: NU5115: 未指定 Description。正在使用「Description」。 17:53:31 Successfully created package 'D:\Program Files (x86)\Jenkins\workspace\unittest\Jenkins.Core\bin\Release\Jenkins.Core.0.5.0.nupkg'. 17:53:32 17:53:32 D:\Program Files (x86)\Jenkins\workspace\unittest>exit 0 17:53:33 Recording NUnit tests results 17:53:33 Starting Publish Nuget packages publication 17:53:33 [unittest] $ E:\開發工具\VS開發工具\VS插件\NuGet.exe push Jenkins.Core\bin\Release\Jenkins.Core.0.5.0.nupkg ******** -Source http://127.0.0.1:10080/nuget -NonInteractive 17:53:33 Pushing Jenkins.Core.0.5.0.nupkg to 'http://127.0.0.1:10080/nuget'... 17:53:34 PUT http://127.0.0.1:10080/nuget/ 17:53:35 Created http://127.0.0.1:10080/nuget/ 981ms 17:53:35 Your package was pushed. 17:53:35 Ended Publish Nuget packages publication 17:53:35 [WS-CLEANUP] Deleting project workspace... 17:53:35 [WS-CLEANUP] Skipped based on build state SUCCESS 17:53:35 Finished: SUCCESS
此時流程優化以下
graph LR 編譯程序集 --> 編譯單元測試程序集 編譯單元測試程序集 --> |經過| 執行單元測試 編譯單元測試程序集 --> |不經過| 失敗 執行單元測試 --> |經過| 建立nuget包 建立nuget包 --> 上傳nuget包 執行單元測試 --> |不經過| 失敗 上傳nuget包 --> 清理編譯文件夾 失敗 --> 清理編譯文件夾
SVN自動觸發構建一共有3種方式。
Jenkins定時輪詢觸發是使用Jenkins 輪詢SCM功能定時檢查SVN是否有變動觸發構建。
Jenkins的輪詢SCM的說明上提到該功能須要掃描整個Jenkins工做區並驗證,操做性能要求比較高。咱們依然驗證一下這個功能。
在配置Build Triggers
選項中勾選輪詢SCM,在Schedule輸入 * * * * *
表示每分鐘輪詢一次,即代碼提交後1分鐘觸發構建。
設置完以後咱們提交代碼就會自動構建了。相比手動構建,自動構建左邊菜單欄會顯示輪詢日誌,右邊會顯示由SCM變動啓動,代表是輪詢SCM觸發的構建。
SVN客戶端鉤子觸發是在本地提交的時候執行本地的Post-Commit
鉤子,經過這個鉤子執行腳本使用http請求調用jenkins的遠程構建接口。
在系統配置-管理用戶-用戶-配置
的API TOKEN
點擊生成新的Token按鈕,建立一個token。咱們須要根據這個token來獲取權限。
在項目的配置中修改Build Triggers
,勾選Trigger builds remotely
支持觸發遠程構建。在Authentication Token
輸入一個自定義的串,咱們可使用JENKINS_URL/job/JOB_NAME/build?token=TOKEN_NAME
來遠程構建項目。好比咱們當前項目可使用http://127.0.0.1:8080/job/unittest/build?token=123
遠程構建
graph LR SVN提交代碼 --> 觸發代碼提交後鉤子 觸發代碼提交後鉤子 --> 執行本地腳本
建立一個bat腳本。命名爲post-commit-unittest.bat
,咱們在這個腳本里寫入參數,將真正執行通知的腳本分離出來,這就能夠重用了。
SET CSCRIPT=%windir%\system32\cscript.exe SET VBSCRIPT=F:\Repositories\JenkinsTest\hooks\post-commit-hook-jenkins.vbs SET JENKINS=http://127.0.0.1:8080/ SET JOBNAME="unittest" SET TOKEN="123" REM AUTHORIZATION: Set to "" for anonymous acceess REM AUTHORIZATION: Set to encoded Base64 string, generated from "user_id:api_token" REM found on Jenkins under "user/configure/API token" REM User needs "Job/Read" permission on Jenkins REM AUTHORIZATION=base64(test:1184023ac835f44484f52316235a033db8) SET AUTHORIZATION="dGVzdDoxMTg0MDIzYWM4MzVmNDQ0ODRmNTIzMTYyMzVhMDMzZGI4" "%CSCRIPT%" "%VBSCRIPT%" %JENKINS% %JOBNAME% %TOKEN% %AUTHORIZATION%
SVN調用腳本會傳入3個參數
1. 當前項目的SVN倉庫地址 2. 當前的版本號 3. 事務名稱
這裏暫時不須要用到。
經過CScript.exe調用執行vbs腳本。
CScript.exe是Windows腳本宿主的一個版本,能夠用來從命令行運行腳本。
通知腳本參數說明
1. CSCRIPT:CScript.exe的路徑。 2. VBSCRIPT:同時jenkins的腳本路徑。 3. JENKINS:jenkins服務地址。 4. JOBNAME:項目名稱。 5. TOKEN:項目的Token。 6. AUTHORIZATION:用於受權token。
AUTHORIZATION值爲
base64(user_id:api_token)
在SVN客戶端的設置中找到鉤子腳本,點擊添加。
設置路徑和腳本路徑,注意左下角兩項勾起來。
graph LR 獲取Jenkins-Crumb-->提交build請求
建立一個vbs腳本用於執行通知。
jenkins = WScript.Arguments.Item(0) Wscript.Echo "jenkins="&jenkins jobName = WScript.Arguments.Item(1) Wscript.Echo "token="&token token = WScript.Arguments.Item(2) Wscript.Echo "token="&token authorization = WScript.Arguments.Item(3) Wscript.Echo "authorization="&authorization url = jenkins + "crumbIssuer/api/xml?xpath=concat(//crumbRequestField,"":"",//crumb)" Wscript.Echo "url="&url Set http = CreateObject("MSXML2.ServerXMLHTTP") http.open "GET", url, False http.setRequestHeader "Content-Type", "text/plain;charset=UTF-8" if not authorization = "" then http.setRequestHeader "Authorization", "Basic " + authorization end if http.send crumb = null if http.status = 200 then crumb = split(http.responseText,":") end if Wscript.Echo crumb(0)&"="&crumb(1) url = jenkins + "job/unittest/build?token=" + token Wscript.Echo url Set http = CreateObject("MSXML2.ServerXMLHTTP") http.open "GET", url, False http.setRequestHeader "Content-Type", "text/plain;charset=UTF-8" if not authorization = "" then http.setRequestHeader "Authorization", "Basic " + authorization end if if not isnull(crumb) then http.setRequestHeader crumb(0),crumb(1) end if http.send Wscript.Echo "Status: " & http.status &"Body: " & http.responseText
不一樣項目使用不一樣的post-commit.bat的腳本,腳本中設置JOB_NAME和JOB_TOKEN,不一樣項目最終都是調用上面的這個腳本進行遠程構建。
咱們先獲取到Jenkins-Crumb獲取到防跨域攻擊token。經過向JENKINS_URL/crumbIssuer/api/xml
發送一個post請求,獲取到crumb。
發送的時候咱們須要將
Authorization
加入到http頭部。
將獲取到的Jenkins-Crumb:XXXXX
加入到http頭部,經過發送Get請求調用遠程構建,觸發成功會響應201的狀態碼。
關於遠程調用更詳細的文檔說明能夠查看Remote access API
經過上面的設置SVN客戶端鉤子遠程構建就完成了,在項目中能夠看到遠程構建的標誌。
相比SCM輪詢,客戶端遠程構建實時性更高,因爲是主動通知,所以代碼提交完馬上能夠觸發遠程構建。
服務端鉤子與客戶端鉤子相似,具體區別以下。
客戶端鉤子 | 服務端鉤子 | |
---|---|---|
腳本位置 | 客戶端post-commit鉤子 | 服務端post-commit鉤子 |
配置 | 須要在Build Triggers 配置中勾選Trigger builds remotely ,設置Authentication Token |
須要在Build Triggers 配置中勾選輪詢 SCM |
防跨域攻擊 | 支持,須要獲取防跨域攻擊的token | 支持,須要獲取防跨域攻擊的token |
通知方式 | 經過Remote access API 調用主動構建 |
經過向Subversion Plugin 發送請求主動構建 |
其餘要求 | 無 | 須要安裝Subversion Plugin 插件,同時服務端執行腳本須要一些特殊權限 |
每一個版本庫建立後都會自動生成一些文件夾和文件,hooks文件夾內就是存放了服務器端的鉤子。咱們將咱們須要的鉤子腳本根據命名規則放入hooks文件夾便可。
windows環境鉤子命名規則爲鉤子名.bat或鉤子名.exe,如post-commit.bat
或post-commit.exe
。
詳情能夠查看官方文檔Implementing Repository Hooks
建立服務端鉤子腳本post-commit.bat
。
SET REPOS=%1 SET REV=%2 SET CSCRIPT=%windir%\system32\cscript.exe SET VBSCRIPT=F:\Repositories\JenkinsTest\hooks\post-commit-svn-server.vbs SET SVNLOOK=D:\Program Files\VisualSVN Server\bin\svnlook.exe SET JENKINS=http://127.0.0.1:8080/ REM AUTHORIZATION: Set to "" for anonymous acceess REM AUTHORIZATION: Set to encoded Base64 string, generated from "user_id:api_token" REM found on Jenkins under "user/configure/API token" REM User needs "Job/Read" permission on Jenkins REM AUTHORIZATION=base64(test:1184023ac835f44484f52316235a033db8) SET AUTHORIZATION="dGVzdDoxMTg0MDIzYWM4MzVmNDQ0ODRmNTIzMTYyMzVhMDMzZGI4" "%CSCRIPT%" "%VBSCRIPT%" "%REPOS%" "%2" "%SVNLOOK%" %JENKINS% %AUTHORIZATION%
詳細的鉤子能夠到SVN服務管理上找到管理hooks
同時咱們建立了鉤子腳本放入,SVN鉤子管理就能夠直接讀取到咱們的腳本。
通知腳本參數說明
1. %1:當前項目的SVN倉庫地址。 2. %2:提交後的版本號。 3. CSCRIPT:CScript.exe的路徑。 4. VBSCRIPT:同時jenkins的腳本路徑。 5. SVNLOOK:svnlook.exe的路徑。 6. JENKINS:jenkins服務地址。 7. AUTHORIZATIONN:用於受權token。
svnlook是檢驗Subversion版本庫不一樣方面的命令行工具。
graph LR 獲取SVN版本庫的UUID --> 獲取SVN修改項 獲取SVN修改項 --> 獲取Jenkins-Crumb 獲取Jenkins-Crumb-->提交build請求
建立一個vbs腳本用於執行通知。
repos = WScript.Arguments.Item(0) Wscript.Echo "repos="&repos rev = WScript.Arguments.Item(1) Wscript.Echo "rev="&rev svnlook = WScript.Arguments.Item(2) Wscript.Echo "svnlook="&svnlook jenkins = WScript.Arguments.Item(3) Wscript.Echo "jenkins="&jenkins authorization = WScript.Arguments.Item(4) Wscript.Echo "authorization="&authorization Set shell = WScript.CreateObject("WScript.Shell") Set uuidExec = shell.Exec(svnlook & " uuid " & repos) Do Until uuidExec.StdOut.AtEndOfStream uuid = uuidExec.StdOut.ReadLine() Loop Wscript.Echo "uuid=" & uuid Set changedExec = shell.Exec(svnlook & " changed --revision " & rev & " " & repos) Do Until changedExec.StdOut.AtEndOfStream changed = changed + changedExec.StdOut.ReadLine() + Chr(10) Loop Wscript.Echo "changed=" & changed url = jenkins + "crumbIssuer/api/xml?xpath=concat(//crumbRequestField,"":"",//crumb)" Wscript.Echo "url="&url Set http = CreateObject("MSXML2.ServerXMLHTTP") http.open "GET", url, False http.setRequestHeader "Content-Type", "text/plain;charset=UTF-8" if not authorization = "" then http.setRequestHeader "Authorization", "Basic " + authorization end if http.send crumb = null if http.status = 200 then crumb = split(http.responseText,":") end if Wscript.Echo crumb(0)&"="&crumb(1) url = jenkins + "subversion/" + uuid + "/notifyCommit?rev=" + rev Wscript.Echo url Set http = CreateObject("MSXML2.ServerXMLHTTP") http.open "POST", url, False http.setRequestHeader "Content-Type", "text/plain;charset=UTF-8" if not authorization = "" then http.setRequestHeader "Authorization", "Basic " + authorization end if if not isnull(crumb) then http.setRequestHeader crumb(0),crumb(1) end if http.send changed if http.status <> 200 then Wscript.Echo "Error. HTTP Status: " & http.status & ". Body: " & http.responseText end if
Windows specific post-commit hook示例使用的是
Microsoft.XMLHTTP
調用http請求,可是我本機發送會返回403錯誤,查到一篇msxml3.dll 錯誤 80070005 拒絕訪問換爲MSXML2.ServerXMLHTTP
發送成功。
經過svnlook uuid REPOS-PATH
獲取版本庫的惟一UUID
C:\Users\Dm_ca>"D:\Program Files\VisualSVN Server\bin\svnlook.exe" uuid "F:\Repositories\JenkinsTest" 3f64521c-9849-7c44-a469-468730bce0a2
能夠看到和SVN版本庫的UUID一致
經過svnlook changed --revison REV REPOS-PATH
獲取版本庫某個版本的改變項
C:\Users\Dm_ca>"D:\Program Files\VisualSVN Server\bin\svnlook.exe" changed --revision 50 "F:\Repositories\JenkinsTest" U trunk/JenkinsTest.Core/Jenkins.Core.Test/TestClass.cs
和客戶端獲取Jenkins-Crumb方式同樣。
與客戶端提交build請求不一樣,服務端是向http://jenkins-server/subversion/${UUID}/notifyCommit?rev=$REV
發送一個post請求。
服務端構建會顯示SCM啓動,和jenkins scm不一樣的是,不須要每分鐘定時輪詢,而是經過服務端鉤子觸發任務執行。
SCM輪詢 | 客戶端鉤子 | 服務端鉤子 | |
---|---|---|---|
腳本位置 | 無腳本 | 客戶端post-commit鉤子 | 服務端post-commit鉤子 |
配置 | 須要在Build Triggers 配置中勾選輪詢 SCM,在Schedule 配置輸入計劃規則 |
須要在Build Triggers 配置中勾選Trigger builds remotely ,設置Authentication Token |
須要在Build Triggers 配置中勾選輪詢 SCM |
防跨域攻擊 | 無需考慮 | 支持,須要獲取防跨域攻擊的token | 支持,須要獲取防跨域攻擊的token |
通知方式 | 定時輪詢 | 經過Remote access API 調用主動構建 |
經過向Subversion Plugin 發送請求主動構建 |
時效性 | 最快代碼提交後1分鐘觸發 | 當即觸發 | 當即觸發 |
其餘要求 | 無 | 無 | 須要安裝Subversion Plugin 插件,同時服務端執行腳本須要一些特殊權限 |
具體使用哪一種方案根據上面表格選擇便可。
最終咱們的完整持續集成流程圖以下圖所示
graph LR 獲取代碼 --> 編碼 編碼 --> 提交代碼 提交代碼 --> |自動構建| 編譯程序集 編譯程序集 --> 編譯單元測試程序集 編譯單元測試程序集 --> |經過| 執行單元測試 編譯單元測試程序集 --> |不經過| 失敗 執行單元測試 --> |經過| 建立nuget包 建立nuget包 --> 上傳nuget包 執行單元測試 --> |不經過| 失敗 上傳nuget包 --> 清理編譯文件夾 失敗 --> 清理編譯文件夾 失敗 -.-> 獲取代碼
本文地址:http://www.javashuo.com/article/p-hxqkzgij-hg.html 做者博客:傑哥很忙 歡迎轉載,請在明顯位置給出出處及連接