第 10 章 创建项目的构建计划

构建计划用于启动或触发构建活动,包括了后台自动触发和手工触发两种方式。

构建需要一个工作目录,该工作目录用来保存从VCS代码库中检出的代码。 下面是Luntbuild构造工作目录的一些准则:

  1. Luntbuild顶层工作目录作为所有的Luntbuild项目工作目录的根目录。

  2. 每个构建计划都允许定义自己的工作目录。默认情况下,该目录位于Luntbuild顶层工作目录下的以项目名命名的子目录下。

  3. 定义了源目录的VCS模块在检出之后,Luntbuild自动在构建计划的工作目录下建相应的子目录,通常情况下子目录结构和 VCS模块的源目录结构一致(除非在定义VCS模块时指定了目标目录)。

例如,如果Luntbuild的顶层工作目录为/luntbuild-install-dir/work, 项目名为myproject,而构建计划子目录定义为myscheduleworkdir, VCS的某个模块的源路径为source, 那么通常情况下source下的内容将会被检出到:/luntbuild-install-dir/work/myproject/myscheduleworkdir/source

为什么构建计划的工作目录这么重要?原因如下:

构建计划的工作目录可以在同一个项目的多个构建计划间共享。 这样这些构建计划的构建就会同一个工作目录,从而可以节省很多磁盘空间。 Luntbuild保证如果多个构建计划共享同一个工作目录,那么这些构建计划不会同时运行。 事实上,如果使用该共享工作目录的第一个构建启动了,那么其他的使用该共享目录的构建就 会进入一个等待构建的队列, 等待前一个构建完成之后才能启动下一个构建。
如果构建计划的工作目录没有和同一个项目的其他构建计划共享,那么项目对应的VCS模块的内容会被多次检出(到多个工作目录), 这样会消耗大量的磁盘空间,而且也会花更多的时间来执行检出VCS模块的操作。 但是这样有个好处就是,(同一个项目里面)不同的构建计划使用不同的工作目录,这样不同的构建计划里的构建可以同时进行。

每个构建实例使用发布目录来输出构建的制品,例如构建日志,版本变更日志,要发布的文件等等。 下面是Luntbuild构建发布目录的一些准则:

  1. Luntbuild顶层发布目录是所有的Luntbuild构建发布目录的根目录。

  2. 在顶层发布目录下是以项目名命名的子目录。

  3. 在项目子目录下是以构建计划名字命名的子目录

  4. 在构建计划子目录下则是以构建版本号为名字来命名子目录。 该目录下包括了构建日志build_log.txt,版本变更日志revision_log.txt, 还有两个子目录artifactsjunit_html_report。 其中artifacts用于存储您的其他输出制品, junit_html_report用于存储单元测试的结果。

例如:如果Luntbuild的顶层发布目录为 /luntbuild-install-dir/publish, 项目名myproject, 构建计划名为myschedule, 当前构建的版本号为myapp-1.2.0, 那么版本myapp-1.2.0的构建发布目录的绝对路径为 /luntbuild-install-dir/publish/myproject/myschedule/myapp-1.2.0.

点击Schedules(构建计划)标签,然后点击该页右上角的New Schedule(新建构建计划)图标,即可新建一个构建计划。

Schedules Editor Tab(构建计划编辑页面)

Name(名字)

构建计划的名字,该名字用于标识构建计划。

Description(描述)

在此提供对该构建计划的一些描述信息。

Next build version(下一个构建版本)

在此指定下一个构建版本的字符串。Luntbuild会在构建的过程中自动增量式修改该字符串的版本号部分。

luntbuild-1.0 会增加到 luntbuild-1.1
luntbuild-1.2.9 增加到 luntbuild-1.2.10
luntbuild-1.5(1000) 增加到 luntbuild-1.5(1001)

通常情况下,每次构建下一个构建版本的最后一个数字都会增加。 例如三次构建之后"luntbuild-1.2.0" 会增加到 "luntbuild-1.2.3"。 但是,如果在该字符串中嵌入了OGNL表达式(以${...}括起来),那么最后一个数字就不会自动增加了。 取而代之的是,Luntbuild会根据特定的构建计算出每一个嵌入的OGNL表达式的实际值。 在执行计算的过程中,当前的Schedule 对象会作为该OGNL表达式的根(root)对象。 下面的例子展示了使用OGNL表达式获取不同的版本号的策略:

场景1:将当前的日期和迭代次数作为构建版本号的一部分 Scenario 1: Put current date and iteration of this date as the part of the build version

将每个构建计划的下一个版本号定义为:

                    foo-${#currentDay=system.(year+"-"+month+"-"+dayOfMonth), #lastDay=project.var["day"].setValue(#currentDay), \
                    #dayIterator=project.var["dayIterator"].intValue, project.var["dayIterator"].\
                    setIntValue(#currentDay==#lastDay?#dayIterator+1:1), #currentDay}.${project.var["dayIterator"]}
                

最终,某个构建的实际版本的字符串将包括构建的日期和当天迭代的次数。

场景2:测试和发布构建计划共享和共同增加相同的版本号字符串, 而持续集成构建则使用另一个独立的版本号。

测试和发布构建计划的下一个构建版本都设置为:

	foo-${project.var["majorVersionPart"]}.${project.var["minorVersionPart"].increaseAsInt()}

对于持续集成构建计划,将下一个构建版本设置为:

	foo-1

场景3:发布构建计划增加版本号的发布有关的部分,而每夜构建计划增加版本好的迭代有关的部分。 当发布有关的部分改变的同时,迭代部分重置为1。

定义以下项目的变量:

fixPart=foo-1.1
releasePart=1
iterationPart=0

定义每夜构建计划的下一个版本号为:

${project.var["fixPart"]}.${project.var["releasePart"]} build ${project.var["iterationPart"].increaseAsInt()}

定义发布构建计划的下一个版本号为:

${project.var["fixPart"]}.${project.var["iterationPart"].setValue(1), project.var["releasePart"].(increaseAsInt(), value)}

This way, builds in "release" schedule will get versions like: foo-1.1.1, foo-1.1.2, foo-1.1.3, ..., and builds in "nightly" schedule will get versions like: foo-1.1.1 build 1, foo-1.1.1 build 2, foo-1.1.1 build3, ...., foo-1.1.2 build 1, foo-1.1.2 build2, ...

注意

在计算OGNL表达式的值的时候,Luntbuild会替换所有的"."字符串为"_",所有的空格则被替换为"-"。 该构建的版本号字符串会用作给VCS系统中相应的源码打标签的值。 例如,如果构建的版本号是"v1.0 build256",该构建对应的源码会被打上名为"v1_0-build256"的标签。

注意

Luntbuild基于版本号给源码打标签。如果在Luntbuild里面存在多个项目,或者配置了多个构建, 那么您要确保没有重复定义的版本号字符串。 例如,如果您给build1的下一个构建版本配置为"v1.0",build2的下一个构建版本号为"v1.5", 如果者两个构建使用同一个VCS和包括了同样的模块,那么可能在5次或者更多次构建之后,build1和build2的版本号就会相同了, 这样我们就无法区分相应的源码,因为它们有相同的标签。

Work directory(工作目录)

在此设置构建计划的工作目录。如果设置的不是绝对路径,那么就假设是相对于该构建计划所属项目的工作目录。 如果该属性为空,那么系统使用项目工作目录,即:<global_work_dir>/<project_name>。 其中<global_work_dir>是Luntbuild的顶层工作目录,<project_name>是构建计划对应的项目的名称。 默认的工作目录可能造成同一个项目的多个构建计划使用同一个工作目录。 See build work directory 查看工作目录.

Trigger type(触发器类型)

选择构建计划的触发器类型。如果选择"manual"(手工)那么意味着构建计划的构建任务只能通过手工触发。 "simple"则周期性触发(定义一个时间间隔,每隔多少分钟触发一次)。 "cron"则用来定义cron风格的触发器。关于怎么配置cron触发器的详情请参考 http://www.opensymphony.com/quartz/

Cron expression(Cron表达式)

设置构建计划的cron表达式,格式为 <seconds> <minutes> <hours> <day-of-month> <month> <day-of-week> 例如

0 1 * * ?

的意思是每天的早上1点。 关于该格式的详情,请参考 Cron触发器指南.

Repeat interval (minutes)(时间间隔(单位:分钟))

在此设置构建计划实施的时间间隔,单位为分钟。

Build necessary condition(构建必要条件)

该属性可选。如果为空,那么默认值为"vcsModified or dependencyNewer"。 Luntbuild使用构建必要条件来决定当前构建是否有必要进行。 构建必要条件是一个OGNL表达式。当该表达式的值为true的时候,就认为构建有必要进行。 该OGNL表达式的根对象是当前的 Schedule对象。 下面的例子展示了是OGNL表达式的格式:

  1. vcsModified - 如果当前构建要访问的代码库的内容发生了改变那么认为该表达式的值为true。

  2. dependencyNewer - 如果依赖的构建计划更新了,那么该表达式的值为true

  3. dependencySuccessful - 如果依赖的构建计划里的最新构建都成功了,那么该表达式的值为true

  4. always - 其值总是为true,用于强制运行构建

  5. never - 其值总是为false,通过设置该表达式来停止构建

  6. alwaysIfFailed - 如果上一次构建失败了,那么该表达式的值始终为true, 如果上一次构建成功了,那么该表达式的值和"vcsModified or dependencyNewer"一致。

  7. project["testcvs"].vcsModified - 如果项目"testcvs"对应的代码库的"development"视图的值改变了,那么该表达式的值为true。

  8. execute("/path/to/command.sh") == 0 - 如果指定的命令执行的返回值为0,那么该表达式的值为true

    注意

    一些特殊的符号,例如'\', '"',应该在前面使用'\'符号,这和java字符串语法是一致的。

以上的表达式都可以加上'!'前缀,用来求相反的值, 例如如果当前项目代码库中的代码没有变化那么!vcsModified的值为true。

以上的表达式可以使用"and"和"or"逻辑运算符组合成新的表达式。例如表达式 vcsModified or execute("/path/to/command.sh")==0, 如果项目代码库中的代码发生了变化,或者指定的命令运行的返回值为0,那么该表达式为true。

关于OGNL表达式的语法请参考 http://www.ognl.org

Associated builders(该构建计划使用的builder)

选择当前构建计划要使用的builder。执行顺序和选择的顺序一致。

Associated post-builders(该构建计划使用的post-builders)

选择当前构建计划要使用的post-builders。 在"post-build strategy"设置了合适的值(post build strategy属性),那么在所有选择的builder执行完 后就会执行这里选择的post-builders。

Build type(构建类型)

选择构建计划的构建类型,完整构建(clean build)相对可靠,但是速度更慢。 增量式构建(Incremental build)速度快,但是没那么可靠。 我们建议所有重要的构建计划例如日构建和发布构建都应该使用完整构建,而那些 频繁的构建计划,例如每小时构建使用增量式构建。

注意

该设置只有构建不是手工触发的时候才有效。

Post-build strategy(Post-build策略)

设置构建计划的Post-build策略,目前支持的策略如下:

do not post-build(不运行post-builders)

构建完成后不执行前述的post-builders。

post-build when success(成功后运行post-builders)

只有构建成功后才运行前述的post-builders。

post-build when failed(失败后运行post-builders )

只有构建失败后才运行前述的post-builders。

post-build always(无条件运行post-builders )

构建之后无条件运行post-builders

注意

该设置只有构建不是手工触发的时候才有效。

Label strategy(标签策略)

选择构建计划的标签策略。Luntbuld提供了以下策略:

label successful builds(给成功构建的代码打标签)

只给那些成功完成的构建对应的代码库打上相应的标签。

do not label(不打标签)

不论成功失败,构建结束后都不会打标签。

label always(无条件打标签)

不论成功失败,构建结束后都会打上标签。

注意

如果在第一次构建的时候不打上标签,那么产生的构建以后将不能够进行重新构建(因为 如果不打标签的话,Luntbuild无法断定特定构建所对应的源代码)。

注意

该设置只有构建不是手工触发的时候才有效。

Notify strategy(消息通知策略)

选择构建计划的消息通知策略。Luntbuld提供了以下策略: Choose the notify strategy for this schedule. There are following strategies:

notify when status changed(状态改变时发送通知)

如果当前构建和上一次构建的状态相比有变化的话就发送消息通知。 也就是说,如果上一次构建失败,而本次构建成功,或者上一次构建成功,本次构建失败,这些情况下都会发送通知。

notify when failed(构建失败时发送通知)

构建失败时发送通知

notify when success(构建成功时发送通知)

构建成功时发送通知

do not notify(不发送通知)

构建结束后不发送通知

notify always(无条件发送通知)

无论构建状态如何,结Ĉ