Jenkins持續集成學習-Windows環境進行.Net開發3

Jenkins持續集成學習-Windows環境進行.Net開發3


目錄

Jenkins持續集成學習-Windows環境進行.Net開發1
Jenkins持續集成學習-Windows環境進行.Net開發2
Jenkins持續集成學習-Windows環境進行.Net開發3
Jenkins持續集成學習-Windows環境進行.Net開發4
Jenkins持續集成學習-搭建jenkins問題彙總shell

前言

在前面兩篇文章介紹了關於持續集成的完整主流程。windows

30.png

目標

在上一篇文章中咱們完成了主流程的持續集成,可是提交代碼仍然須要手動點擊構建,本篇文章就來探究如何作到SVN代碼提交後自動構建。api

優化nuget包生成流程

在開始以前我須要解決上一篇文章理解有誤的一個問題。
在上一章咱們將單元測試的不穩定錯誤等級設置爲1。跨域

2.27.PNG

當我添加多個失敗的單元測試時,我發現1次單元測試失敗錯誤等級就會加1,我增長了一共11個失敗的單元測試,所以單元測試失敗返回值爲11。bash

4.PNG
所以上次的邏輯就行不通了,編譯的時候自動建立nuget包,不穩定版本刪除nuget包,這樣只能將錯誤等級設置的很是大。好比int.Max,不然失敗會致使刪除腳本不執行。
所以咱們有兩種選擇:服務器

1. 編譯的時候自動建立nuget包, 單元測試將不穩定的ERRORLEVEL設置的很是大,單元測試失敗均可以認爲是不穩定,而後自動刪除nuget包。
2. 編譯的時候不自動建立nuget包,單元測試經過後再調用腳本建立nuget包。

咱們優化一下使用第二種方法生成nuget包。svn

咱們將項目中自動生成nuget包的勾去除
3.PNG工具

或者咱們修改csprojGeneratePackageOnBuild節點值,改成false,則編譯的時候也不會自動建立nuget包。
5.PNGoop

而後咱們修改單元測試ERRORLEVEL,單元測試失敗了就再也不執行後續Build的流程,在單元測試成功時建立Nuget包。
6.png

經過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

此時流程優化以下

28.PNG

graph LR

    編譯程序集 --> 編譯單元測試程序集
    編譯單元測試程序集  --> |經過| 執行單元測試
    編譯單元測試程序集  --> |不經過| 失敗
    執行單元測試 --> |經過| 建立nuget包
    建立nuget包 --> 上傳nuget包
    執行單元測試  --> |不經過| 失敗
    上傳nuget包 --> 清理編譯文件夾
    失敗 --> 清理編譯文件夾

自動觸發構建

SVN自動觸發構建一共有3種方式。

  1. 分別爲Jenkins定時輪詢觸發。
  2. SVN客戶端建立鉤子觸發。
  3. SVN服務器端建立鉤子觸發。

Jenkins定時輪詢觸發

Jenkins定時輪詢觸發是使用Jenkins 輪詢SCM功能定時檢查SVN是否有變動觸發構建。

Jenkins的輪詢SCM的說明上提到該功能須要掃描整個Jenkins工做區並驗證,操做性能要求比較高。咱們依然驗證一下這個功能。

在配置Build Triggers選項中勾選輪詢SCM,在Schedule輸入 * * * * *表示每分鐘輪詢一次,即代碼提交後1分鐘觸發構建。
1.png

設置完以後咱們提交代碼就會自動構建了。相比手動構建,自動構建左邊菜單欄會顯示輪詢日誌,右邊會顯示由SCM變動啓動,代表是輪詢SCM觸發的構建。

2.png

SVN客戶端鉤子觸發

SVN客戶端鉤子觸發是在本地提交的時候執行本地的Post-Commit鉤子,經過這個鉤子執行腳本使用http請求調用jenkins的遠程構建接口。

配置

生成用戶受權Token

系統配置-管理用戶-用戶-配置API TOKEN點擊生成新的Token按鈕,建立一個token。咱們須要根據這個token來獲取權限。
10.png

增長項目受權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遠程構建
11.PNG

建立客戶端鉤子腳本

20.PNG

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客戶端的設置中找到鉤子腳本,點擊添加。

7.PNG
設置路徑和腳本路徑,注意左下角兩項勾起來。
8.png

21.PNG

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

咱們先獲取到Jenkins-Crumb獲取到防跨域攻擊token。經過向JENKINS_URL/crumbIssuer/api/xml發送一個post請求,獲取到crumb。
12.PNG

發送的時候咱們須要將Authorization加入到http頭部。

提交build請求

將獲取到的Jenkins-Crumb:XXXXX加入到http頭部,經過發送Get請求調用遠程構建,觸發成功會響應201的狀態碼。
13.png
14.png

關於遠程調用更詳細的文檔說明能夠查看Remote access API

經過上面的設置SVN客戶端鉤子遠程構建就完成了,在項目中能夠看到遠程構建的標誌。

9.PNG

相比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文件夾便可。

24.PNG

windows環境鉤子命名規則爲鉤子名.bat或鉤子名.exe,如post-commit.batpost-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
25.png
26.png
同時咱們建立了鉤子腳本放入,SVN鉤子管理就能夠直接讀取到咱們的腳本。
27.PNG

通知腳本參數說明

1. %1:當前項目的SVN倉庫地址。
2. %2:提交後的版本號。
3. CSCRIPT:CScript.exe的路徑。
4. VBSCRIPT:同時jenkins的腳本路徑。
5. SVNLOOK:svnlook.exe的路徑。
6. JENKINS:jenkins服務地址。
7. AUTHORIZATIONN:用於受權token。

svnlook是檢驗Subversion版本庫不一樣方面的命令行工具。

22.png

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發送成功。

獲取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一致
16.png

獲取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請求。
17.PNG
18.png
服務端構建會顯示SCM啓動,和jenkins scm不一樣的是,不須要每分鐘定時輪詢,而是經過服務端鉤子觸發任務執行。
19.PNG

三種鉤子比較

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包 --> 清理編譯文件夾
    失敗 --> 清理編譯文件夾
    失敗 -.-> 獲取代碼

參考文檔

  1. 使用TortoiseSVN的客戶端鉤子腳本觸發Jenkins構建
  2. Jenkins SVN自動構建
  3. SVN怎麼觸發Jenkins自動構建
  4. msxml3.dll 錯誤 80070005 拒絕訪問
  5. 經過jenkins API去build一個job
  6. Remote access API
  7. Implementing Repository Hooks
  8. Windows specific post-commit hook

本文地址:http://www.javashuo.com/article/p-hxqkzgij-hg.html 做者博客:傑哥很忙 歡迎轉載,請在明顯位置給出出處及連接

相關文章
相關標籤/搜索