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包的勾去除

或者我们修改csprojGeneratePackageOnBuild节点值,改为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

此时流程优化如下

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分钟触发构建。

设置完之后我们提交代码就会自动构建了。相比手动构建,自动构建左边菜单栏会显示轮询日志,右边会显示由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远程构建

创建客户端钩子脚本

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

我们先获取到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.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





同时我们创建了钩子脚本放入,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发送成功。

获取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插件,同时服务端执行脚本需要一些特殊权限

具体使用哪种方案根据上面表格选择即可。

结语

最终我们的完整持续集成流程图如下图所示

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

本文地址:https://www.cnblogs.com/Jack-Blog/p/10331263.html

作者博客:杰哥很忙

欢迎转载,请在明显位置给出出处及链接

Jenkins持续集成学习-Windows环境进行.Net开发3的更多相关文章

  1. Jenkins持续集成学习-Windows环境进行.Net开发1

    目录 Jenkins持续集成学习-Windows环境进行.Net开发 目录 前言 目标 使用Jenkins 安装 添加.net环境配置 部署 结语 参考文档 Jenkins持续集成学习-Windows ...

  2. Jenkins持续集成学习-Windows环境进行.Net开发2

    目录 Jenkins持续集成学习-Windows环境进行.Net开发2 目录 前言 目标 使用 .Net Stardard 单元测试 流程 手动执行单元测试 自动执行单元测试 单元测试报告 上传Nug ...

  3. Jenkins持续集成学习-Windows环境进行.Net开发4

    目录 Jenkins持续集成学习-Windows环境进行.Net开发4 目录 前言 目标 Github持续集成 提交代码到Github 从Github更新代码 git上显示构建状态 自动触发构建 Gi ...

  4. Jenkins持续集成学习-搭建jenkins问题汇总

    目录 Jenkins持续集成学习5-搭建jenkins问题汇总 目录 前言 问题列表 nuget还原包问题 编译问题 SVN更新问题 参考文档 Jenkins持续集成学习5-搭建jenkins问题汇总 ...

  5. Windows系统的Jenkins持续集成环境

    Windows系统的Jenkins持续集成环境 如题:本文将介绍如何在Windows环境下运用Jenkins部署持续集成环境.之所以写本文,是因为在最近工作当中,学习使用Jenkins时,确实遇到了一 ...

  6. windows部署jenkins持续集成maven测试项目不能访问测试报告

    买了一台阿里云的服务器用于练习maven test项目,系统版本wiondows server 2012,将jenkins war包部署在Tomcat服务器上,项目构建后,生成的报告在C:\Windo ...

  7. windows系统下构建Jenkins持续集成

    环境准备 windows10+tomcat+python3.x(安装方法自行百度) 安装Jenkins 从https://jenkins.io/download/ 下载war包 将war包放到tomc ...

  8. Jenkins持续集成(上)-Windows下安装Jenkins

    环境:Windows 2008 R2.Jenkins2.235.1: 概要 前面写过一篇文章,<自动发布-asp.net自动发布.IIS站点自动发布(集成SLB.配置管理.Jenkins)> ...

  9. Docker+Jenkins持续集成环境(4):使用etcd+confd实现容器服务注册与发现

    前面我们已经通过jenkins+docker搭建了基本的持续集成环境,实现了服务的自动构建和部署,但是,我们遇到一个问题,jenkins构建出来的镜像部署后,需要通过ip:port去访问,有什么更好的 ...

随机推荐

  1. Spring MVC 的 Converter 和 Formatter

    Converter 和 Formatter 都可用于将一种对象类型转换成另一种对象类型. Converter 是通用元件,可以将一种类型转换成另一种类型,可以在应用程序中的任意层中使用: Format ...

  2. shell启动执行cypher语句

    1.跳转到目录:cd /data/soft/neo4j-community-not/ 2.修改配置文件:nano ./conf/neo4j.conf: 3. 登录:bin/cypher-shell - ...

  3. 多线程安全单例模式学习代码 c++11

    // Singleton.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <mutex> #include & ...

  4. 学习Acegi应用到实际项目中(1)

    在此,本人声明,我处于菜鸟阶段,文章的内容大部分摘自zhanjia的博客(http://zhanjia.iteye.com/category/43399),旨在学习,有很多地方,我理解不够透彻,可能存 ...

  5. OpenCV图像分割2

    1.GrubCut算法 2.K-means聚类算法 3.分水岭算法

  6. ABP框架系列之十六:(Dapper-Integration-Dapper集成)

    Introduction Dapper is an object-relational mapper (ORM) for .NET. Abp.Dapper package simply integra ...

  7. std::string的拷贝赋值研究

    说明:以下涉及的std::string的源代码摘自4.8.2版本.结论:std::string的拷贝复制是基于引用计数的浅拷贝,因此它们指向相同的数据地址. // std::string类定义type ...

  8. 网页中的数据的4个处理方式:CRUD(Creat, Retrive, Update, Delete)

    网页中的数据的4个处理方式:CRUD(Creat, Retrive, Update, Delete) 2018-12-21, 后续完善

  9. Codeforces Round #514 (Div. 2) B - Forgery

    这个题我一开始没思路,最后也没思路 2个小时一直没思路 本来还想解释题意的,写了半天发现解释的不是很清楚,你还是google翻译一下吧 这个题解法是这样的: 首先,给你图案里面有很多的点,每个点的周围 ...

  10. Python 装饰器(笔记,非原创)

    定义:本质是函数,为其他函数添加附加功能原则:1.不能修改被装饰的函数的源代码         2.不能修改被装饰的函数的调用方式知识储备:       1.函数即“变量”       2.高阶函数  ...