轻量级的软件开发方法学,如XP和近期流行的敏捷软件开发,都注重代码的持续集成和自动测试。开发人员以非常短的迭代周期工作,以便能够经常性的交付可以工作的软件。在这样的软件方法学中,代码持续集成和自动测试极其重要,以至于被形象地称为项目开发的心跳,心跳停止之时通常是项目死亡之时。这个至关重要的心跳,通常由Nightly
Build系统来实现。
实现Nightly Build途径之一是利用已有的工具。
“对于Java开发项目,支持Night Build的软件很多,开源的选择有AntHill OS和CruiseControl,后者是大名鼎鼎的ThoughtWorks的作品,配置起来比较麻烦。而AntHill是一个Java
Web应用,拥有友好的定制界面,是2003年Jolt大奖的Productivity Award获得者,比CruiseControl更容易入手。”
这方面的工具中我推荐Buildbot。BuildBot基于Python,配置简洁明了。BuildBot是分布式结构,master监控若干slaves(监视状态,下发命令,搜集结果),各个slave按照指示执行update/compile/test并返回结果。Python和其他许多项目利用它做持续构建。
以上工具都只是持续构建的框架,版本构建的每个步骤(编写Ant脚本、Python脚本或者其他)仍然需要自己实现。
途径之二就是完全自己动手:脚本+crond服务。脚本可以选择Python/Perl/TCL/Shell等。
按照我的理解:持续构建分为如下几个部分:
(1)调度策略:定时构建,还是每次提交就构建?分布式构建还是集中式构建?
BuildBot支持定时构建/每次提交构建等多种,支持分布式构建。而自己动手则仅支持定时构建,仅支持集中式构建。
(2)版本构建步骤:一个版本是由多个组件构成的。这些组件之间的依赖关系如何?版本特定的操作有哪些(如更新Changlog,计算Build
number等)?
BuildBot不关心组件依赖关系和版本特定操作;AntHill之类的工具直接支持这些概念。而自己动手则需要自己处理这些东西。
(3)组件构建步骤:从何处获取最新版本源码?如何编译?如何放置到版本文件中去?
一个组件通常由一个Makefile(传统C/C++项目),Ant脚本(Java项目)或Scons脚本(我偏爱的,Make替代品)来管理,所以构建步骤非常简单。所有的工具都将单个组件的构建任务交给用户编写脚本片段去做。
我偏爱自己编写脚本做Nightly Build,因为它简单、灵活、够用。我不认为大项目非得用个Nightly
Build工具。大项目只是组件多一些,但每个组件的构建步骤仍然是极其简单的一个make命令搞定的事情!如果可移植性不是很重要,就不需要分布式构建。如果组件之间的依赖关系很复杂,只能说明项目规划差劲。
中小型项目需要Nightly Build吗?项目在开发阶段没有做Nightly Build,现在进入维护阶段了,还需要费劲实现这个吗?按照我的经验,回答都是肯定的。我维护过一个中等规模的针对嵌入式Linux的项目IPCam,大的组件只有两个,其他还有配置文件、初始化脚本等。这个项目的版本文件内容包括两部分:发布说明和目标板上用的Linux根文件系统。这个项目针对不同的目标平台分别构建版本文件。这个项目的版本文件构建步骤比较简单,就是从各个SVN服务器上取出最新版本,编译或者删除.svn临时目录后,替换掉上一版本文件中对应的组件,更新releasenotes,最后打包。就这么简单的步骤,我和同事们往往花15分钟时间小心翼翼地做,但仍然不时地出错,例如忘记了删除.svn临时目录、为某目标平台编译组件时忘记了修改Makefile中相应的选项、不同目标平台的组件弄混了、忘记在发布说明中添加新版本的说明...在我花两三天时间为这个项目编写500多行的Python脚本之后,整个项目组在制作版本文件方面花费的心思从此降为0。
其实实现NightlyBuild机制并不难。编写一个脚本,将其作为一个crond任务于每晚运行即可。在众多脚本语言中,我偏爱Python。Python语法简明并且许多事情都能做得更好。Perl和Shell稍微复杂点的语法就难以理解了(理解是维护的前提),远不如Python好用。
以下介绍我在上述项目中的Nightly Build脚本(涉及项目细节的,为保密起见作了适当修改)。它实现了以下功能:
(1)每晚构建(作为一个crond任务即可)。
(2)无论构建成功与否都有邮件通知。
(3)没有修改的组件不作编译和更新动作。
(4)记录了构建轨迹,即每次构建出的文件版本号与各个SVN库的修订号的对应关系。方便下次构建,也方便事后的问题跟踪。
(5)把自上次构建以来所有的SVN提交动作的log作为本次构建的changelog,放入发布说明中。如果是构建的版本文件需要正式发布(如发布给客户),则changelog需要人工调整一下。
需要说明的是,它并不是一个框架或者库。要修改成框架或者库要花心思,但它目前对我来说够用了。所以如果其他项目要移植这个脚本的话,需要改动一些东西:(1)为每个组件定义一个类实现其特有的构建步骤、更新版本文件中相应组件的操作。(2)修改版本构建步骤,也就是Project::makeRamdisk()方法。(3)修改配置文件build.conf以反映特定的项目-SVN库-组件的3层关系。另外事先要安装svn客户端的Python绑定。 |