Jenkins持續集成學習-Windows環境進行.Net開發3
目錄
Jenkins持續集成學習-Windows環境進行.Net開發1
Jenkins持續集成學習-Windows環境進行.Net開發2
Jenkins持續集成學習-Windows環境進行.Net開發3
Jenkins持續集成學習-Windows環境進行.Net開發4
Jenkins持續集成學習-搭建jenkins問題匯總
前言
在前面兩篇文章介紹了關於持續集成的完整主流程。
目標
在上一篇文章中我們完成了主流程的持續集成,但是提交代碼仍然需要手動點擊構建,本篇文章就來探究如何做到SVN代碼提交后自動構建。
優化nuget包生成流程
在開始之前我需要解決上一篇文章理解有誤的一個問題。
在上一章我們將單元測試的不穩定錯誤等級設置為1。
當我添加多個失敗的單元測試時,我發現1次單元測試失敗錯誤等級就會加1,我增加了一共11個失敗的單元測試,因此單元測試失敗返回值為11。
因此上次的邏輯就行不通了,編譯的時候自動創建nuget包,不穩定版本刪除nuget包,這樣只能將錯誤等級設置的非常大。比如int.Max,否則失敗會導致刪除腳本不執行。
因此我們有兩種選擇:
1. 編譯的時候自動創建nuget包, 單元測試將不穩定的ERRORLEVEL設置的非常大,單元測試失敗都可以認為是不穩定,然后自動刪除nuget包。
2. 編譯的時候不自動創建nuget包,單元測試通過后再調用腳本創建nuget包。
我們優化一下使用第二種方法生成nuget包。
我們將項目中自動生成nuget包的勾去除
或者我們修改csproj
的GeneratePackageOnBuild
節點值,改為false,則編譯的時候也不會自動創建nuget包。
然后我們修改單元測試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
此時流程優化如下
自動觸發構建
SVN自動觸發構建一共有3種方式。
- 分別為Jenkins定時輪詢觸發。
- SVN客戶端創建鈎子觸發。
- SVN服務器端創建鈎子觸發。
Jenkins定時輪詢觸發
Jenkins定時輪詢觸發是使用Jenkins 輪詢SCM功能定時檢查SVN是否有變更觸發構建。
Jenkins的輪詢SCM的說明上提到該功能需要掃描整個Jenkins工作區並驗證,操作性能要求比較高。我們依然驗證一下這個功能。
在配置Build Triggers
選項中勾選輪詢SCM,在Schedule輸入 * * * * *
表示每分鍾輪詢一次,即代碼提交后1分鍾觸發構建。
設置完之后我們提交代碼就會自動構建了。相比手動構建,自動構建左邊菜單欄會顯示輪詢日志,右邊會顯示由SCM變更啟動,表明是輪詢SCM觸發的構建。
SVN客戶端鈎子觸發
SVN客戶端鈎子觸發是在本地提交的時候執行本地的Post-Commit
鈎子,通過這個鈎子執行腳本使用http請求調用jenkins的遠程構建接口。
配置
生成用戶授權Token
在系統配置-管理用戶-用戶-配置
的API TOKEN
點擊生成新的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
遠程構建
創建客戶端鈎子腳本
創建一個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客戶端的設置中找到鈎子腳本,點擊添加。
設置路徑和腳本路徑,注意左下角兩項勾起來。
創建通知腳本
創建一個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
我們先獲取到Jenkins-Crumb獲取到防跨域攻擊token。通過向JENKINS_URL/crumbIssuer/api/xml
發送一個post請求,獲取到crumb。
發送的時候我們需要將
Authorization
加入到http頭部。
提交build請求
將獲取到的Jenkins-Crumb:XXXXX
加入到http頭部,通過發送Get請求調用遠程構建,觸發成功會響應201的狀態碼。
關於遠程調用更詳細的文檔說明可以查看Remote access API
通過上面的設置SVN客戶端鈎子遠程構建就完成了,在項目中可以看到遠程構建的標志。
相比SCM輪詢,客戶端遠程構建實時性更高,由於是主動通知,因此代碼提交完立刻可以觸發遠程構建。
SVN服務器鈎子觸發
服務端鈎子與客戶端鈎子類似,具體區別如下。
服務端與客戶端鈎子比較
客戶端鈎子 | 服務端鈎子 | |
---|---|---|
腳本位置 | 客戶端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版本庫不同方面的命令行工具。
創建一個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
發送成功。
獲取SVN版本庫的UUID
通過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一致
獲取SVN版本改變項
通過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
和客戶端獲取Jenkins-Crumb方式一樣。
提交build請求
與客戶端提交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 插件,同時服務端執行腳本需要一些特殊權限 |
具體使用哪種方案根據上面表格選擇即可。
結語
最終我們的完整持續集成流程圖如下圖所示
參考文檔
- 使用TortoiseSVN的客戶端鈎子腳本觸發Jenkins構建
- Jenkins SVN自動構建
- SVN怎么觸發Jenkins自動構建
- msxml3.dll 錯誤 80070005 拒絕訪問
- 通過jenkins API去build一個job
- Remote access API
- Implementing Repository Hooks
- Windows specific post-commit hook
本文地址:https://www.cnblogs.com/Jack-Blog/p/10331263.html
作者博客:傑哥很忙
歡迎轉載,請在明顯位置給出出處及鏈接