持续集成环境的构建
 

2010-07-27 来源:IT168.com

 

敏捷意味着什么

Agile可以说是近几年来软件工程界最"热"的一个单词,关于它的文章、书籍、讨论不计其数。尽管如此,却仍有大量的从业者对Agile存有误解和困惑。Agile到底意味着什么呢?仅仅是一些漂亮、时髦的宣传吗?到底怎样才算是Agile呢?做到了Agile能为软件开发团队带来什么好处呢?类似的问题还有很多。

Agile其实根本不是一个什么新鲜、时髦的东西,它已经存在了数十年之久了。在这数十年中,那些取得成功的软件开发团队无一不是敏捷开发团队。他们在自己的软件开发过程中大量应用了Agile的思想,只是没有把他们的工作方式、价值观念以及指导思想正式表述出来而已。到了2001年初,这种状况得到了改善,一批在软件开发领域奋战了数十年的领袖和开发大师们(尤其是面向对象社团和Smalltalk社团的领袖)再也无法容忍由于对软件本身的误解以及官僚主义所造成的软件开发方面的混乱,他们把自己数十年来对软件以及团队软件开发的理解和经验总结成了一份"Agile Manifesto",以呼吁软件从业者们应该以怎样的态度来开发和认识软件。Agile的所有思想基础和价值取向全都包含在这份宣言之中。

但是这份宣言对于大多数人来讲,仍然显得有些缺乏可实践性。作为一个软件开发团队,我们可以接受敏捷宣言中的价值观念,但是怎样做才是Agile呢???换句话说,Agile如何落实到团队每天的开发工作中呢?几乎每个试图尝试敏捷软件开发的团队,都曾经被这个问题所困扰过。从团队日常的开发活动的角度来看,Agile就是:

"Short Cycles that are test-driven and feedback-driven, yielding constant improvement."

其中,short cycle是核心。整个软件开发活动应该被划分成一系列短的迭代过程,每个迭代完成一定数目的features。迭代的周期应该尽量得短。更为重要的是,迭代应该是由测试和反馈驱动(TDD和沟通)的。只有这样,我们才能为持续地改进(通过refactoring)提供一个良好的基础和安全网络。请注意,这个过程和一般所说的code-and-fix的本质不同在于:这里的每个迭代周期产出的都是一个经过验证的可用产品,只是可能功能不全,并且这是一个有意识的、持续的基于反馈的改进过程,而不是简单的fix。其实所有成功的项目开发活动都是接近这个标准的,只不过Agile把它放在了最为重要的位置上。

要想有效地达到上面所说的效果,除了需要一些技术方面的技能外(比如:重构技能,TDD技能等)。我们还需要一个能够对上面这种形式的活动进行有效支撑的环境,这个环境应该是所有想取得成功的项目的基础,也就是一个持续集成环境。持续集成为有效地达到Agile提供了基础。那么什么是持续集成呢?

什么是持续集成

从技术层面上来讲,"持续集成"的含义是指开发团队中的每个成员都尽量频繁地把他们所做的工作更改合入到源码库中,并且还要验证新合入的变化没有造成任何破坏。这里的库指的是受版本控制工具(比如:ClearCase或者CVS)管理的软件源代码储存地。这里的频繁程度和团队所开发的软件类型有关,但是一般来说频度应该不大于1个小时。

请注意,持续集成的概念和大家以前曾经听说过的"每日构建"和"每晚构建"的概念有所不同。按照Martin Fowler的话来讲,这个不同主要体现在三个方面:

持续集成在一天之中要频繁地发生,而每晚构建却每天发生一次。

每晚构建的目的是为了产生一个稳定的可用发布,而持续集成除了达成这个目标之外,还对集成的成功与否提供了快速的反馈。

每晚构建并没有规定开发者应该check in的频度,而持续集成为了达到快速反馈的目的,鼓励高频度的check in。

大家可以看出,持续集成的高频度check in和快速提供反馈的特性为有效地达到Agile提供了一个坚实的技术基础。可以这么说,如果没有一个好的持续集成环境作为基础,要想高效地进行团队软件开发几乎是不可能的。那么,如何构建起一个这样的环境呢?在本文的后面,我将给出了一个详细的教程为你提供一步一步的详细指导,但是在这之前,我们先来了解一下构建一个有效的持续集成环境所需要的工具。

持续集成工具介绍

高效地进行持续集成活动的一条有效途径就是自动化,这一点不用说大家也都知道。那么如何才能实现自动化呢?有没有一些现成的工具可以直接拿来使用呢?答案是肯定的。除了那些价格昂贵的商用工具软件外,还有很多简单易用并且非常有效的Open Source免费软件可用。对于这些开源的免费软件,大家大可放心使用,因为很多非常优秀的开源软件都是在这些工具软件所构建的持续集成环境中开发出来的。下面我对几个比较重要的开源工具进行简单的介绍。

Eclipse:Eclipse是一个开源的IDE,是为程序员量身定做的。它最大的特点在于它借鉴了Smalltalk开发环境的思想,可以把自己内部的工作原理通过某种方式展现在使用者面前,使用者只要遵循一些原则就可以根据自己的需要更改这个开发环境。在Eclipse中,这种机制是通过plug-in的方式运作的。通过这种方式,使用者可以方便地把开发过程中常用的工具无缝地集成起来,并以便于自己使用的方式呈现出来。比如:可以方便地把refactoring、JUNIT和CVS等工具集成到Eclipse这个统一的开发平台中来,为持续集成提供一个良好的操作平台。

CVS:CVS是一个开源的版本控制工具软件,和一些价格昂贵的同类商业软件相比,它提供的功能可谓不多,但是这些功能对于大多数的软件开发团队来说已经足够了。CVS为开发团队提供了一个项目范围内的时间机器。通过它,团队可以方便、准确地获取项目在指定时间的状况。不仅如此,CVS还提供有tag和branch的功能,这些功能为团队进行多分支并行开发提供了基础,并且不用担心工作成果的丢失问题。

CruiseControl:CruiseControl是一个持续构建过程框架,并且它对外提供了用于扩展的机制。使用CruiseControl的plugins机制,用户可以方便地将各种需要的源码控制工具和构建工具集成起来,并且可以针对当前和历史构建状态提供诸如email通知、Web显示等对外接口。正是通过这个工具,实现了持续集成的可定制化和自动化。

好了,工具的介绍就到这里,下面就可是我们的持续集成环境搭建之旅。本文不对Refactoring技术、Eclipse、JUnit以及CVS本身的知识做太多的介绍,主要集中在如何把这些工具集成起来构建一个持续集成环境上面,相关的基本知识读者可以自行参考相关的书籍。

持续集成环境搭建教程

下面就是我利用上述的三个开源工具搭建持续集成环境的步骤,将它总结出来以飧读者。

1 工具软件的下载

读者可以到一下网址下载构建持续集成环境所需要的工具软件,这些软件都是Open Source的,可以免费下载和使用。

到 http://www.eclipse.org 下载Eclipse。

到http://www.cvsnt.com 下载CVS

到http://cruisecontrol.sourceforge.net下载CruiseControl

2 安装、配置CVS

CVS是在UNIX系统里的SCCS和RCS的基础上开发的,用于源代码版本管理的产品。它是客户机/服务器结构的产品,可用于多种平台(Linux,Windows),目前已经发展成为软件开发人员在开发过程中进行版本管理的主流产品之一(特别是Open Source软件的开发)。CVS的主要功能是在CVS服务器记录软件开发过程中源文件的历史。当同一组的开发人员对同一项目进行开发时,CVS会将他们进行区分,这样,每个开发人员可以在自己的客户端进行独立的开发工作,在开发人员向CVS服务器提交新的文件后,由CVS资源库统计进行冲突检测和合并。

可以从http://www.cvsnt.com 上下载最新版本的CVSNT,笔者从网站上down下的版本是2.0.58d。双击执行文件,安装,安装过程中会自动添加环境变量,用于表示CVS的安装路径。

选择开始"开始-程序-CVSNT-Service control panel",如图所示,可以看到,CVS服务器和CVS Lock服务器默认都已经启动起来了。  

选择"Repositories"页面,点击"Add"按钮,选择添加CVS资源库的地址,创建一个CVS资源库。本例中地址的选择是笔者按照自己机器上的情况进行的,读者可以根据自己的环境进行设定。

选择"Advanced"页面,确认"Tempory"目录和运行的默认用户。只要端口没有冲突,CVS服务器和CVS Lock服务器的监听端口无需改动,选择"确定"。更改了高级选项后,切换到"Service Status"页面,将两个服务停止,再重新启动。

到此,我们的CVS服务器已经配置成功了,并且也建立一个资源库。

Eclipse中建立和CVS 资源库的连接

CVS的功能是很强大的,并且使用起来也很简洁,但是对于习惯了在GUI环境下开发的程序员来说,如果能够有一个方便操作的图形化界面,并且能够将CVS和我们开发使用的IDE结合起来,在IDE中就能够方便地操作CVS,当然是再好不过了。这样,每个开发人员就都能够方便地在同一个开发平台中check out出产品代码,在本地创建工作备份,将对源代码的改变即时地提交到版本服务器,并且能够把CVS服务器上的最新版本更新到自己本地的工作备份中来。

Eclipse就是一种这样的工具。Eclipse作为一个开源的工作平台,已经被越来越多的开发人员喜欢甚至为他疯狂。它的扩展点和插件思想也使得开发人员可以按照自己的喜好去扩展它,使得它能够以开发人员更加偏爱的方式和面貌出现(似乎每个软件开发人员都有程度或轻或重的偏执),它就像一个任何开发人员通过定制都可以游刃有余地去使用的工具,更多的开发人员把自己的扩展贡献出来,甚至也定制了扩展点,方便更多人的扩展。Eclipse提供了用于管理CVS服务器的插件,并且将对CVS的管理和Eclipse本身所包含的资源透视图等相关透视图和视图联系起来,使得在Eclipse中对CVS的操作更加直观。

Eclipse开发平台的使用和安装,就不再赘述了,因为它是那么深入人心的一个平台,对它太多的描述就显得多余了,笔者在这里将着重介绍它和CVS的珠联璧合。

首先,我们选择Eclipse的菜单"Windows-Open Perspective",打开透视图"CVS Repository Exploring"。

打开透视图后,选择上下文菜单中的"New- Repository Location",如下图所示:

其中重要项的解释如下:

Host:CVS服务器的IP地址

Repository Path:CVS服务器的资源库路径,这个就是刚才通过CVS的服务管理panel建立起来的资源库。

User:用户名,Password:密码,用户就是通过Windows的用户管理建立出来的用户。(这里是通过pserver方式连接CVS的)

另外,勾上Save Password前面的复选框,这个选项使得输入的密码可以被存储在一个本地文件中,这样在以后操作时,就不会被要求再次输入密码了。点击"Finish"按钮,Eclipse按照刚才的配置开始建立和CVS服务器的连接,在连接后,从CVS服务器上读出相关信息。

可以看到,一个CVS的节点下,有Head,Branches,Versions,Dates,分别用来显示资源库中源代码的列表,以及相关tag和branch信息。

4 将Eclipse中的工程检入CVS

现在我们已经将对CVS服务器的管理融合进Eclipse平台之中了。CVS服务器的目的就在于帮助管理源代码,使得每个开发人员都能够独立地开发。现在我们来展示一下,如何将工程加入到CVS服务器中。

首先,在Eclipse中,我们切换到Java透视图中的"Package Explorer",选择我们需要共享的项目,点击右键,选择右键菜单中的"Team-Share Project",选择我们刚才在CVS Repository Exploring透视图中的建立的Location,按照定制的步骤依序进行,即可。我将一个名为"tddsample"的工程检入到CVS中。

工程现在就被纳入到CVS服务器的管理中了,切换到Java透视图的"Package Explorer",我们可以看到工程和其中相关的文件前面的图标都有了些许的改动,并且每个文件后都跟上了版本号。

现在选择一个文件,点击右键,选择"Team",可以看到如下的菜单,commit用来提交改变到CVS服务器,Update用于在CVS服务器选择版本来更新到本地工程中。可以看到,Eclipse集成CVS的功能是非常强大的,通过它,我们可以非常方便的使用CVS提供的功能而无需记忆那些烦杂的命令(不过有些命令还是要知道如何通过命令行下发的,因为自动化的持续集成时是需要的)。

5 建立本地工作空间

在将工程检入CVS以后,要做的就是如何建立本地工作空间了。选择"File-import"菜单,选择导入源为"Checkout Project from CVS"。

按照导向步骤,选择资源库(可以是刚才我们刚刚建立的资源库,也可以重新创建一个新的资源库连接),选择需要导出的模块名,选择导出的位置,然后,就可以完成了。在上一步共享项目中,我们将名为tddsample的工程check in进了CVS,在这一步,我们将它检出,下图中名为tddsample_cvs的工程就是我们从CVS中check out出来的,每个文件的右键菜单上都会有"Team"菜单项,含有的条目和上面相同,现在我们就可以在这个check out出来的工程中工作了。可以想象小组中的每个人员都可以通过这样的方式,从CVS中检出工作副本,在上面独立地工作。

6 安装CruiseControl

首先我们下载CruiseControl,笔者下载的是cruisecontrol-2.1.6版本,一个压缩文件,下载后解压缩到一个目录,笔者称之为CC_HOME。接着,需要构建cruisecontrol,命令如下:

这个脚本将会编译并且测试cruisecontrol。在这个脚本执行完毕后,你会在CC_HOME/main/dist目录下找到cruisecontrol.jar文件,我们以后在运行cruisecontrol时,需要这个文件。

7 准备工作目录

接下来,需要在执行持续集成的机器上准备一个工作目录,这个目录将作为cruisecontrol运行和存贮集成结果的目录。下面将一步一步地描述这个过程。

构建目录就是构建机器上的一个普通的目录,我将这个目录名称为builds。目录结构如下图所示,其中checkout目录用来存放将要被从CVS中check out出进行构建的项目,logs目录用来存放cruisecontrol运行时生成的所有日志文件。

接着我们在builds目录下创建出cc-build.xml和config.xml两个文件:

8 编写构建委托文件

让我们先来看cc-build.xml文件,每次构建至少应该包括以下三个步骤:

1. 删除上一次的构建结果

2. 将工程从cvs中check out出来

3. 运行工程的ant构建文件

将这三个步骤作为ant脚本构建文件中的一个目标任务。为了和构建工程的运行文件分开,并且由于这个文件将来是要被cruisecontrol使用的,所以我们称它为cc-build.xml文件。目前,这个文件定制的任务就是从CVS资源库中check out出最新的工程副本,将它的构建过程委托给工程的build.xml文件。可以看到构建过程被委托给了build.xml文件中定义的目标任务test。<cvs command="co tddsample" />用于从CVS的资源库中check out出模块名为tddsample的工程。在上面的步骤中,我们已经将这个工程通过"Team-Share Project"加入到了CVS的资源库中。

9 测试构建过程

执行下列命令:

该脚本在运行时,会把指定的工程check out到builds/checkout下,并运行工程的build.xml中的test任务,从运行脚本文件的dos窗口中,我们可以看到测试结果(采用的是junit单元测试)。由于test任务是依赖于compile任务的,可以看到,在test任务前,check out出来的文件被编译了。

10 配置构建计划

现在我们来看看cc-build.xml都做了些什么,它把工程从CVS中check out到我们指定的目录中,并进行构建。然而,我们却没有得到任何反馈,任何可以帮助我们更加有信心继续工作下去的反馈。现在,该是cruisecontrol出马的时候了。下一步,我们将要告诉cruisecontrol什么时候以及它该如何运行我们的构建委托文件。通常,这样的配置将会写在一个名为config.xml的文件中,在该文件中我们可以定制cruisecontrol的运行逻辑。

1) 定义工程

首先看看下面两行配置文件。

<project>元素的属性name定义了工程的名字,通常,配置文件中可以定义多个工程,每个工程都可以有其自己的名字。一般的情况下,在上一次的build没有成功并且CVS资源库中也没有任何改变的时候,cruisecontrol仍然会继续下一次的构建,这种情形一般适用于工程的构建对外部资源存在依赖的情形。但是对绝大多数的工程来说,所有的依赖都是存放在CVS的资源库中,此时这种连续的构建就没有必要了,所以,我们使用buildafterfailed="false"来拒绝这种失败后继续构建的行为,仅在检测到CVS资源库中发生变化时才进行下一次的构建活动。

2) 构建的自启动

接着定义一下在每次构建循环开始前要做的事情,就是在文件中记录本次构建开始的时间。这样的记录不表示开始真实的构建,仅仅表示cruisecontrol被唤醒去检查是否有必要去做构建。

3) 检查资源库的变化

这个配置表明cruisecontrol需要去检查哪些内容已经改变来判断是否需要一次集成。Cruisecontrol会将本地中的副本和CVS资源库中的内容进行比较判断是否做了变更,为了保证集成时所需要内容的完整性,quietperiod="60"用来表示在60秒钟之内,CVS的资源库中没有check in动作,才从资源库中check out出副本来进行构建。如果cruisecontrol在60秒钟内发现有check in动作发生,则继续睡去,等待下一次被唤醒。

4) 执行计划

这个配置表明cruisecontrol间隔多长时间被唤醒去做上述检查,并且执行什么文件,可以看到执行文件就是我们刚才编写的构建委托文件。在上述的配置中,可以看到,cruisecontrol每隔一分钟被唤醒去检查构建内容是否发生变化,以及变化是否发生在静态周期内。若是满足条件,则根据<ant buildfile="cc-build.xml" target="build" />来告诉cruisecontrol该去做什么。在这里,就是去运行ant脚本文件cc-build.xml。

5) 存储日志

Cruisecontrol每尝试一次构建后,都会产生日志,<log dir="logs/tddsample">就用来指定目录存放cruisecontrol运行产生的日志。现在被check out出来的工程在执行test目标任务时,产生的测试结果是打印在工作台上的,我们希望测试结果能够以xml文件的形式生成,并且能够被合入到cruisecontrol产生的日志中,作为cruisecontrol每个构建产出日志的一部份,方便查看。好在,cruisecontrol可以做这样的合并,<merge dir="checkout/tddsample/test" />这句脚本用来合并结果。checkout/tddsample/test就是准备用来存放测试结果的目录,这样的合并过后,cruisecontrol可以分析日志文件,并生成各种报表。

6) 以xml文件的形式生成测试结果

因为需要合并测试结果到CruiseControl的构建日志,所以在我们工程的build.xml文件中,将单元测试的结果以XML文件形式生成:

7) 记录构建状态

<currentbuildstatuspublisher> 的状态记录只是每次在构建结束后,在logs/currentbuildstatus.txt 中记录一条信息表明构建结束。

8) 运行cruisecontrol

到此,cruisecontrol的基本配置已经完成了,我们可以来运行它看看结果了。

起始:

等待构建:

看看,一切都是这么美好,集成不再是我们周末的"专利",我们可以周期地执行它,快速得到大量的反馈。下一步该做什么了呢,对了,除非整天盯着工作台,否则,我们不会知道什么时候构建失败了,在构建失败时,我们最希望的就是能够收到一份详细的失败通知。

11 发布构建结果

Cruisecontrol可以通过发送Email和将历史的构建结果显示在web页面上,甚至可以将结果发送到你的手机上,在此,我仅仅介绍第二种方式:通过Web页面发布构建结果。

标准的cruisecontrol发行包中都会包含一个可供选择的web报告工程,放置在$CC HOME/reporting/jsp下,构建这个工程将会产生出一个WAR文件,这个WAR文件可以部署在任何你喜欢的servlet引擎上,比如Tomcat,笔者比较喜欢这个(也是开源的)。

1) 配置web页面属性

在<htmlemail>元素中,我们配置结果发布的web路径、web页面的样式集目录,以及构建结果存放的日志目录。

2) 部署cruisecontrol

首先,我们需要定义三个属性,告诉web应用到哪里去寻找你构建目录中的文件和其他目录。在CC_HOME/reporting/jsp下,创建文件override.properties,然后定义属性,用绝对路径来替代。

接着我们运行

脚本执行完毕,我们在CC_HOME/reporting/jsp/dist下,会发现一个cruisecontrol.war文件,我们把它部署到webserver上。对Tomcat来说,就是拷贝到Tomcat下的webapps目录下。

好了,让我们启动Tomcat,运行bin/startup.bat文件,Tomcat服务器启动后,让我们来查看构建结果吧: http://localhost:8080/cruisecontrol/buildresults/tddsample

在左边,我们可以看到列出了最近的每次构建,我们可以点击某次构建来查看它的测试结果,选择构建,然后点击上方的Test Results,我们可以看到每个测试用例,以及测试用例中涉及的方法,测试的状态

点击上方的Metrics按钮,cruisecontrol可以统计出构建的总数,构建成功的次数和构建失败的次数,画出饼图,同时,还能在下方的时间图上画出构建成功,以及失败发生的时间点。

好了,到此为止,我们已经搭建起了一个持续集成环境,在这个环境中你可以方便、高效地进行软件开发。有了这个环境,你和你的软件开发团队就具备了敏捷的基础。让我们记住:"Agile is short cycles that are test-driven and feedback-driven, yielding constant improvement"。在这个环境中,你和你的团队可以有效地学习、集成进其他一些敏捷开发实践,进入一个良性的软件开发循环中。现在,就从这里开始你的敏捷软件开发之旅,并享受其中的快乐吧。



由外而内看敏捷软件开发
架敏捷开发中史诗故事与用户
看板任务管理
面向全球化的有效敏捷交付
小型团队快速开发方法
DevOps,不是一个传说!
更多...   


统一过程及应用
敏捷过程实践
基于XP/RUP的迭代开发
软件开发过程指南
SCRUM过程实践
敏捷测试-简单而可行


某博彩企业 产品经理与产品管理
北京 研发团队与工作管理
广东金赋信息 敏捷开发过程与项目管理
某支付平台 软件配置管理与发布管理
富士 软件外包项目管理与进度管理
塞孚耐 基于Scrum的敏捷开发
更多...   
 
 
 
 
 

组织简介 | 联系我们 |   Copyright 2002 ®  UML软件工程组织 京ICP备10020922号

京公海网安备110108001071号