Archive for the 'Continuous Integration' Category

解决 Hudson 控制台输出乱码

2011-6-1 21:57 | by 2ndboy

  我的 Hudson 装在英文版的 Windows XP 里,但是有些 build tool 会输出中文,这样一来在查看 Hudson 的控制台输出(如:http://localhost:8080/job/test/1/console)时所有中文都变成了乱码。

  由于我不是搞 Java 的,所以没有看过 Hudson 的源码,但是从解决方案上来看,乱码的根本原因在于 Hudson 弄错了控制台数据的字符编码。如果你的 Hudson 也存在这个问题,那么首先可以进入“系统管理”->“系统信息”,看看“file.encoding”的值是不是“Cp1252”,如果是的话那么你可以接着往下看:)

  file.encoding = Cp1252 意味着 Hudson 认为你的控制台输出数据是 Cp1252 编码,由于 Hudson 的 Web page 编码是 UTF-8 编码,所以 Hudson 会尝试做一个 Cp1252 to UTF-8 的转换,把中文当作拉丁文来解读,其结果当然是错的了。解决方法如下:

1) 如果你是在命令行启动 Hudson 的(如:java -jar hudson.war),那么就给 java.exe 多传一个参数“-Dfile.encoding=gbk”(gb2312 也可以)

2) 如果你已经把 Hudson 安装成 Windows Service 了,那么打开 hudson.xml,把“arguments”节点的内容改成:
<arguments>-Xrs -Xmx256m -Dfile.encoding=gbk -Dhudson.lifecycle=hudson.lifecycle.WindowsServiceLifecycle -jar “%BASE%\hudson.war” –httpPort=8080</arguments>

重启 Hudson 以后,再进入系统信息,可以看到 file.encoding 的值已经变成了 gbk 了。

Hudson 的分布式 build

2010-9-14 22:18 | by 2ndboy

  前段时间一直比较忙,最近几天利用稍稍松下来一点的时间研究了一下 Hudson 的分布式 build。同样,以下内容都只在 Windows 平台下验证通过。

  一般来说,如果项目需要在不同的平台上进行编译的话,分布式 build 就比较有用了。假设某项目需要在 Windows、Linux 和 Mac 进行编译,那么可以拿一台 Windows 主机安装 Hudson 做 master,同时进行 Windows 平台上的 build。然后再分别在一台 Linux 主机和一台 Mac 主机上配置 Hudson salve。之后就可以在 master 上创建 job,然后在不同的平台上做 build 了。

  另外一种用途就是纯粹的负载均衡了,默认情况下 Hudson 在一台主机上只允许同时进行两项 job(当然这个可以在系统设置的“# of executors”里进行修改,但是这个数字肯定是跟主机的配置情况相关的),如果你有数十个 job 需要同时做 build 的话,为了便于统一管理,这时用到分布式 build 也是个不错的主意。

  下面就是一些设置步骤的记录:

Slave 端主机的设置

Hudson 在 Windows 平台下是通过 DCOM 对 slave 进行操作的,所以首先要保证 slave 主机的 DCOM 相关 service 可以正常工作。

Master 在操作 slave 主机时需要以 slave 主机上的用户身份登录进行,所以要在 slave 主机上为 Hudson 创建一个管理员帐号。

在 slave 主机上为 Hudson 无色一个栖身之所,比如 D:\HudsonSlave。这个目录无需手工创建。

Master 端的设置

以管理员身份登录 Hudson 的 master 端,进入“系统管理”->“管理节点”->“新建节点”,如下图:
新建节点
注意“节点名称”不能随便写,因为我们后面要创建/连接的是一个 Windows 平台的节点,所以节点名称一定要用 IP 地址或者主机名称。“Dumb Slave”一定要选,否则无法继续。

新建节点的填写例子见下图:
节点设置
“Remote FS root”填写的是位于 slave 主机上的路径,就是刚才你为 slave 选的那块宝地。
“Labels”比较有用,它是用来描述 slave 的一些标签,在绑定 job 时用于标识节点,不填的话默认就是节点名称。
“Usage”有两个选项,分别是不绑定 job 和只能跑绑定 job,按照实际需要选择。
“Launch method”我们这里选择“Let Hudson control this Windows salve as a Windows service”,这样设置成功以后 slave 主机上的 slave 进程会被作为服务来运行。
“Administrator user name”和“Password”填写你在 slave 主机上为 Hudson 创建的用户名和密码即可。
保存以后 Hudson 就会尝试连接 slave 主机,然后用设置的管理员用户身份登录 slave 主机,创建 slave 目录,上传 slave 程序,把它作为 service 安装。

节点创建成功以后你就会在 Hudson master 界面左边的生成状态栏里看到 salve 了。同时在 slave 主机上你会发现 Hudson 已经建好了给 slave 使用的文件夹并且上传了一些文件,同时你会在 slave 的 service 列表里看到一个新 service,如下图:
Hudson slave service

Slave 的使用

Slave 连好以后,你就可以给它分配活儿干了。当然,这个新“奴隶”能干什么活儿跟你在创建它的时候的设置很有关系,如果你创建它的时候在 Usage 里选的是“Utilize this slave as much as possible”的话,那么普通的 job 不用做什么额外设置就可以跑在这个 slave 上了。但是如果你在 Usage 里选的是“Leave this machine for tied jobs only”的话,那么只有跟这个 slave 进行了绑定的 job 才能跑在这个 slave 上。

其实由于配置和程序安装的情况不同,一般来说让 job 跑在特定的 slave 上更常用些。把 job 跟 slave 绑定很简单,进入 job 设置,在“Tie this project to a node”里选中某个 salve(或者 master)就可以了。这样这个这个 job 以后就只能跑在某个特定的节点上了。

Slave 的删除

在 master 的管理节点页面里删掉 slave 只会让 slave 在 master 上不可见、不可用,但是 Hudson 不会对 slave 上的文件和 service 做任何删除操作。

在 slave 主机上彻底删除 slave 需要两个步骤,删除 service 和删除 slave 程序。由于 Hudson slave service 的名称里有盘符和路径分隔符,所以用“sc delete xxx”是不管用的,需要在命令行下进入 slave 目录运行“hudson-slave.exe uninstall”,之后就可以把整个 slave 目录干掉了。

后记

结合之前的那篇“用 Hudson 实现 Visual Studio (C++) 项目的 daily build”,看完这两篇 post 以后在日常工作里应用 Hudson 应该已经没什么大问题了。我陆续抽时间把我使用 Hudson 的过程写出来,希望对想要学习使用 Hudson 的同道有所帮助,同时也为这个优秀的持续集成工具的普及做些事情,Hudson 是个好东西:D

Skip changelog computation on Hudson

2010-5-27 20:52 | by 2ndboy

  Hudson 的 changelog computation 功能其实是个很有用的功能,但是如果你的项目是用 CVS 做 SCM 的,而且项目又特别大,那么这个 changelog computation 做起来那可是耗时巨大!就拿工作上的项目来说,CVS update + changelog computation + clean build 耗时 3 个多小时,其中居然有 2 个多小时是在做 changelog computation!!!所以即便是 local daily build 出了错,留给开发的反应时间太短。关于如何禁用这个 feature,在 Hudson 的 Wiki 上找到一篇文档。按照文档所述如法炮制,修改 Hudson home 目录下的 hudson.xml(这是 Hudson service 的配置文件),在 节点下加一句:

  1. <env name="hudson.scm.CVSSCM.skipChangeLog" value="true"/>

  但是试过以后发现根本没效果,所以看来文档上说的“In general, these switches are often experimental in nature, and subject to change without notice.”不是在忽悠:) 这么看来,不存在 disable changelog computation 一说,顶多也只能 skip。

  今天尝试的一个方法可以达到绕过 changelog computation 的目的——建个新 job,workspace 设定成跟真正需要 build 的 job 一样。这个新 job 只做 SCM 部分的工作,然后早于需要 build 的 job 运行,这样等真正需要 build 的 job 运行起来的时候,changelog computation 的时间会大大缩短,现在用了这招后,我们的项目全程 build 时间减少到了正常的 1 小时左右。

[Update: 2010/7/8]
实践中发现上面这一招还是有玩儿不转的时候,比如在第一次和第二次 update 之间有过大量 code commit 的情况下,这个更新过程还是会长的让人崩溃。所以今天又换了个思路,干脆绕过 Hudson 的 SCM update 机制,用命令行自己来 update code。

方法是在所有的 build step 之前再加一个 Execute Windows batch command,示例内容如下:
@echo off
echo Updating src …
cd %WORKSPACE%\src
cvs -d :pserver:username:password@cvs_server_address:module update -P -d

由于 Hudson 在每次执行批处理的时候都会把 current path 设置在 workspace 下,所以命令序列里不用加切换盘符的内容,只需要按照实际需要切换路径就可以了。

shell in Hudson

2010-5-26 22:34 | by 2ndboy

  以下内容说的是 Windows 平台,在 *nix 下用 shell 没什么好说的:)

  在 Hudson 的系统设置里可以设置“Shell executable”,在 Windows 下,最好的选择是 Cygwin。不改 Cygwin 的默认安装路径的话,这里可以设置成“C:\cygwin\bin\sh.exe”,然后就可以在 job 设置里 add 一个“Execute shell”的 build step 了。这种情况下取 Hudson 预设环境变量的话可以在变量名前加“$”,比如 job 的 workspace 路径——$WORKSPACE。

  如果不想装 Cygwin,或者觉得 shell 脚本太弱的话,Hudson 还支持用 Python 做 shell。这种情况下不用在系统设置里对“Shell executable”做什么设置,而是用 *nix 下 shell 脚本惯用的首行注释来指明 Python 解释器的位置。在 job 设置里用“Add build step”加一个“Execute shell”,然后在“Command”里直接写 Python 代码,比如第一行写:

  1. #!E:\Python26\python.exe

就可以用 Windows 风格的路径来指示 Python 解释器所在的位置。这这种情况下,取 Hudson 预定义的环境变量要用库函数:

  1. import os
  2.  print( os.getenv('WORKSPACE') )

  还有一种情况是你的 Windows 系统里没装 Python,而是把 Python 装在了 Cygwin 里,这种情况下要配置系统设置里的“Shell executable”,然后 Python 脚本可以放在磁盘文件里。Command 里可以写成形如:

  1. /bin/python /cygdrive/E/foo/2ndboy.py

或者:

  1. /bin/python E:/foo/2ndboy.py

但不能写成:

  1. /bin/python E:\foo\2ndboy.py

第一种“/cygdrive/E/foo/2ndboy.py”的形式是 Cygwin 里用于访问其它分区的语法形式,因为“/”只能访问到 Cygwin 的安装路径而已。

用 Hudson 实现 Visual Studio (C++) 项目的 daily build

2010-4-24 13:12 | by 2ndboy

  大概是去年吧,在尝试找一款开源 CI 工具的时候看到了这张表格,当时感觉 BuildbotHudson 不错,但是 Buildbot 在 Windows 下的安装和配置略显复杂,Hudson 就比较简单了,不过在装好 Hudson 以后没有找到编译 VC 6 项目的方法,所以没有继续研究下去。今年工作上的项目基本都要转到 Visual Studio 2008 上去,所以又把 Hudson 捡起来研究了一下,这里记录一下用 Hudson 为 C++ 的 Visual Studio project 做 daily build 的方法和步骤。

一、环境准备和安装

我们的项目是 for Windows 平台的,所以下面介绍的内容很多也只适用于 Windows 平台。Hudson 是用 Java 开发的,所以首先要确保机器上已经安装了 JRE,没有的话可以在这里下载合适的版本安装。

当然,还需要下载 Hudson,目前最新版的 Hudson 是 1.355 版,下载得到的是一个 war 包。俺不是做 Java 的,以前一直以为运行 Hudson 必须要装 Tomcat 这类容器,后来才知道用命令行就可以启动运行 Hudson。所以装 Tomcat 就省啦。

给 Hudson 在剩余空间比较大的盘上安个家,因为 Hudson 一般都把自己的配置文件,从 SCM 里 check out 出来的代码什么的放在它自己的 home 文件夹里。比如把下载回来的 Hudson.war 放在 D:\Hudson 目录下,在命令行下用 java -jar Hudson.war 就可以把 Hudson 开起来。但是这样的话 Hudson 会自动把它的 home 目录设定到当前用户的 home 目录下,所以我们可以在启动 Hudson 的时候手工指定一下 Hudson 的 home 目录:java -DHUDSON_HOME=D:\Hudson -jar hudson.war。

启动 Hudson 之后打开浏览器,访问 http://localhost:8080 就可以看到 Hudson 的 UI 了。为了方便使用,我们可以把 Hudson 安装成为 Windows 的一个 service,这样就不用每次在重启机器后再去手工运行 Hudson 了。进入 Hudson 的设置界面,点 Install as Windows Service。

Install as Windows Service

之所以有很多人喜欢 Hudson 是因为它的灵活和强大,跟 WordPress 一样,Hudson 同样支持通过安装各种 plugin 来扩展自己的功能。而且安装 plugin 在 Hudson 自己的 UI 上就可以完成,不必自己手工下载,放在某个特定目录再去后台设置什么的,非常方便!我们编译 Visual Studio 项目需要用到 MSBuild 这个 plugin,在 plugin 管理界面里的可用 plugin 页面找到 MSBuild,安装,然后重启 Hudson 服务即可。在把 Hudson 安装成一个 service 以后,我们可以通过命令行来启动和停止 Hudson——net start hudson,net stop hudson。

plugins

安装好 MSBuild 以后还要设置一下,进入系统设置,找到 MSBuild 那一段,会看到两个字段:name 和 Path to msbuild.exe。注意这里 name 一定要填,以后在做编译 job 设置的时候会用到,Path to msbuild.exe 就是你机器上 MSBuild.exe 的绝对路径,比如 C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe。

接下来要设置一下 SCM,比如 cvs.exe 在本机上的绝对路径,还有邮件通知使用的 SMTP 地址和账户等。注意邮件通知里的 Hudson URL 默认是 http://localhost:8080/,这里最好改成对外有效的主机名,否则别人收到 build 结果通知邮件以后点击链接访问 localhost 是无意义的:)

二、创建 Hudson build job

Hudson 把受它管理的每个编译项目叫做一个 job,在 Hudson 的 home 目录里你可以找到一个叫 jobs 的目录,里面存放着所有的 build job,在具体一个 job 的目录下还有一个 workspace 文件夹,里面存放的就是从 SCM 里 check out 出来的代码,当然你可以自己指定 workspace 的位置。比如有一个叫 foo 的 job,那它的 workspace 的位置就在 HUDSON_HOME\jobs\foo\workspace。

在 Hudson UI 里新建任务,然后选 Build a free-style software project 这个类型。

点击 Advanced Project Options 可以设置一些不常用的高级选项,比如 Use custom workspace 就可以自己来指定 workspace 的位置。如果你想把代码 check out 到一个特定名字的文件夹里,这个选项就派上用场了。假设你想把 code check out 到一个叫 bar 的文件夹里,可以在 Use custom workspace 里设置 D:\Hudson\jobs\foo\workspace\bar。其实 Hudson 内部定义了一些环境变量,使用这些变量可以增加 job settings 的灵活性,比如上面这个目录可以写成:$HUDSON_HOME\jobs\$JOB_NAME\workspace\bar,这样一来如果你以后变动了 Hudson 的安装位置就可以不用重现设置 job settings 了。有关 Hudson 的环境变量,可以看这个 link。需要注意的是,一但在这里设置了 custom workspace,那么再使用 $WORKSPACE 这个环境变量拿到的就是这个 custom workspace 的位置,而不是默认的位置。

选中 Build Triggers 里的 Build periodically 就可以让 Hudson 在特定的时间自动触发一个 build,这里的语法跟 *nux 里面的 cronjob 很像,比如你想让这个 build 在每天凌晨 1 点自动触发,可以写成 0 1 * * *。

在 Build 节里点 Add build step,选 Build a Visual Studio project or solution using MSBuild,然后来设置 MSBuild。有 3 个 field 需要设置:
MsBuild Version 这里选我们在系统设置设置的 MSBuild 的 name,如果你机器上有多个版本的 MSBuild,这里可以选择合适的版本。
MsBuild Build File 这里填 .sln 或者 .vcproj 文件的位置。
Command Line Arguments 这里填需要传递给 MSBuild 的命令行参数。比如你要编译 foo.sln 里的 p1,p2,p3 这三个工程,但是顺序必须是 2->3->1,那么可以传这个参数:/p:Configuration=Release /t:p2;p3;p1,如果想做一个 clean build,那么只需要在第一个 target 前加上 Clean 即可——/p:Configuration=Release /t:Clean;p2;p3;p1。

最后还可以设置在编译完成以后发通知邮件,多个收件人之间用空格分隔,据说淘宝内部还自己开发了旺旺通知 plugin,在编译结束后可以通过用旺旺发 IM 的形式来通知有关人等,这也体现了 Hudson 非常好的扩展性:)

设置完成以后点 save 保存,一个 new job 就创建好了。你可以点“立即生成”来马上启动一个 build,或者等着 Hudson 在你设定好的时间自动 build 然后把通知邮件发给你。

三、安全设置

安装之后 Hudson 默认是允许匿名访客对 Hudson 和 build job 的设置做修改,而且也可以访问 workspace 查看代码,在实际环境里我们显然需要对这种宽松的 AC 做一下限制。

进入系统管理,系统设置。选中 Enable security。在 Access Control 的 Security Realm 中选中 Hudson’s own user database,表示我们要使用 Hudson 内建的用户数据库来做访问控制。然后在 Authorization 中选中 Matrix-based security,这样我们就可以对每个用户的权限做详细的设置了。

默认已经有一个 Anonymous 匿名用户了,不过他没有任何权限,我们一般要给他 read 权限,这样一来收到 build 邮件通知的人就可以通过点击邮件里的链接看到一些结果信息而又无法改动配置了。在下面我们还可以用 User/group to add 增加一个用户,比如增加一个叫 2ndboy 的管理员用户,然后给他所有的权限:

Access Control

注意我们在创建 2ndboy 用户的时候并没有指定密码,而一旦你开启访问控制,保存设置后,你马上就变成了匿名用户,再也不能访问系统设置了。一开始我也晕了,后来才明白,你在系统设置里新建的用户其实相当于一个 placeholder,要真正创建这个用户、设置密码还需要先点 Log in,然后在 Log in 界面里点 Create an account 来到 Sign up 页面才能真正的创建这个用户。Sign up 好以后要记得到系统设置里把 Hudson’s own user database 下面的 Allow users to sign up 改成未选中状态,否则匿名用户可以随意的 sign up 自己的账户。

Hudson 跟 Buildbot 一样,还支持分布式 build,不过暂时还没什么研究,等有了心得以后再来分享:)