热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

本篇文章探究如何做到SVN代码提交后自动构建。完成完整的

目录

  • Jenkins持续集成学习-Windows环境进行.Net开发3
    • 目录
    • 前言
    • 目标
    • 优化nuget包生成流程
    • 自动触发构建
      • Jenkins定时轮询触发
      • SVN客户端钩子触发
      • SVN服务器钩子触发
    • 三种钩子比较
    • 结语
    • 参考文档

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

目录

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

前言

在前面两篇文章介绍了关于持续集成的完整主流程。

目标

在上一篇文章中我们完成了主流程的持续集成,但是提交代码仍然需要手动点击构建,本篇文章就来探究如何做到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

此时流程优化如下

自动触发构建

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远程构建

创建客户端钩子脚本

创建一个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.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版本库不同方面的命令行工具。

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

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

结语

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

参考文档

  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

推荐阅读
  • Jenkins的分布式构建,在Jenkins的配置中叫做节点,分布式构建能够让同一套代码或项目在不同的环境(如:Windows和Linux系统)中编译、部署等。将jenkins项目 ... [详细]
  • Jenkins教程:使用Jenkins进行持续集成
    【注】本文译自:https:www.edureka.coblogjenkins-tutorial本文将重点介绍Jenkins架构和Jenkins构建管道,并向您展示如何在Jenki ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 解决github访问慢的问题的方法集锦
    本文总结了国内用户在访问github网站时可能遇到的加载慢的问题,并提供了解决方法,其中包括修改hosts文件来加速访问。 ... [详细]
  • svnWebUI:一款现代化的svn服务端管理软件
    svnWebUI是一款图形化管理服务端Subversion的配置工具,适用于非程序员使用。它解决了svn用户和权限配置繁琐且不便的问题,提供了现代化的web界面,让svn服务端管理变得轻松。演示地址:http://svn.nginxwebui.cn:6060。 ... [详细]
  • SVN 功能说明(简版)
    Subversion(SVN)是什么?SVN是一种版本管理系统,是开源软件的基石。即使在沟通充分的情况下,多人维护同一份源代码的一定也会 ... [详细]
  • 文章目录UnsafeDeserialization反序列化漏洞背景认识Java序列化与反序列化用途应用场景Java中的API实现:序列化基础类型参数序列化对象漏洞是怎么来的呢?解决 ... [详细]
author-avatar
情都欧阳
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有