NAnt 在.NET 环境中实现每日构建 NAnt 篇 (zz)

liuxue.gu@hotmail.com · 2008年06月18日 · 5 次阅读

在.NET 环境中实现每日构建 NAnt 篇 2007年02月07日星期三 11:49 前言

关于每日构建这个话题,也已经有很多很好的文章讨论了。本文的写作过程中也参考了这些文章。本文之所以继续这个题目,是因为在查阅了网上的资源后,发现没有一个比较通用的过程。所以本文就主要讨论了利用 NAnt 构建一个通用日编译的方案。利用这个方案,日编译的维护者可以不需要对每个要编译的方案都要做很多维护。只要定义一个属性文件就可以了。

关键词: Daily Build, NAnt

  1. 简介

1.1. 每日构建的优点:

每日构建(Daily Build)也可称为持续集成(Continuous Integration),强调完全自动化的、可重复的创建过程,其中包括每天运行多次的自动化测试。每日构建的作用日益显得重要。它让开发者可以每天进行系统集成,从而减少了开发过程中的集成问题。

持续集成可以减少集成阶段"捉虫"消耗的时间,从而最终提高生产力。它使得绝大多数 bug 在引入的同一天就可以被发现。而且,由于一天之中发生变动的部分并不多,所以可以很快找到出错的位置。

1.2. 每日构建完成的任务

实现自动化每日构建需要做以下几部分的工作:

l 使创建过程完全自动化,让任何人都可以只输入一条命令就完成系统的创建。

l 使测试完全自动化,让任何人都可以只输入一条命令就运行一套完整的系统测试。

l 确保所有人都可以得到最新、最好的可执行文件。

  1. 每日构建所使用的工具

在.NET 环境下建立每日构建可以使用一系列开源工具:

Nant: 完成代码的自动编译,自动运行测试工具。[url]http://nant.sourceforge.net/builds//url][

NantContrib:自动从源码库中获取源代码。[url]http://nantcontrib.sourceforge.net/nightly/builds//url][

NUnit2Report:将 NUnit 测试工具产生的 XML 报告转换为 HTML 报告形式。[url]http://NUnit2Report.sourceforge.net/url][

VSS:Visual Source Safe,微软源码管理工具

Draco.NET: 用于自动检测 VSS 中源代码变动情况,调用 Nant 完成自动编译

[url]http://sourceforge.net/projects/draconet//url][

下载所需的工具后,按照如下步骤进行安装:

在服务器上安装 VSS 源码管理工具

安装下载的 Draco Server 和 Draco Web,修改安装后的 Draco Web 目录下的 web.config 文件,设置正确的 Draco Server 安装路径

将 NAnt、NAntContrib、NUnit2Report 压缩包解压,将三个 Bin 目录中的内容复制到一个公用目录,比如 D:\DailyBuildTools,然后将该路径加入系统的 Path 路径列表中,具体为 “控制面板-〉系统属性-〉环境变量-〉Path”

  1. NAnt 自动脚本

NAnt 脚本实现了每日构建的主体功能,它具体分为下面几部分

l 定义每日构建所需的一些环境变量,比如从 VSS 上下载的源码的保存目录,发布目录等

l 清除旧的代码并从 VSS 源码库中下载最新源代码

l 编译源代码并运行测试代码集

l 将编译后的目标代码拷贝到发布目录进行发布

为了尽可能少的改动 NAnt 的脚本文件,简化日常维护的工作量,我们把一些对所有项目都基本相同的过程抽取出来,如环境变量定义,清除旧代码获取新代码,编译源代码,对目标代码进行发布的过程都可以写成通用的脚本,而一个具体项目的每日构建脚本则调用通用过程完成

本文采取的目录体系如下所示:

D:\DailyBuild\

\Source:存放源代码的目录

\Build:存放编译后的目标代码的目录

\Publish:存放的 WEB 发布文件的目录

\log:存放的日志文件

3.1. Nant 的基础知识

l Nant 脚本代码文件的基本结构

<?xml version="1.0" encoding="gb2312"?>

……

……

说明:encoding="gb2312"使得脚本文件可以支持中文

标签定义了项目属性,一个脚本文件只能有一个项目定义

default="prebuild"说明该项目缺省从 prebuild 任务开始执行

标签定义了一项任务,任务是 Nant 脚本具体执行动作的最小单元

depends="namecheck,clean "说明该任务执行前需要 namecheck 和 clean 任务先执行

description 描述了该任务的一些说明性信息

l 定义变量

使用了已定义变量 core.basedir 和 solution.name 来定义变量 solution.basedir;

使用了 NAnt 内建函数 directory::get-current-directory() 来定义 curdir 变量

3.2. 定义环境变量

定义环境变量的脚本代码写在 Common。Config 文件里

主要有以下几类信息的定义:

l 每日构建所在的根目录

说明:${directory::get-current-directory()}内建函数获取当前文件所在路径信息

l 被编译的解决方案的目录结构,和前面提到的目录体系一致

说明:以上代码是定义了要编译的解决方案的目录结构信息,其中 ${solution.name}是由外部传入的解决方案的名称,后面的代码将根据该名称在日编译的根目录下生成和 solution.name 指定的名称同名的目录,并在该目录下生成 source,buld,log 等子目录

l VSS 源代码管理系统的基本信息

说明:定义了和 VSS 源码管理系统相关的一些信息,其中 VSS 数据库所在位置可以是网络路径,也可以是本地路径

l <编译时的一些参数

3.3. 建立目录结构,获取源代码

脚本代码写在 CheckSource.build.xml 文件里

l 包含在 Common.config 文件里定义的公共变量

l 检查是否存在 solution.name 变量

<!--检查解决方案名称是否已经定义-->

<!--去掉可能的空格字符-->

<!--检查 solution.name 变量是否为空字符-->

说明:${property::exists('<变量名>')}是 NAnt 内建函数,用于测试某变量是否存在

${string::get-length(<字符串变量>)==0}测试字符串的长度是否为 0

… :如果 test 表达式值为假,执行标签内的代码

… :如果 test 表达式值为假,执行标签内的代码

l 建立解决方案的目录结构

<!--删除旧的解决方案代码所在目录-->

<!--重新建立目录-->

说明:delete 和 mkdir 标签内的 failonerror 属性表示即使操作文件夹的过程中出现了错误,也忽略错误向下执行

l 获取源代码:

从 VSS 上获取解决方案的源代码

<!--检查从 VSS 上下载解决方案的路径是否设定-->

<!-- 如果不定义 vss.projectpath,则缺省为 solution.name -->

<vssget

user="${vss.username}"

password="${vss.password}"

localpath="${solution.source}"

recursive="true"

replace="true"

dbpath="${vss.dbpath}"

path="${vss.basepath}${vss.projectpath}"

/>

说明:标签是 NAntContrib 的语法,用来从 VSS 源码管理器上下载源代码,user 和 password 属性表示登录 VSS 服务器的信息;Localpath 属性是指下载的源代码存放的路径;recursive="true"表示递归获取代码;replace= "true"表示如果本地有重复文件,则进行覆盖;dbpath 定义 VSS 的 srcsafe.ini 文件的路径信息,包括 srcsafe.ini 文件名; path 定义了要获取的源代码在 VSS 数据库中的路径,一般都是以 $/为根目录。

3.4. 编译源代码

l 编译命令

编译解决方案的命令为

其中 solutionfile 属性表明了要编译的解决方案文件的路径信息,即以"sln"为扩展名的文件,

configuration 属性表明要编译的是发行版还是调试版,取值为"Release"或"Debug"

outputdir 表明了编译后的动态链接库或可执行文件存放的目录

solution 中的嵌套标签用于当解决方案含有 WEB 项目的情况,有几个 WEB 项目,就有几项标签,map 标签中的 url 属性为 WEB 项目的.csproj 文件的 WEB 路径,path 则为该.csproj 文件所在磁盘上的物理路径,例如,解决方案中有 WEB 项目 exam,则 map 标签为 <map url="http://localhost/exam/exam.csproj" ... am\exam.csproj"

l 根据解决方案名称获取解决方案文件的路径信息

<!-- 查找解决方案文件名 -->

<!--根据文件名设置解决方案的名称-->

说明:标签是 NAnt 中处理循环的命令,item="File"说明 foreach 进行循环处理的对象是文件,< include>中的 name 变量表示要查找的文件信息,"**\"表示查找路径包括子目录。Foreach 的属性 property="<变量名>"表示查找到的文件路径信息保存在该变量中,可以在标签中引用.foreach 每查找到一项符合条件的 Item,都会执行标签中的代码,以上代码执行的结果就是查找到指定名称的解决方案文件,供后面编译代码使用

l 获取解决方案中 WEB 项目的路径信息

如果解决方案中含有 WEB 项目,则其编译命令和不含 WEB 项目的解决方案编译有所区别,所以要区别对待。如果解决方案含有多个 WEB 项目,则可以让用户将多个 WEB 项目的名称放在一个变量中,如 solution.webprojects,以逗号或分号或空格做分隔符。然后将项目名称分别提取出来,根据 Web 项目的个数决定 solution 命令的形式,代码如下

以上代码中 foreach 标签的属性 item="String" in="${solution.webprojects}" delim=";, " property="project"表明循环对象是字符串,对 in 所代表的字符串

[url]http://hi.baidu.com/xiao0856/blog/item/aae75d23eada2e529822ed16.html/url][

请教一下,我在使用 Nant 编译 C# 的 project 代码时出现问题,提示: 找不到类型或命名空间名称是否缺少 using 指令或程序集引用?) 并且出现多处。 我的 build 文件是这样的: <?xml version="1.0" encoding="gb2312"?>

用 IDE 编译代码有没有问题?如果 IDE 编译通不过,那肯定是代码问题了. 这种错误一般都是 Dev 那边的事情,不是 CM 职责范围了.

一般 CM 只编译成功一次代码之后,很少发生错误.除非他工程文件的名字都改变了,或者涉及到编译的一些 folder structure 改变了.其它都是 Dev 那边的事情, 总不能让 CM 帮助 Dev debug 代码吧...

非常感谢!:) 但是问题是 IDE 可以编译通过,用 NANT 编译就出现 “找不到类型或命名空间名称是否缺少 using 指令或程序集引用” 的这种提示,最终 build 失败。 所以怀疑是不是我的 deault.build 文件写的存在问题。 还请赐教!!谢谢。

还想请教一下,是不是应该在 build 文件里把外部的一些引用都列出来?

需要 登录 后方可回复。