Cruisecontrol CruiseControl Enterprise 最佳实践

liuxue.gu@hotmail.com · 2010年04月23日 · 7 次阅读

CruiseControl Enterprise 最佳实践 (1) : Publish with a Publisher ©Copyright 2007 Julian Simpson. All rights reserved.

英文原文: CruiseControl Enterprise: 10 Best Practices

I'm an Infrastructure Specialist at ThoughtWorks. In my role I make sure that we are building our software so it can successfully be deployed to production. In this series of blog posts I hope to pass on my top ten tips for using CruiseControl Enterprise effectively. I'm writing these with the developers or systems administrators in mind: the people who most often manage CruiseControl. However, I hope that anybody who is interested in Continuous Integration will get something from these articles.

1: Publish with a Publisher : 使用 Publisher 来发布, 而不是在构建过程中发布

许多项目都会用到"发布"的概念: 把构建产物放到指定地方, 或者把测试结果发送给最终用户. ArtifactsPublisher 就是一种很常用的方式, 用来把文件发布到 CruiseControl 自己的时间戳目录形式的仓库中, 这样构建日志, 构建产物和测试结果等就可以通过新的 CruiseControl Dashboard 或者传统的 CruiseControl Reporting 应用展现出来.

ArtifactsPublisher 不过是整个 Publisher 家族中的一员, 而我的最爱是 AntPubliisher. 如果你的 Ant 构建以发布构建产物到仓库中或者给你的版本控制系统打 Tag 来结束, 那么或许应该用另外的方式来做这些事情. 考虑下面的 CruiseControl 调用的 Ant 脚本例子:


构建的最后一步是通过 "publish" target 发布通过了单元测试的工作产物到某个仓库或类似的地方. 这对于 CruiseControl 来说不错, 很好, 但是, "发布"的概念并不真正适合在开发者的构建过程中使用. 如果我们能够断开"发布"和构建过程的其它部分之间的联系, 开发者就能够和 CruiseControl 使用一模 一样的构建过程. 要想这样做, 只需要让 CruiseControl 来调用你开发过程中使用的构建脚本, 而把"publish"作为一个独立的 Ant target:

'publish' target 中的 'if' 属性用来保证这个 target 只会被 publisher 或某个特定的人来运行. 接下来, 只需改动一下 CruiseControl 的配置:

OK, 这就做完了. 一旦你应用了新的配置, CruiseControl 就会运行和开发者一模一样的 Ant 构建. 这意味着构建失败时并不是因为 "CruiseControl" 做了什么神秘的事. 这还有助于通过更快的报告成功或失败来缩短构建的反馈周期. 当开发者在庆祝或郁闷于构建的成功或失败时, AntPublisher 在同一时间继续做着把构建产物发布到网络上的工作. 我还用它来为 codebase 打 tag, 如果构建成功的话 -- 这件事也是"持续集成"的一部分.

Publishers 能够被直接用在配置文件的元素中, 这样每次构建结束后无论成功失败都会运行. 也可以包在或中有条件的运行.

Publishers 有一个堂兄妹表姐弟叫 Bootstrappers, 我另外找时间说说它.


我想这个实践的好处就是

  1. 开发者每次在自己机器上构建时不需要发布, 省时间
  2. CruiseControl 使用跟开发者相同的构建脚本, 减少了开发者构建成功而 CruiseControl 构建失败的概率, 省调试时间
  3. CruiseControl 运行 Publisher 时开发者可以继续工作了, 提高了并发性, 还是省时间

作者:李光磊 转载:http://blog.csdn.net/gongflow/archive/2007/10/11/1820939.aspx

©Copyright 2007 Julian Simpson. All rights reserved.

英文原文: Keep your dependencies to yourself

I'm an Infrastructure Specialist at ThoughtWorks. In my role I make sure that we are building our software so it can successfully be deployed to production. In this series of blog posts I hope to pass on my top ten tips for using CruiseControl Enterprise effectively. I'm writing these with the developers or systems administrators in mind: the people who most often manage CruiseControl. However, I hope that anybody who is interested in Continuous Integration will get something from these articles.

2: Keep your dependencies to yourself : 让 CruiseControl 和你的 Project 各走各道, 互不相干

平均规模的 Java 项目会有很多依赖: 开源的工具和框架, 第三方的库, 你的项目或组织内部开发的库...等等等等. 我数了数我目前项目中依赖的 (或者可能依赖的 :) ) jar 文件, 有 84 个. 更多的痛苦来自于你管理这些依赖的方式. 让你的软件能够编译或执行通常比你想象的要困难的多, 如果这些依赖不清楚的话. 加入一个新项目, 然后用一天的时间让你的代码从不清楚的代码或环境依赖中成功编译真是充满了痛苦. 让 CruiseControl Enterprise 和它的依赖 从 你自己的项目和项目依赖中清楚地分离出来, 是一个很好的主意. 最基本的例子, 可以让你的 CruiseControl Enterprise 安装像下面这样布局:

|-- cruise | |-- 2.7.0 | |-- 2.7.1 |-- logs | |-- blowfish | |-- scorpion |-- projects | |-- blowfish | |-- scorpion

这样升级 CruiseControl Enterprise 应该只是几分钟的事. 如果你发现你需要往 CCE 本身加入额外的库, 通常这是一个警告信号, 意味着你的项目不能满足自我依赖. 仅有的例外是当你用自定义的 bootstrapper 或 publisher 等来扩展 CCE 自身的时候.

这里有两点尤其需要注意: 日志文件和 '.ser' 文件. 日志文件代表了你的项目的历史, 这就是我为什么一直努力把它们保存在与 CruiseControl 安装目录不同的目录层次中. 另外, 缺省情况下, CruiseControl 还把项目的状态信息持久化到后缀名为 '.ser' 的文件中. 确保升级的时候你保留了它们. 如果你这么做了, 你的项目又不依赖于 CCE, 那么就能很容易的升级 CCE.

接下来, 考虑一下那些熔入到你的构建工具中的依赖. 有一个常用的模式是把依赖都放到你的 Apache Ant 的 'lib' 目录中. 这样做对诸如 Junit 之类一般不会被你的产品代码依赖的库没问题. 但如果你的产品代码或构建脚本依赖的库实际上贮存于你的构建工具内部时, 你就有麻烦了. 它今天可能还工作, 但明天就不一定了. 如果你升级了构建工具中你的代码依赖的那些库, 有可能你就构建不了以前的代码了. 这让事情变得很"有趣", 尤其是当你正试图通过升级依赖库解决一个产品中的 Bug 时. (升级后能构建最新的代码, 但不能构建以前的代码)

好消息是, 这很容易解决: 让你的项目包含自己的依赖. (让你的构建脚本显式的引用包含在项目内部的依赖, 而不是隐式的让构建工具来包含那些依赖). 比如说, 如果你的 Ant 脚本依赖于 Oracle, 而你的项目使用的 Ant 包含了 Oracle 的驱动, 那么你的脚本看起来像这样:

在这个例子中, 对于 Oracle 驱动的依赖没有被明确的声明, Ant 只会从缺省 classpath 中寻找 "oracle.jdbc.driver.OracleDriver". 第一件要做的事就是把驱动所在的 jar 文件扔到 project 内部并设置一个 classpath:

lib/ `-- ojdbc14.jar

注意'sql'元素中这个额外的 'classpathref' 属性. 这个有用的属性允许你引用脚本中在别处定义的路径, 减少了重复代码. 当你把一个依赖移到项目内部时, 要在可以删除的时候正式的删除这个依赖. 在我最近采用这种过程的一个项目中, 我很幸运的能够以我喜欢的方式进行定期发布. 我修复了 trunk 中的依赖, 并且几周后进行了重新检查. 以前那种依赖于项目外部某些东西的 release branches 没有被使用.

因此概括的说, 考虑一下你项目的依赖项, 包括那些只是凑巧被满足的依赖项. 如果你让那些依赖都很清楚直观, 我保证你会更少的被你的同事追问为什么他们不能编译! 如果你有许多工程有相同的依赖, 我希望在后续的文章中会解决一些问题.

CruiseControl Enterprise 最佳实践 (3) : Configuring CruiseControl the CruiseControl way

©Copyright 2007 Julian Simpson. All rights reserved.

英文原文: Configuring CruiseControl the CruiseControl way

I'm an Infrastructure Specialist at ThoughtWorks. In my role I make sure that we are building our software so it can successfully be deployed to production. In this series of blog posts I hope to pass on my top ten tips for using CruiseControl Enterprise effectively. I'm writing these with the developers or systems administrators in mind: the people who most often manage CruiseControl. However, I hope that anybody who is interested in Continuous Integration will get something from these articles.

3: Configuring CruiseControl the CruiseControl way : 用 CruiseControl 的方式来配置 CruiseControl.

你刚刚开始使用 CruiseControl, 你用一个版本控制系统来管理你的代码, 你把 CruiseControl 安装在办公室里一台空闲的机器上. 一切都很不错, 你的代码改变后它能够立刻给你反馈. 然后那台空闲机器上的硬盘完蛋了, 于是你的这台构建服务器只好继续着它以前空闲时门闩的角色.

"没问题", 你想: "所有的代码改变都在版本控制系统里, 我们能够重新生成任何我们需要的构件. 事实上, 我们需要的仅仅是那个配置文件 ...". 是的, 那个配置文件. 那个硬盘上的配置文件再也不能工作了. 这篇 blog 将简略叙述一下如何管理你的 CruiseControl 的配置而不必害怕失去它. 像许多工具一样, CruiseControl 将会失去作用, 如果没有配置的话.

在 ThoughtWorks 之前的项目中, 我们老是需要给予某个人访问构建服务器的权限, 来修改 CruiseControl 的配置. 一旦项目壮大到不再是少数几个 Developer, 让每个人都熟悉项目的安装配置就会变得很困难. 最终往往是某个人 (有时是我, 你卑微的讲述者) 变成了项目专职的 CruiseControl 管理员. 这种情形就为开发团队制造了一个瓶颈: 所有对 CruiseControl 的修改都汇集到一个人那里等待处理.

改善这种情形的第一步就是想办法让 CruiseControl 自己来应用配置的改变. 让我们开始吧. 除了那些来构建和测试你代码的, 你还可以有一个专门的来把配置改变应用到构建服务器. 我们一直这么做, 把配置文件放到正确的地方, 当它们改变的时候就使用 CruiseControl 的 plugin 来更新配置 :

<?xml version="1.0"?>

<currentbuildstatuslistener file="/var/spool/cruisecontrol/logs/${project.name}/

currentbuildstatus.txt"/>

<ant antWorkingDir="/etc/cruisecontrol" antscript="/var/spool/cruisecontrol/tools/apache-ant-1.6.5

/bin/ant" uselogger="true"/>

<artifactspublisher

file="${project.name}/build.log"

dest="logs/${project.name}"/>

这将机械的更新配置, 直到世界末日. 它简单却相当有效, 现在我们不再依赖那个能够更改 CruiseControl 的家伙了. 突然之间他们就不需要代表团队中其他人来做些琐碎的更改了, 因为每个人都可以安全的改变配置. 如果有人确实 check in 了一个有问题的配置文件, 没关系, 一切都在版本控制系统中. 你可以 revert 这次改动, 可以找到是谁做的修改, 可以试着理解为什么他们想这么改.

这前进了一大步. 但是如果你 check in 了一个有问题的配置, 它还是会被应用到 CruiseControl. 幸运的是 CruiseControl 有很好的判断力不去应用有问题的配置, 但这将使你失去重要的反馈. 对于这个问题, 你需要自己写一个简单的 validator, 像下面这样:

package org.juliansimpson;

import java.io.File;

import net.sourceforge.cruisecontrol.CruiseControlException; import net.sourceforge.cruisecontrol.config.XMLConfigManager;

import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task;

public class ConfigValidator extends Task { public String configFile;

public void execute() throws BuildException { try { File file = new File(configFile); new XMLConfigManager(file); } catch (CruiseControlException e) { throw new BuildException("Invalid CruiseControl Config"); } }

public void setConfigFile(String config) { configFile = config; }

}

这个 validator 使用 CruiseControl 自己内部的一个类来校验配置. 最好是能有一个公开的接口来做这件事 -- 可以是一个命令行选项或者一个"官方"的 Ant task. 我请求过 CruiseControl Enterprise Team 在以后的 release 中考虑一下这个问题. 这种校验方式确实意味着你需要设置一下 classpath, 以便让你的 validator 能够找到它引用的来自 CruiseControl 内部的类. 但是你会发现它确实能够保证目前的配置对于你正在使用的 CruiseControl 版本来说是有效的. 我倾向于以 Ant task 的方式来运行校验. 它非常简单, 并且每个人都能很容易的看到它做了什么. 下面是我把它放在一个简单的 Ant 脚本中:

<copy file="${config}" todir="${cruisecontrol.dir}" failonerror="true"

description="Copy configuration to CruiseControl server" />

<get src="http://localhost:8000/invoke?operation=reloadConfigFile&ampobjectname=CruiseControl+Manager%3Aid%3Dunique;"

dest="${build.dir}/reload.html" />

它们合在一起像下面这样工作: CruiseControl 的 BootsStrapper 获取最新的配置文件, 但是放在不同于 CruiseControl 安装目录的目录中. 你依然还不清楚它是否是一个有效的配置文件. 然后"validated-config" target 会调用 ConfigValidator 这个 Ant task.这将调用到 CruiseControl 中足够的逻辑来确保配置是合法的,并且配置文件中涉及到的一些目录都存在.如果通过了这一步,那么 "publish"target 就会把配置拷贝到 CruiseControlserver 自身的目录中覆盖原来的文件.最后还是 "publish"target 会发一个简单的 Http 请求到 JMX 接口,来强制 CruiseControl 来重新加载一下配置.这将确保新配置会立即被 加载,这样 team 就会知道新配置是合法的.谢谢我的同事 Tim Brown 的这个非凡的主意.

我不得不承认有时我会不小心弄坏 XML 配置文件. 这种方式对我来说工作的尤其好, 因为我有校验的保护网. 我对我的邮件服务器和 web 服务器做了相似的事情, 希望很快能有机会写一下它们. 文中 validator 的源代码和构建脚本可以在我的网站上下载: http://www.juliansimpson.org/.

©Julian Simpson 2007. All rights reserved.

我想这个实践的核心是:

1, 将 CruiseControl 的配置文件 check in 到版本控制系统中, 以解决意外损坏的问题

2, 使用专门的"project"来自动更新配置, 以解决每次需要有人专门登录到 build server 上去更新的瓶颈问题.

3, 复用但不依赖于 CruiseControl 对配置文件的 validation, 以同时获得 "阻止有问题的配置文件被应用到 build server 的能力" 和 "迅速获知有人 check in 了有问题的配置的能力"

©Copyright 2008 Julian Simpson. All rights reserved.

英文原文: Bootstrap with a Bootstrapper

I'm an Infrastructure Specialist at ThoughtWorks. In my role I make sure that we are building our software so it can successfully be deployed to production. In this series of blog posts I hope to pass on my top ten tips for using CruiseControl Enterprise effectively. I'm writing these with the developers or systems administrators in mind: the people who most often manage CruiseControl. However, I hope that anybody who is interested in Continuous Integration will get something from these articles.

4: Bootstrap with a Bootstrapper

在我上次的文章中, 我演示了如何使用 bootstrapper 来确保 CruiseControl 的配置文件是最新的. 在这篇文章中我会继续讨论这个话题. 这里便是导致在 CruiseControl 中引入 Bootstrapper 的问题: 当你破坏了你的构建脚本时你如何修复你的构建?

想象一下这种情形: 你欢天喜地的对构建脚本做了点修改来支持一个新的特性. 你的同事 Bob 走到你的桌旁想讨论一下这个特性先. 但他并不能阻止你完成这个特性的热情. 无论如何你都几乎已经快做完了. 于是你迅速的 check in, 然后转过身在 Bob 提到钓鱼之前拉着他聊工作.

于是最终 Bob 逛到饮水机旁去诱陷别人, 而你回来继续工作. 你看了一下显示你构建结果的界面, 它居然是红的! "业余的家伙们", 你想. "他们总是弄坏构建". 你刷新了一下 CruiseControl Dashboard 来检查一下这次构建中有哪些 checkin (这里每个人都很频繁的 check in). 最终你发现构建在一秒钟之内就失败了, 因为 build.xml 是非法的.

突然之间多了点对你的构建破坏者同事们的容忍, 你盯着那个 build.xml, 它依然显示在你的 IDE 里面. 就是它了, 文件结尾处有一个多余的大大的 '#' 号. "诅咒这键盘布局", 你叫嚷着. 当你输入文件的最后一行时, 你错过了回车键而敲了个 '#'. 你匆匆忙忙 check in 的时候没有发现它, 而现在构建脚本不会更新 checkout 了. 构建脚本根本就不会运行, 因为它是非法的. 通常情况下它做的第一件事就是更新 CruiseControl 服务器上的源代码工作拷贝来得到最新的修改. 看起来你得 check in 你的修复, 然后到 CruiseControl 服务器上手动更新工作拷贝. 噢!

曾经干过这些事 (有时根本不需要假想一个同事来破坏构建脚本), 因此我可以为 "bootstrapper"这种方法做担保:

<?xml version="1.0"?>

在上面的例子中, bootstrapper 会始终从 Subversion 中抓取最新的文件. Bootstrapper 在构建发生之前运行, 不管构建是否必要, 但是如果 project 被暂停了则不会运行. 但何必到此为止呢? 这将确保你能拿到最新的构建脚本, 而后者将负责从你的版本控制系统中获取最近的更新. 但是你的构建脚本需要做这些事吗? No, Bootstrapper 可以更新所有的工作拷贝, 如果你像这样配置它的话:

现在 CruiseControl 将更新服务器上的工作拷贝中所有最近更改过的文件.

关于这种方法, 过去有个问题 - Bob 会抱怨说: "这就像我钓住了一条 10 磅的鱼, 但是线却断了. 我提交了我的修改, 然后看见一次构建被触发了. 我等到构建结束. 我的更改信息出现在了更改信息列表中, 但是 QA 人员说我的修改根本就不在这次构建中! "

这个问题通常发生在你 check in 的时候 CruiseControl 正在 bootstrapping 以获取最新的版本. 由于最初的那段和不支持原子提交的版本控制系统一起工作的历史, CruiseControl 内部使用日期/时间来引用修改集. 在 CruiseControl 2.7.1 中, 来自 ThoughtWorks Studios 的 CCE 团队修正了这个问题. 他们在 Subversion modification set 中引入了一个 "useLocalRevision " 属性:

一旦 bootstrapper 更新了 CruiseControl 服务器上的工作拷贝, 它就使工作拷贝的 svn 版本号对 ModificationSet 来说是可用的了. 当 ModificationSet 试图计算出这次构建中哪些修改是新增的时候, 它就会限制它的查询只查到工作拷贝的版本号. 这就使 CruiseControl 准确的报告修改. 它对于使用 CruiseControl 的大项目来说是一个巨大的进步. 这也将把你从与 Bob 的更多次谈话中解救出来. 上的 "useLocalRevision" 另一个有用的副作用是 svn 的版本号能够作为一个叫做"${svnrevision}"的属性传递到构建中. 这就使稍后用正确的版本号给这次构建打标签变得易如反掌.

当我们涉及 CruiseControl 和 Subversion(或者任何真正支持原子提交的版本控制系统) 捆绑工作的时候: 永远不要使用 QuietPeriod. QuietPeriod 是在当你使用 CVS 或者其它不支持原子操作的版本控制系统的时候, 用来避免 CruiseControl 过早构建的. 它只会拖慢你的构建.

有更多的 bootstrapper 可用来做一些有意思或有用的事: CruiseControl 支持很多版本控制系统. 它们中的大多数都带有一个可选的 bootstrapper. Bob 和我前面已经描述了版本控制系统的 bootstrapper 的用处, 下面简单的说一下剩余的几个:

*

AntBootStrapper 会在构建开始之前执行一个 Apache Ant 脚本文件. 大部分情况下你用不到这个, 但是我曾经见过用它来获取依赖项, 如果依赖项有变化的话就会触发一次构建 *

ExecBootStrapper 会执行任何你告诉他的脚本或命令 *

LockFileBootStrapper 比较有意思. 继续往下读

你有很多项目运行在同一个 CruiseControl 服务器上? 很好. 你配置了两个或更多的构建线程? 你有两个或多个项目同时构建? 太好了. 多个, 并发的项目是 CruiseControl 从 2004 年夏天开始支持的特性. 什么? 其中的两个项目有时会竞争相同的资源? 噢, 这不好. 尤其烦人如果它只是一天或一段时间只发生一次. 你可以这样做:

lockfilebootstrapper 会在构建开始之前运行, 就像 bootstrapper 应该做的那样. 它将在 "lockfile" 属性指定的文件中查找项目的名称. 如果 "lockfile" 指定的文件存在, 并且里面的项目名称和在配置中设置的期待不匹配的话, 它将取消整个构建企图. 这样的话, 一个项目就可以警告其它项目说我正在构建, 而你永远也不会看到两个不能坐在一起的项目在同时构建. 然而你其它的那些不与第一个项目共享相同外部依赖的项目则可以同时运行. lockfilelistener 会在构建之后清除任何旧的 "lockfile", 这样的话你就不会永久性的阻止某些构建的运行.

"等等", Bob 说, "我刚刚不得不花了 10 分钟来等待 FooLib 项目得到构建! 这怎么办?" "Bob," 你并非不近人情的说: "你知道我们只有一台集成测试服务器. 现在它用来运行 CruiseControl. 下次你和 CTO 一起钓鱼的时候, 你可以告诉他项目的延迟, 再问问他我们能否花点明年的预算再购买一台测试服务器. "

©Julian Simpson 2008. All rights reserved.

 

在 bootstrapper 概念之前, CruiseControl 只是检查源代码是否有修改, 不会更新源代码工作拷贝, 通常都是用户的构建脚本来负责更新源代码. 而 bootstrapper 最开始的设计意图就是作者在文中提到的那样, 只是用来更新构建脚本, 再由构建脚本负责更新源代码. 这在一些 bootstrapper 文档中可略见端倪. 只是人们马上就发现 boostrapper 可以用来更新所有源文件, 进而可以用来在构建之前做任何事情.

其实 bootstrapper 和 publisher 是一对兄弟, 分别用来在构建前后插入用户定义的操作, 就像 AOP 里的 before/after 一样.

See also:

1.

<> 2.

<> 3.

<> 4.

<>

 

hi Julian, have a good desk !

©Copyright 2008 Julian Simpson. All rights reserved.

英文原文: Refactor your configuration file

I was an Infrastructure Specialist at ThoughtWorks. In my role I make sure that we are building our software so it can successfully be deployed to production. In this series of blog posts I hope to pass on my top ten tips for using CruiseControl Enterprise effectively. I'm writing these with the developers or systems administrators in mind: the people who most often manage CruiseControl. However, I hope that anybody who is interested in Continuous Integration will get something from these articles.

5: Refactor your configuration file

请告诉我在计算机系统中重复是一件好事. 我谅你也不敢. 给我你的意见, 我们可以讨论它. 我就是那个在过去十年中, 把最好的时光花费在系统管理, 运行别人代码上的人. 这样一来你可能会猜出我是"重复是魔鬼"俱乐部的持卡会员. 如果你不是会员的话, 这可能不是给你看的文章.

重复不只是蔓延到你的业务代码中. 当你不注意的时候它同样会渗透到构建和持续集成系统中. 很可能你的团队中有个家伙就正在拷贝粘贴点什么东西到构建中. 没必要着急去阻止他们. 继续往下读你就会发现如何把 CruiseControl 的配置拉回正确的轨道.

这里有个关于重复的例子. 你可以看到文件中有大量的重复. 我并不是一字不差的把它从某个项目中拿出来讲 (我愿意在一个叫做 Groucho 的项目中工作), 不过它离真实生活中的情景也差不多.

<?xml version="1.0"?>

幸运的是, CruiseControl 中有办法来消除这种重复

CruiseControl 从 2005 年开始就支持在 config.xml 中使用属性. 他们被设计成 Apache Ant 风格的属性, 使用美元符号和花括号: ${cruise.home}. 这个特性立马就可以用来替换你的 config.xml 中常数类的值, 比如你 Ant 脚本的位置和日志文件的目录

这是一个巨大的进步, 但还不够. 那些在配置文件本身里面定义的东西怎么办? 比如项目的名字? 作者已经提前考虑到这一点了: 有个魔法属性叫做"${project.name}"可以供你使用. 它的解释被限制在包含它的项目内, 这样你就不会在 chico 项目中引用到 harpo, 反之亦然.

来看一下引入这些属性后配置文件的样子: <?xml version="1.0"?>

看起来好多了. 如果你想改变项目的名称, 或者它引用的某个路径, 你只需要修改一个地方. 但是依然有某些样板一遍又一遍的重复着. - 也许我们可以做的更好.

属性其实有更多魔术. ${project.name}动态的随着包围着它的项目的改变而改变. 你不仅能够把它用在配置值中, 你还可以把它定义为另外某个属性值的一部分. 这对你长期忍受的配置文件来说意味着你可以为所有的项目路径声明 一个 属性, 让它惰性求值来适应每个项目. 这可能引起你的同事的困惑, 当他们第一次看到这个配置文件的时候 - "同一个属性怎么能够在这么多不同的情况下都工作呢?"

<?xml version="1.0"?>

大点儿的项目中经常发生的一件事是配置文件变得很庞大. 虽然你可以做些用 XSLT 来生成配置文件之类的事 (这种方法曾经弄得我很头疼), 但实际上你能够把配置文件分散到小文件中. 在 CruiseControl 的配置文件中这个强大的特性叫做 - 它允许你引用另外一个配置文件. 它和 Ant 中的功能很像. 最终你维护着一个 config.xml 文件, 里面包含了变量定义 (它们对于 include 进来的文件也生效), 和一堆小配置文件, 里面包含单个项目的定义. 在我现在的项目中这个特性让添加和移除项目变得非常容易. 甚至当有人删除了一个小配置文件却忘了移除对应的 的时候也没问题 - 文件不存在的时候它就不会被导入进来. 跟踪 CruiseControl 配置文件的改变也变得容易很多.

下面是现在的配置文件:

<?xml version="1.0"?>

这里是其中一个项目: <?xml version="1.0"?>

希望这能帮助让你的 CruiseControl 的配置文件更容易维护. 我相信持续集成应该很简单, 即使这会让我失业.

©Julian Simpson 2008. All rights reserved.

------流行的分割线------

其实 Julian 忘了说 CruiseControl 的另外一种机制: 用来定义项目模板:

<?xml version="1.0"?>

如果结合模版和 include.projects, 最终的配置文件可能会非常简单; 只不过 CruiseControl 有一种限制, 模版必须在主配置文件中定义才有效.

©Copyright 2008 Julian Simpson. All rights reserved.

英文原文: Scaling up

I was an Infrastructure Specialist at ThoughtWorks. In my role I make sure that we are building our software so it can successfully be deployed to production. In this series of blog posts I hope to pass on my top ten tips for using CruiseControl Enterprise effectively. I'm writing these with the developers or systems administrators in mind: the people who most often manage CruiseControl. However, I hope that anybody who is interested in Continuous Integration will get something from these articles.

6: Scaling up

第 一件要做的事就是确保你可以同时构建你的多个项目. CruiseControl 使用 Java 线程来管理构建和项目. 每个项目都有自己的项目线程. 而至少有一个构建线程来真正的运行一次构建. 实际上有一个构建队列, 来调度从项目线程到发到构建线程的请求. 你要给 CruiseControl 足够的构建线程来运行: 缺省情况下只有一个构建线程. 它的影响就是如果你配置了 5 个项目, 你也只能一次构建一个. 这也可以接受, 如果你只有一台很弱的构建服务器, 或者项目之间不能和平共处.

另一方面, 如果你有强大的计算能力可以使用, 你就可以从额外的构建线程中得到提速. 正确的线程数量设置会随着时间而变化; 不要不情愿去做性能管理来找到你的服务器的最优的设置.

Jeffrey Frederick 则明智的指出设置多于项目个数的构建线程数是没有意义的.

在 调优你的持续集成服务时, 还有大量的其它因素可以考虑: 你的版本控制系统的速度, 你在哪里存储你的构建产物, 日志, 等等. 今天我要提到的一个因素是硬盘带宽. 编译软件是一个很耗硬盘的过程. 即使构建已经完成了编译 Java 代码和打包 jar 包等操作, CruiseControl 还得写日志文件. 所有这些事情很容易就会让单个硬盘满负荷运转. 理想情况下你想确保你的机器能够一次构建多个项目.

在 我很早期的一个 ThoughtWorks 项目中, 我们的团队运行了两个 CruiseControl 服务器, 显然是因为最初的那个 Solaris 服务器太慢了. 对我来说这看起来不对劲. 于是我深入的看了一下. 依靠我的系统管理员背景, 我发现了某个硬盘 100% 的忙于运行操作系统, CruiseControl 和构建. 我把工作负载分布到系统中的四个硬盘上, 然后那台机器就能管理多得多的项目了.

在我后续的项目中, 这个模式不断的重复. 以我的经验, 没有多少 CI 服务器是因为处理器过载而受到限制. 不幸的是, 一旦系统启动并开始运行, 矫正磁盘问题通常会很痛苦. 在调优和人们开始抱怨缓慢的构建之前, 定购大量的快速的硬盘驱动器并祝自己好运.

实 现这个模式的方法是使用 CruiseControl 的配置文件. 元素用来告诉 CruiseControl 把日志文件写到哪. 缺省情况下它是 CruiseControl 安装目录下的一个子目录. 如果你修改了元素的"dir"属性, 你就能够确保日志文件可以写到没有运行 CruiseControl 的硬盘上. 如果你使用 Ant 来构建你的代码, 你可以使用配置文件中元素的 "antWorkingDir" 属性来保证你的项目在另外一个硬盘上构建.

我 无法为此给出一个很好的例子, 每个 CruiseControl 的实例之间太不一样了. Buildx 是一个使多个安装更一致的尝试. 如果你看一下各个部分在硬盘上的布局方式, 你就会发现 CruiseControl 的安装在/usr/share/cruisecontrol, 但是 projects 和 logs 安装在/var/spool/cruisecontrol: 我们这么做的原因是这样的话你就能 mount /var 目录到另外一块硬盘, 如果系统开始变得繁忙. 如果你想知道更多的话随时告诉我.

需要 登录 后方可回复。