构建自动化工作流程






4.67/5 (5投票s)
使用 NAnt 和 Cruise Control 描述构建自动化的通用流程。
引言
每个解决方案都有其自己的配置集。因此,自动化构建系统所需的操作系统取决于项目。在这里,我建议了对每个项目都相同的有效工作流程和操作系统。
自动化流程
我使用了 Cruise Control 和 NAnt 进行构建自动化。Cruise control 是一个出色的工具,您可以使用它轻松地自动化您的构建并在团队中实现持续集成。它还非常容易集成其他服务输出,例如单元测试、NCover 结果,以改进构建过程并确保产品质量和可部署性。
Cruise control 定时器(<intervalTrigger seconds="60"/>
)会在一定时间后触发,以检查是否有任何内容已提交到源代码控制,或者强制构建并启动构建过程。在我的项目中,我们的源代码控制由我们的客户维护,我们通过互联网访问。如果我们在每次提交后都签出整个解决方案进行构建,那么会花费很多时间,而我们只需要合并最后一次提交的文件。因此,我们创建一个名为 SVNFOLDER 的文件夹,其中我们只签出一次整个解决方案,然后每次 cruise control 只更新最新文件,但我们会在该签出位置运行构建过程,以确保我们的代码在 cruise control 下次获取最新更改时不会发生任何冲突。我们创建另一个名为 BUILDFOLDER 的文件夹,我们将新的代码从 SVNFOLDER 复制到其中,并执行所有构建解决方案的操作。这些操作我都是使用 NAnt 完成的。更新最新代码后,cruise control 会调用 config 文件中定义的 NAnt 脚本。
NAnt 操作可以通过以下步骤描述:
- 将整个源从 SNVFolder 复制到 BuildFolder。
- 获取 SVN 修订号和 CCNet 级别来创建版本号。版本号格式为
<CCNetLevel>.<SVN Revision>
。 - 使用版本号和其他设置修改 GlobalAssembly.cs,并使用发布配置修改 web.config。
- 使用所有配置运行 MSBuild 以重新构建解决方案。
- 如果您的项目包含单元测试,则运行单元测试。
- 运行 NCoverage(可选)。
- 您还可以运行 FxCop 和其他工具来分析您的构建。此步骤也是可选的。
- 创建安装程序文件或其他可部署的输出。
- 将可部署的输出与版本号一起复制到 SetupFolder。
当从 CCNET 点击 ForceBuild 或 BuildCondition = “ForceBuild”
时,Nant 会执行上述 1 到 9 的所有操作。而对于开发人员的常规提交,NAnt 只执行步骤 1 到 7,以确保开发人员的最后一次提交是安全的,可以创建可部署的输出。
构建自动化的工作流程如下:

实现
我在这里包含了 ccnet 配置文件和 Nant 构建脚本,这些脚本是根据上述步骤实现的。现在我将在此描述我的 CCNet 和 Nant 脚本。
在团队环境中,我们需要确保我提交到源代码控制的代码不会破坏构建,并且还要确保我的代码也是可部署的。为了确保我们提交的代码不会破坏构建,我们可以使用构建自动化工具在每次提交后构建解决方案,或者可以进行预提交构建(TeamCity CI 工具),这可以确保最后一次提交的代码对团队开发是安全的。成功构建后,我们可以创建安装程序文件或可部署的输出,但这不是每次提交都需要的,这可能会增加我们的自动化处理时间。但是,为了确保可部署的输出/安装程序文件也是安全的,我们可以通过夜间构建自动创建安装程序文件。我们可以很容易地通过 cruise control 的 <triggers>
选项来实现。
<triggers>
<intervaltrigger seconds="60">
<scheduletrigger time="04:00" buildcondition="ForceBuild">
</scheduletrigger></intervaltrigger></triggers>
在这里,CCNet 每 60 秒触发一次,以检查是否有任何新的代码提交到 SVN。如果发现开发人员有任何最新的提交,它就会运行 NAnt 脚本。并且使用计划触发器,它会在早上 6 点以强制构建模式运行 Nant,而不管是否有任何最新代码提交到 SVN。如果您愿意,可以在 Force build 条件为 true
时创建 Setup 文件/可部署输出,否则只重新构建解决方案,然后您可以在 Nant 中创建一个目标,该目标根据您的 BuildCondition 做出此决定。
<target name="Run">
<property value="" name="CCNetBuildCondition" overwrite="false"/>
<call target="BuildPublish"
unless="${CCNetBuildCondition=='ForceBuild'}">
<call target="BuildSetup" if="${CCNetBuildCondition=='ForceBuild'}"/>
</target>
在此,“Run
”目标调用另外两个目标“BuildPublish
”和“BuildSetup
”。当您按下 CCNet 的“Force Build”按钮或使用 BuildCondition =”ForceBuild”
时,它将调用“BuildSetup
”目标,否则对于源代码的常规提交,它将运行“BuildPublish
”以确保您的源代码始终可部署。
在“BuildPublish
”目标中,它首先调用“setversion
”目标,并以发布模式运行 MSBuild 来重新构建解决方案,这是上述流程的第 4 步。您还可以在 MSBuild
命令之后包含单元测试脚本和 NConverage 脚本调用,以确保您的单元测试代码在提交后运行良好。
<target name="BuildPublish" depends="setversion">
<echo message="Build is published"/>
<exec program="${MSBuildPath}">
<arg value="${BuildDir}\${SolutionFileName}" />
<arg value="/property:Configuration=release" />
<arg value="/t:Rebuild" />
</exec>
</target>
在这里,在重新构建解决方案之前,它首先调用“setversion
”目标(步骤 3)。“setversion
”目标还依赖于另一个名为“get
”的目标,并在执行“get
”目标后,调用“getSubversionRevision
”,这是步骤 2。这对于维护版本号至关重要,以便了解我们的构建系统正在使用哪个 SVN 最新修订版本。获取修订号后,它会设置程序集通用程序集文件的版本。因此,我们的程序集也知道 CCNet 构建号和 SVN 修订号。
<target name="setversion" depends="get">
<call target="getSubversionRevision"/>
<asminfo output="${BuildDir}\GlobalAssemblyInfo.cs" language="CSharp">
<attributes>
<attribute
type="System.Reflection.AssemblyFileVersionAttribute"
value="${CCNetLabel}.${RevisionNumber}"/>
</attributes>
</asminfo>
</target>
现在,基本的第一步是将 SVN 文件夹复制到 BUILD 文件夹,以运行上述目标,这样 SVN 文件夹将保持与最新 SVN 存储库相同,并减少获取最新提交所需的时间。NAnt 在 BUILD 文件夹上进行的所有修改都是 SVN 文件夹的副本。因此,SVN 文件夹始终安全,不会与 SVN 存储库发生冲突。
<target name="clean" description="Remove all files from target folder.">
<delete dir="${BuildDir}" failonerror="false" />
<mkdir dir="${BuildDir}" />
</target>
<target name="get" depends="clean">
<copy todir="${BuildDir}">
<fileset basedir="${SVNDir}">
<include name="**/**"/>
</fileset>
</copy>
</target>
在此,我描述了开发人员提交代码后,并且 BuildCondition
不等于“ForceBuild
”时执行的步骤 1 到 4。
现在,当 Build Condition 为“ForceBuild
”时,它会调用“BuildSetup
”目标,该目标也依赖于“BuildPublish
”。这意味着对于“ForceBuild
”,将先执行步骤 1 到 4,然后创建安装程序文件。此目标是
<target name="BuildSetup" depends="BuildPublish" >
<echo message="Build is setup"/>
<script language="c#">
<code>
<![cdata[
Here have some code which used to change product code so that running setup
allowed on machine with already contained previous version of this product.
]]>
</code>
</script>
<exec program="${VisualStudio9}" failonerror="true"
commandline="/build Release ${BuildDir}\${SolutionFileName}
/project MYPROJECT.Setup">
</exec>
<property name="publish.dir" value="${ResultDir}\${CCNetLabel}.${RevisionNumber}" />
<mkdir dir="${publish.dir}" />
<copy todir="${publish.dir}">
<fileset basedir="${BuildDir}\MYPROJECT.Setup\release">
<include name="*"/>
</fileset>
</copy>
</target>
在执行完“BuildPublish
”目标的所有步骤后,它首先运行 Setup 项目并创建安装程序文件。然后,它在部署文件夹中创建版本文件,并将安装程序文件复制到该位置,以便于了解此安装程序是为哪个 SVN 修订和 CCNet 标签创建的。
结论
我在这里描述了构建自动化的所有步骤及其实现,这些都是所有项目通用的。我没有在此包含一些 NAnt 目标,例如 NUnit、NCover、NCoverExplorer、FxCop,它们在我的一些项目中有所实现。我没有包含这些 NAnt 目标,因为它们对于所有项目来说都不是必需的。