本系列文章包含:
1、前言
本文是对用“MSBuild和Jenkins搭建持续集成环境(2)”的解读,原文中一些设置并不能得到作者所描述的结果,因此下文会结合实际部署对原文稍作修改。
第一眼看上去,Jenkins像是一个专为Java项目准备的持续集成工具:有为Maven项目设计的job,有诸多为Java项目提供的默认插件,更不要说那些用Java写的插件了。
但Jenkins其实是一个非常灵活的工具,它可以结合各种版本管理系统和构建工具,用来构建任何类型的项目。在这篇文章中,我们会利用它的灵活性,从Mercurial中pull代码,用MSbuild构建项目。首先,我们需要下载并安装Jenkins,然后安装Git和MSBuild插件。【原文中使用的是Mercurial,由于我经常使用Git,因此这里会更改为对Git的配置】
2、配置Jenkins
从官方网站下载安装程序。它的Windows安装包很简单,会把Jenkins安装成Windows服务。Jenkins的默认的访问路径是“localhost:8080”,请确保8080端口不要被其他应用占用。
安装完毕以后就是装插件。请点击“系统管理”链接,然后再点击“插件管理”。
在“可用插件”标签页可以查看当前可安装的插件──你需要有一个能上网的环境,才能看到这一页的内容。用“过滤框”找到Git Plugin、GitHub Plugin和 MSBuild插件,点击插件名称前面的复选框,进行安装【在选择安装时,会自动关联一些必要的插件进行安装,很方便】。
你可以点击“已安装”标签页,来确保这两个插件已经被安装成功了。
在安装过程中,你可能会看到提示信息说Jenkins需要重启才能完成安装,请让它重启,等重启完成后再访问“已安装”标签页,看看是不是安装成功。
由于将来使用GitHub,因此只需要知道一个Code的地址即可,配置很方便。回到“系统管理”这一页上来,点击“系统设置”,找到“Git”这一部分──如果你找不到“Git”的话,就说明Git插件没有装好──点击“Add Git”按钮之后,你需要给这个Git实例起个名字(自己用着越方便越好);还需要输入Git可执行文件的安装路径,这里用的是git.exe文件的所在目录;
3、创建一个Jenkins Job
点击Jenkins的logo,回到控制面板上来,然后点击“新建”链接。你会看到一组job类型,选择“构建一个自由风格的软件项目”,给它命名为“CIProjectWebDemo1-RunUnitTests”,点击OK。
下一步是job配置页面。这一页有很多配置项,而且大多数都带有详细的描述信息,点击右侧的帮助图标就可以看到。
我们现在只配置两部分,一是代码库所在位置,二是如何用MSBuild构建项目。
找到“源码管理”,选择Git。在“Repository URL”输入框中输入”你自己的GitHub中的代码地址”。然后在Credentials中选择证书【如果没有就创建一个,一直默认就行,最开始我没有选择证书,在执行Job时,有时会卡在GitHub的通信上,可能和这个有关,网上也有说和https协议有关】。最后在Branch中输入你想跟踪的分支名,其他的选项看自己喜好。
接下来到“构建”这部分。点击“增加构建步骤”按钮后,下拉框中就会出现一系列的step类型以供选择,其中便包括“Build a Visual Studio project or solution using MSBuild”,如果你没看到这个选项,就说明MSBuild插件没有正确安装。
点击“Build a Visual Studio project or solution using MSBuild”之后,在“MSBuild Build File”输入框中输入构建脚本的名字:CIProjectWebDemo1.msbuild。我们想让Jenkins执行“RunUnitTests”这个Target ,如果你没有把DefaultTargets属性设成RunUnitTests的话,可以在“Command Line Arguments”中输入“/t:RunUnitTests”,其中/t是/target的简写。
点击“Save”或“Apply”保存之后,这个job一旦被触发,就可以pull代码下来,编译项目,执行单元测试【这里感觉Save的提示很醒目,不知道用的那个UI框架,源码中有看到引用YUI,没用过不知是不是这个,有知道的朋友请留言给我,不胜感激】。
我们先来手工触发一次,看看配置是否正确。先回到“控制面板”,这时可以在屏幕中央看到我们的job。点击job名字,然后在左侧的链接中找到“Build Now”链接,点击它,Jenkins就会开始执行。
在这组链接的下方有一个“Build History”列表,它显示的是这个job的所有构建历史,当第一次构建开始运行的时候,你会在列表中看到一个进度条,同时还有一个小圆球显示构建状态。圆球闪烁表示构建正在进行中,它停止闪烁的时候一般会是红色或蓝色,红色表示构建失败,蓝色表示成功。
如果这个job能够访问GitHub版本库,找到了CIProjectWebDemo1.msbuild脚本,“RunUnitTest”执行成功,这个圆球应该会变蓝。这时候你也就顺利完成了第一个Jenkins构建。如果构建失败,请点击“Build History”对应的编号查看详细信息,然后点击“Console Output”,就可以看到Jenkins所执行的每一个命令和对应结果,从中可以分析出构建失败的原因。
4、触发构建
构建成功以后,下一步要做的就是让Jenkins检测版本库的变化,一旦有代码提交,Jenkins就要pull代码并执行构建。有好几种方法可以做到这一点。
最简单的就是让Jenkins定时构建,但是如果在这一段时间内没有代码提交,这次构建反而是浪费。
另一种方式是让Jenkins定时轮询,看看版本库中是否有代码提交。这种方法的缺点是当有了代码提交以后,Jenkins要等到下一个轮询周期才能执行构建。当然,你也可以让Jenkins每分钟都轮询一次,尽可能缩短等待时间。但我们还有另一种更优雅的方案──给版本库中放一个post-commit的钩子,这样一旦版本库接受了新代码,它都会通知Jenkins,让它立刻开始构建。【原文是使用Mercurial作为版本管理工具的,因此下面的这种方法,我没有尝试,有兴趣的朋友可以拜读原文,尝试一下】
回到job配置页面,在“Build Trigger”区域选择“Poll SCM”,在“Schedule”输入框中输入轮询周期。它采用的语法格式是cron的风格。如果要每5分钟轮询一次,就输入“H/5 * * * *”。你可以点击输入框右侧的帮助按钮,查看轮询周期的语法介绍。
5、构建流水线
Jenkins可以在某个构建成功结束之后启动其他job。于是就有了构建流水线,它的概念就是一个job成功之后触发其他job。触发者叫做上游job,被触发者被称作下游job。
构建流水线的应用场景有很多:让耗时较长的测试在单元测试结束之后执行;运行静态代码检查;把构建结果部署到试机环境(staging)或者产品环境中。我们下面来演示一下这个功能,让Jenkins在构建结束后启动web服务器,运行CIProjectWebDemo1这款应用。
我们只需要做三件事情:
1. CIProjectWebDemo1-RunUnitTests job成功之后触发一个新job;
2. 把CIProjectWebDemo1-RunUnitTests的构建结果拷贝出来;
3. 启动web服务器。
在开始之前,你还需要安装Copy Artifacts插件。回到Manage Plugins页面,参考之前安装Mercurial插件的方法安装Copy Artifacts。在看到重启的提示信息时重启Jenkins。【这一阶段要连接的源有些是国外的,很有可能被Q,导致安装失败,到时自行FQ即可】
创建新job之前,我们需要告诉CIProjectWebDemo1-RunUnitTests job,让它把构建产物保存下来,以供新job使用。回到CIProjectWebDemo1-RunUnitTests job的配置界面,找到“增加构建后操作步骤”,选中“Archive the artifacts”,页面上就会出现一个文本框:“用于存档的文件”。
我们要存档的目录有两份,一份是BuildArtifacts目录,一份是packages目录,后者是为了让我们能够访问NuGet package。如果要指定某个目录以及目录下所有内容,就需要在目录后面跟一个斜杠和两个星号。不同的目录或文件之间用逗号分割。在这里我们输入的是“BuildArtifacts/**”。
现在创建一个新job,起名叫“CIProjectWebDemo1-StartWebServer”【选择“构建一个自由风格的软件项目”】。在配置页面上“构建触发器”那一节里选中“Build after other projects are built”,把之前那个job配置成要触发当前job的项目。
接下来给job添加一个build step,让这个job所做的第一件事情就是拷贝之前job所保存的构建产物。这里要用到“Copy artifacts from another project”这个step(它是由Copy Artifacts插件提供的)。我们只需要填入CIProjectWebDemo1-RunUnitTests job的名字就可以。
最后还要添加一个build step,让它启动web server。这里用的是“Execute Windows batch command”,我们用Visual Studio提供的Cassini来运行应用。
Cassini可以在“C:\Program Files (x86)\Common Files\microsoft shared\DevServer\10.0\WebDev.WebServer40.EXE”找到【我是全盘搜索找到的】。运行Cassini很简单,把web应用存放的路径作为参数传给它就行,如果没有指定端口号的话,它就会使用默认的端口号80。
“Execute Windows batch command”step需要一个可以在BuildArtifacts和packages拷贝后的目录下执行的命令。我们把下面这个命令复制到“Command”输入框中:
"C:\Program Files (x86)\Common Files\microsoft shared\DevServer\10.0\WebDev.WebServer40.EXE" /port:9988 /vpath:"BuildArtifacts\_PublishedWebsites\CIProjectWebDemo1"
【上面的命令是我自己测试出来的,原文中的命令无法执行,可能是Cassini版本不一样】
这个命令可以启动Cassini,把它指向拷贝过来的应用,然后在9988端口启动服务器。
所有的配置都已就绪。试着修改一下代码然后提交。Jenkins应该能够监听到变化,运行CIProjectWebDemo1-RunUnitTests。如果代码编译成功,所有测试均以通过,Jenkins应该开始运行CIProjectWebDemo1-StartWebServer job,把CIProjectWebDemo1-RunUnitTests的构建产物拷贝过来,在9988端口启动Cassini。如果这一切都运行无误,我们的持续集成系统就搭好了。
6、结尾
此配置的结果是网站拷贝完毕后,启动Cassini,指定网站目录,然后这个job就一直处在等待的状态,我觉得这就到结果了吧,相当于在Jenkins的进程中开启了一个Web服务,此时在浏览器中输入http://localhost:9988/main.aspx(这里我是用的自己的webFrom网站)就可以访问到你的页面了。
但是,如果不手动结束这个Job,那么就会一直执行下去,当下一次被CIProjectWebDemo1-RunUnitTests运行结束的消息启动,除非在配置里开启并发执行,否则将会一直等待上一个进程的执行;而并发执行又会由于端口被占用,导致Cassini无法启动,并使其崩溃。。感觉好乱。
作者写这个例子的目的,可能是为了演示Job链吧。
后来想到,如果没有使用Cassini,而是用其他的web服务器来启动网站,可能就不会存在这种问题了。
各位看官,请继续阅读 [独孤九剑]持续集成实践 - 引子