Jenkins持續整合學習-Windows環境進行.Net開發
目錄
- Jenkins持續整合學習-Windows環境進行.Net開發
Jenkins持續整合學習-Windows環境進行.Net開發
前言
本文探究在.net環境下的持續整合環境研究並使用。關於為什麼使用Jenkins,可以參考一下jenkins持續整合原理
目標
學習jenkins的基本使用,完成以下2點任務。
- 搭建jenkins任務完成自動編譯。
- 自動從nuget上獲取需要的包。
使用Jenkins
安裝
到 Jenkins官網 下載安裝包,進行安裝。安裝完成後會自動開啟一個頁面。預設是網站是localhost:8080。若埠已被佔用則需要修改成別的埠。
具體安裝問題可以看這裡 淺談.net jenkins svn下自動化整合環境安裝 搭建 配置
主要是安裝完後需要安裝.net的環境的一些外掛及svn(或git)等相關外掛。
根據官網描述是需要安裝java環境的
新增.net環境配置
安裝完後如果要在.net環境使用,在MSBuild外掛安裝完的前提下。配置msbuild.exe的路徑。這樣jenkins就能通過msbuild來編譯.net專案了。具體配置可以可以參考 《為 Jenkins 配置 .NET 持續整合環境》
我本地的jenkins的全域性配置配的MSBuild也為14.0
安裝了不同版本的VS的MSBuild版本可能不一樣。
部署
我們通過VS先新建一個控制檯專案 .net framework4.5
的專案,專案名稱叫做 JenkinsTest
。在Program.cs中簡單的輸出 hello world
static void Main(string[] args) { Console.WriteLine("Hello World!"); }
程式目錄如下
│JenkinsTest.sln │ └─JenkinsTest │App.config │JenkinsTest.csproj │Program.cs │ └─Properties AssemblyInfo.cs
編譯通過後將專案上傳到SVN上,我在我本地建了SVN的服務,並增加了使用者名稱和密碼分別為test。
新建專案

建立一個名為test的自由風格軟體專案。

我本地使用的是SVN,因此選擇Subversion,輸入SVN的路徑。 Local module directory
為SVN獲取程式碼的路徑。 .
表示獲取到jenkins的根目錄下。

首次建立的時候需要建立SVN的登入憑據,在Credentials項點選Add新增一個新的憑據,型別就選擇 Username with password
即可,id需要輸入一個唯一憑據標識。

在 Build Environment
下勾選 Add timestamps to the Console Output
,這樣可以顯示時間戳。

在 Build
選擇MSBuild的版本,這個版本在全域性配置設定過,在這裡就可以顯示出來。 MSBuild Build File
輸入需要編譯的程式集檔名。在 Command Line Arguments
輸入編譯的引數,我們編譯成Realse版本。完成後點選儲存即可。具體MSBuild指令不做具體探究,有什麼問題直接可以看 官方文件
點選立即構建就會自動編譯,完成就會顯示一個結果


點選 #1
即可調轉到該次編譯的詳細資訊中,在左側點選 Console Output
可以看到編譯的過程日誌。

構建過程分析
-
先從SVN獲取程式碼
16:21:55 由使用者 jake 啟動 16:21:55 構建中 在工作空間 D:\Program Files (x86)\Jenkins\workspace\test 中 16:21:55 Updating https://jakepc/svn/JenkinsTest/trunk/JenkinsTest at revision '2019-01-18T16:21:55.792 +0800' --quiet 16:21:55 Using sole credentials test/****** (本地svn伺服器) in realm ‘<https://jakepc:443> VisualSVN Server’ 16:21:55 At revision 3
-
呼叫MSBuild命令進行編譯,這裡會查詢我們全域性配置的MSBuild.exe執行我們在建立時輸入的
Command Line Arguments
指令。16:21:56 Path To MSBuild.exe: C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe 16:21:56 Executing the command cmd.exe /C " "C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" /t:Build /p:Configuration=Release JenkinsTest.csproj " && exit %%ERRORLEVEL%% from D:\Program Files (x86)\Jenkins\workspace\test 16:21:56 [test] $ cmd.exe /C " "C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" /t:Build /p:Configuration=Release JenkinsTest.csproj " && exit %%ERRORLEVEL%%
-
編譯完成,顯示警告,錯誤和結果
... 16:21:57 _CopyAppConfigFile: 16:21:57正在將檔案從“App.config”複製到“bin\Release\JenkinsTest.exe.config”。 16:21:57 CopyFilesToOutputDirectory: 16:21:57正在將檔案從“obj\Release\JenkinsTest.exe”複製到“bin\Release\JenkinsTest.exe”。 16:21:57JenkinsTest -> D:\Program Files (x86)\Jenkins\workspace\test\bin\Release\JenkinsTest.exe 16:21:57正在將檔案從“obj\Release\JenkinsTest.pdb”複製到“bin\Release\JenkinsTest.pdb”。 16:21:57 已完成生成專案“D:\Program Files (x86)\Jenkins\workspace\test\JenkinsTest.csproj”(Build 個目標)的操作。 16:21:57 16:21:57 已成功生成。 16:21:570 個警告 16:21:570 個錯誤 16:21:57 16:21:57 已用時間 00:00:01.22 16:21:59 Finished: SUCCESS
通過以上三步驟,實際和我們自己使用VS編譯過程也是一樣的。
增加依賴dll
上面我們建立了一個最簡單的專案,並通過jenkins獲取並編譯成功了,下面我們增加專案複雜性,增加其他依賴項。
新建一個jenkins.Common的類庫。我們把 HelloWorld
的字串通過該類庫獲取到,然後主專案進行輸出。
增加 HelloWolrdHelper
類獲取字串
public class HelloWolrdHelper { public static string GetString() { return "Hello World!"; } }
修改原專案
static void Main(string[] args) { Console.WriteLine(HelloWolrdHelper.GetString()); Console.ReadKey(); }
然後提交程式碼到SVN後在jenkins再次構建,結構如下。
│JenkinsTest.sln │ ├─Jenkins.Common ││HelloWolrdHelper.cs ││Jenkins.Common.csproj ││ │└─Properties │AssemblyInfo.cs │ └─JenkinsTest │App.config │JenkinsTest.csproj │Program.cs │ └─Properties AssemblyInfo.cs
構建一下,編譯成功了,MSBuild會根據 csproj
檔案內的依賴關係編譯其他程式集。

生成啟動時間為 2019/1/18 17:16:03。 17:16:03 專案“D:\Program Files (x86)\Jenkins\workspace\test\JenkinsTest\JenkinsTest.csproj”在節點 1 上(Build 個目標)。 17:16:03 PrepareForBuild: 17:16:03正在建立目錄“bin\Release\”。 17:16:03正在建立目錄“obj\Release\”。 17:16:03 專案“D:\Program Files (x86)\Jenkins\workspace\test\JenkinsTest\JenkinsTest.csproj”(1)正在節點 1 上生成“D:\Program Files (x86)\Jenkins\workspace\test\Jenkins.Common\Jenkins.Common.csproj”(2) (預設目標)。 17:16:03 PrepareForBuild: 17:16:03正在建立目錄“bin\Release\”。 17:16:03正在建立目錄“obj\Release\”。 17:16:03 GenerateTargetFrameworkMonikerAttribute: 17:16:03 正在跳過目標“GenerateTargetFrameworkMonikerAttribute”,因為所有輸出檔案相對於輸入檔案而言都是最新的。
增加Nuget依賴
新建一個 Jenkins.Core
專案,並生成Nuget包上傳到Nuget伺服器上。
關於Nuget如何打包可以看我之前的部落格 NuGet的使用、部署、搭建私有服務 ,這裡不做討論。
為了簡單起見,建立一個和 Jenkins.Common
程式集一樣的輸出HelloWorld的方法,但是為了作為區分,分別略作修改。
Jenkins.Common
的程式碼
public class HelloWolrdHelper { public static string GetString() { return "Hello World! Jenkins.Common"; } }
Jenkins.Core
的程式碼
public class HelloWolrdHelper { public static string GetString() { return "Hello World! Jenkins.Core"; } }
程式結構如下
│JenkinsTest.sln │ ├─.nuget │NuGet.Config │NuGet.exe │NuGet.targets │ ├─Jenkins.Common ││HelloWolrdHelper.cs ││Jenkins.Common.csproj ││ │└─Properties │AssemblyInfo.cs │ ├─Jenkins.Core ││HelloWorldHelper.cs ││Jenkins.Core.csproj ││Jenkins.Core.sln ││ │└─Properties │AssemblyInfo.cs │ └─JenkinsTest │App.config │JenkinsTest.csproj │packages.config │Program.cs │ └─Properties AssemblyInfo.cs
注意:Jenkins.Core我放到一個單獨的專案中打包的。原本我是放到原專案一起。但是Nuget似乎有個bug,導致編譯通不過。
因為控制檯專案更新的時候會向 JenkinsTest.csproj
檔案寫入nuget包還原的指令
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <PropertyGroup> <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> </PropertyGroup> <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" /> </Target>
而中解決方案的目錄是在上一層目錄 <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
,最終編譯的時候會校驗pacakges是否存在已下載的包。通過路徑 $(SolutionDir)\packages\
下查詢,即 ..\\packages\
。多了一個\導致存在包仍然報錯查詢不到,最終編譯不過。
上傳nuget包
然後從Nuget本地nuget伺服器上獲取。
Program
的程式碼增加新的helloworld輸出
class Program { static void Main(string[] args) { Console.WriteLine(HelloWolrdHelper.GetString()); Console.WriteLine(Jenkins.Core.HelloWolrdHelper.GetString()); Console.ReadKey(); } }
重新編譯專案後上傳程式碼到SVN後再次到Jenkins上構建專案。
可以看到構建失敗了,去看下具體失敗原因。
正在將檔案從“obj\Release\Jenkins.Common.pdb”複製到“bin\Release\Jenkins.Common.pdb”。 12:51:14 已完成生成專案“D:\Program Files (x86)\Jenkins\workspace\test\Jenkins.Common\Jenkins.Common.csproj”(預設目標)的操作。 12:51:14 ResolveAssemblyReferences: 12:51:14主引用“Jenkins.Core, Version=0.2.0.0, Culture=neutral, processorArchitecture=MSIL”。 12:51:14 C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(1820,5): warning MSB3245: 未能解析此引用。未能找到程式集“Jenkins.Core, Version=0.2.0.0, Culture=neutral, processorArchitecture=MSIL”。請檢查磁碟上是否存在該程式集。 如果您的程式碼需要此引用,則可能出現編譯錯誤。 [D:\Program Files (x86)\Jenkins\workspace\test\JenkinsTest\JenkinsTest.csproj] 12:51:14用於 SearchPath“{HintPathFromItem}”。 12:51:14已考慮使用“..\packages\Jenkins.Core.0.2.0\lib\net45\Jenkins.Core.dll”,但它不存在。 12:51:14用於 SearchPath“{TargetFrameworkDirectory}”。 12:51:14已考慮使用“C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Jenkins.Core.winmd”,但它不存在。 12:51:14已考慮使用“C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Jenkins.Core.dll”,但它不存在 ... 12:51:14 Program.cs(15,22): error CS0234: The type or namespace name 'Core' does not exist in the namespace 'Jenkins' (are you missing an assembly reference?) [D:\Program Files (x86)\Jenkins\workspace\test\JenkinsTest\JenkinsTest.csproj] 12:51:14 已完成生成專案“D:\Program Files (x86)\Jenkins\workspace\test\JenkinsTest\JenkinsTest.csproj”(Build 個目標)的操作 - 失敗。 12:51:15 12:51:15 生成失敗。 12:51:15 12:51:15 “D:\Program Files (x86)\Jenkins\workspace\test\JenkinsTest\JenkinsTest.csproj”(Build 目標) (1) -> 12:51:15 (ResolveAssemblyReferences 目標) -> 12:51:15C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(1820,5): warning MSB3245: 未能解析此引用。未能找到程式集“Jenkins.Core, Version=0.2.0.0, Culture=neutral, processorArchitecture=MSIL”。請檢查磁碟上是否存在該程式集。 如果您的程式碼需要此引用,則可能出現編譯錯誤。 [D:\Program Files (x86)\Jenkins\workspace\test\JenkinsTest\JenkinsTest.csproj] 12:51:15 12:51:15 12:51:15 “D:\Program Files (x86)\Jenkins\workspace\test\JenkinsTest\JenkinsTest.csproj”(Build 目標) (1) -> 12:51:15 (CoreCompile 目標) -> 12:51:15Program.cs(15,22): error CS0234: The type or namespace name 'Core' does not exist in the namespace 'Jenkins' (are you missing an assembly reference?) [D:\Program Files (x86)\Jenkins\workspace\test\JenkinsTest\JenkinsTest.csproj] 12:51:15 12:51:151 個警告 12:51:151 個錯誤 12:51:15 12:51:15 已用時間 00:00:01.43 12:51:15 Build step 'Build a Visual Studio project or solution using MSBuild' marked build as failure 12:51:16 Finished: FAILURE
一開始會去 ..\packages\Jenkins.Core.0.2.0\lib\net45\Jenkins.Core.dll
獲取,但是因為沒有包,後面就去遍歷其他目錄獲取,最終都沒有找到包導致編譯失敗。因此我們需要使用nuget,在MSBuild編譯之前將包下載下來。
為了方便我將nuget一同上傳到SVN上,SVN的程式目錄如下
│JenkinsTest.sln │ ├─.nuget │NuGet.Config │NuGet.exe │NuGet.targets │ ├─Jenkins.Common ││HelloWolrdHelper.cs ││Jenkins.Common.csproj ││ │└─Properties │AssemblyInfo.cs │ └─JenkinsTest │App.config │JenkinsTest.csproj │packages.config │Program.cs └─Properties AssemblyInfo.cs
由於Jenkins.Core可以理解為第三方依賴,不是和JenkinsTest放一起。
在Build配置中新增一項批處理命令,執行nuget包還原。如圖拖動到編譯之前。

根據我們目錄結構呼叫 ".nuget/nuget.exe" restore JenkinsTest.sln
命令使用nuget進行包還原。
由於.nuget目錄帶有.因此需要用雙引號引起來執行。
再次編譯仍然失敗了。可以通過日誌看到已經在編譯前已經執行了指令碼,但是沒有從我們想要的地方獲取包。
13:26:47 No changes for https://jakepc/svn/JenkinsTest/trunk/JenkinsTest since the previous build 13:26:47 [test] $ cmd /c call C:\WINDOWS\TEMP\jenkins8156278399083484284.bat 13:26:47 13:26:47 D:\Program Files (x86)\Jenkins\workspace\test>".nuget/nuget.exe" restore JenkinsTest.sln 13:26:47 MSBuild auto-detection: using msbuild version '15.9.21.664' from 'D:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\bin'. 13:26:48 Restoring NuGet package Jenkins.Core.0.2.0. 13:26:49GET https://api.nuget.org/v3-flatcontainer/jenkins.core/0.2.0/jenkins.core.0.2.0.nupkg 13:26:49NotFound https://api.nuget.org/v3-flatcontainer/jenkins.core/0.2.0/jenkins.core.0.2.0.nupkg 191ms 13:26:49 警告: Unable to find version '0.2.0' of package 'Jenkins.Core'. 13:26:49C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\: Package 'Jenkins.Core.0.2.0' is not found on source 'C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\'. 13:26:49https://api.nuget.org/v3/index.json: Package 'Jenkins.Core.0.2.0' is not found on source 'https://api.nuget.org/v3/index.json'. 13:26:49 13:26:49 警告: Unable to find version '0.2.0' of package 'Jenkins.Core'. 13:26:49C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\: Package 'Jenkins.Core.0.2.0' is not found on source 'C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\'. 13:26:49https://api.nuget.org/v3/index.json: Package 'Jenkins.Core.0.2.0' is not found on source 'https://api.nuget.org/v3/index.json'. 13:26:49 13:26:49 13:26:49 Errors in packages.config projects 13:26:49Unable to find version '0.2.0' of package 'Jenkins.Core'. 13:26:49C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\: Package 'Jenkins.Core.0.2.0' is not found on source 'C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\'. 13:26:49https://api.nuget.org/v3/index.json: Package 'Jenkins.Core.0.2.0' is not found on source 'https://api.nuget.org/v3/index.json'. 13:26:49 13:26:49 NuGet Config files used: 13:26:49D:\Program Files (x86)\Jenkins\workspace\test\.nuget\NuGet.Config 13:26:49C:\WINDOWS\system32\config\systemprofile\AppData\Roaming\NuGet\NuGet.Config 13:26:49C:\Program Files (x86)\NuGet\Config\Microsoft.VisualStudio.Offline.config 13:26:49 13:26:49 Feeds used: 13:26:49https://api.nuget.org/v3/index.json 13:26:49C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\ 13:26:49 13:26:49 D:\Program Files (x86)\Jenkins\workspace\test>exit 1 13:26:49 Build step '執行 Windows 批處理命令' marked build as failure 13:26:50 Finished: FAILURE
指定nuget包下載源地址。
找到Nuget.exe的配置Nuget.Config,在configuration節點內增加packageSources節點。
<packageSources> <add key="Jake Package source" value="http://127.0.0.1:10080/nuget" /> </packageSources>
再次編譯,終於編譯成功了,日誌如下。
13:38:08 No changes for https://jakepc/svn/JenkinsTest/trunk/JenkinsTest since the previous build 13:38:08 [test] $ cmd /c call C:\WINDOWS\TEMP\jenkins5326599668058283263.bat 13:38:08 13:38:08 D:\Program Files (x86)\Jenkins\workspace\test>".nuget/nuget.exe" restore JenkinsTest.sln 13:38:08 MSBuild auto-detection: using msbuild version '15.9.21.664' from 'D:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\bin'. 13:38:09 Restoring NuGet package Jenkins.Core.0.2.0. 13:38:09 Adding package 'Jenkins.Core.0.2.0' to folder 'D:\Program Files (x86)\Jenkins\workspace\test\packages' 13:38:09 Added package 'Jenkins.Core.0.2.0' to folder 'D:\Program Files (x86)\Jenkins\workspace\test\packages' 13:38:09 13:38:09 NuGet Config files used: 13:38:09D:\Program Files (x86)\Jenkins\workspace\test\.nuget\NuGet.Config 13:38:09C:\WINDOWS\system32\config\systemprofile\AppData\Roaming\NuGet\NuGet.Config 13:38:09C:\Program Files (x86)\NuGet\Config\Microsoft.VisualStudio.Offline.config 13:38:09 13:38:09 Feeds used: 13:38:09C:\WINDOWS\system32\config\systemprofile\.nuget\packages\ 13:38:09http://127.0.0.1:10080/nuget 13:38:09https://api.nuget.org/v3/index.json 13:38:09C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\ 13:38:09 13:38:09 Installed: 13:38:091 package(s) to packages.config projects 13:38:09 13:38:09 D:\Program Files (x86)\Jenkins\workspace\test>exit 0 13:38:09 Path To MSBuild.exe: C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe 13:38:09 Executing the command cmd.exe /C " "C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" /t:Build /p:Configuration=Release JenkinsTest/JenkinsTest.csproj " && exit %%ERRORLEVEL%% from D:\Program Files (x86)\Jenkins\workspace\test 13:38:09 [test] $ cmd.exe /C " "C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" /t:Build /p:Configuration=Release JenkinsTest/JenkinsTest.csproj " && exit %%ERRORLEVEL%%
結語
通過N次嘗試,最終完成了.Net開發下Jenkins進行持續整合。總結起來如下:
- 安裝Java環境,由於我本地已有java環境,因此該步驟跳過。
- 安裝MSBuild,由於我本地已安裝過VS,因此該步驟跳過。
- 下載Nuget,由於我本地已安裝VS,同時已安裝過Nuget,因此該步驟跳過。
- 安裝Jenkins,並安裝MSbuild外掛。
- 修改Jenkins的MSBuild外掛的配置。
- 新建一個工程,修改配置
- 選擇原始碼管理,我本地是SVN,因此選擇SVN(增加登入憑據)
- 增加windows批處理指令碼用於Nuget下載庫包。(在Nuget.Config中增加自己的包服務地址)
- 增加MSBuild編譯VS的專案
通過以上步驟,基本就完成了自動編譯的功能。但是光編譯還是不夠的,最終還要完成自動跑單元測試,下一篇部落格再進行研究。