从 《【Hello CC.NET】CC.NET 实现自动化集成》 到 《【Hello CC.NET】自动化发布时 Web.config 文件维护》 ,大神在评论里提到的方案还没有一一去研究对比,调研的 deadline 已经逼近,CC.NET 的落地提上日程。

  经过两周的努力,终于成功部署了两个项目,由于两个项目的人员配置/开发流程/项目架构不一样,部署的方案也有些差异。过程中碰到这样那样的坑,都是用最快想到的笨方法填坑,然后继续往下走。落地的姿势并不完美,但总算有了一些看得到的成果。   

  落地面临的第一个问题是,ccnet.config 配置比较繁复:太多的 hardcode;相同的 xml 节点内容比较多,尤其在配置多个项目的时候,策略变更时,需要改动的地方比较多。本文将讲述 ccnet.config 模板化的思路。

  

  目标

  • 提取全局性的配置,避免到处 Hardcode
  • 简化各个节点的配置,便于维护

  1.全局变量

    <cc:define CIWebSite="http://vm-caihaihua/CCNET/"/>
<cc:define CIDirectory="C:\CI\"/>
<cc:define MsBuildPath="C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe"/>
<cc:define MsTestPath="C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\MSTest.exe"/>
<cc:define SVNPath="C:\Program Files (x86)\VisualSVN Server\bin\svn.exe"/>
<cc:define FCReplacerPath="C:\CI\Tools\FCReplacer.exe"/>
<cc:define DFCopierPath="C:\CI\Tools\DFCopier.exe"/>
<cc:define name="MsBuildXmlLogger">
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</cc:define>

  

变量名称 描述
CIWebSite CC.NET配套网站的地址 http://vm-caihaihua/CCNET/
CIDirectory 工作目录 C:\CI\
MsBuildPath MsBuild 程序的地址 C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe
MsTestPath MsTest 程序的地址 C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\MSTest.exe
SVNPath Svn 程序的地址 C:\Program Files (x86)\VisualSVN Server\bin\svn.exe
FCReplacerPath FCReplacer 程序的地址 C:\CI\Tools\FCReplacer.exe
DFCopierPath DFCopier 程序的地址 C:\CI\Tools\DFCopier.exe
MsBuildXmlLogger 日志 Logger 的配置 <logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>

 

  2.默认值

    <!-- 默认配置 -->
<cc:define QueuePriority="1"/>
<cc:define KeepLastXBuilds="300"/>
<!-- Email 相关 -->
<cc:define EmailDomain="company.com"/>
<cc:define EmailSendHost="smtp.live.com"/>
<cc:define EmailSendPort="25"/>
<cc:define EmailUseSSL="FALSE"/>
<cc:define EmailSendUser="ci"/>
<cc:define EmailSendPassword="********"/>
<cc:define CIEmailUser="ci"/>
<cc:define PMEmailUser="pm_1"/>
<cc:define name="EmailTesterList">
<user group="tester" name="tester_1" address="tester_1@$(EmailDomain)"/>
<user group="tester" name="tester_2" address="tester_2@$(EmailDomain)"/>
</cc:define>
<!-- Trigger 相关 -->
<cc:define ModificationTriggerIntervalSeconds="300"/>
<cc:define ModificationDelaySeconds="60"/>
<cc:define ProjectTriggerIntervalSeconds="30"/>
<cc:define ProjectTriggerStatus="Success"/>
<cc:define DailyBuildTriggerTime="18:00"/>
<!-- SVN 相关 -->
<cc:define SVNUsername="ci"/>
<cc:define SVNPassword="********"/>
<cc:define SvnCleanCopy="FALSE"/>
<cc:define name="SourceControl">
</cc:define>
<!-- Task 相关 -->
<cc:define TestTimeout="1800"/>
<cc:define CopyTimeout="60"/>
<cc:define ReplaceTimeout="60"/>
<cc:define BuildConfiguration="DEBUG"/>
<cc:define PublishConfiguration="RELEASE"/>

    

变量名称 描述
QueuePriority  项目在队列中的优先级  1
KeepLastXBuilds  保留最后的 X 个构建结果  300
EmailDomain  公司邮箱域名  company.com
EmailSendHost  邮箱服务器地址  smtp.live.com
EmailSendPort  邮箱服务器端口  25
EmailUseSSL  是否启用 SSL  TRUE
EmailSendUser  发送邮箱的帐号  ci
EmailSendPassword  发送邮箱账户的密码  ******
 CIEmailUser  CI 维护人员的邮箱账户  ci
 PMEmailUser  部门经理的邮箱账户  pm_1
 EmailTesterList  测试人员邮箱列表

<user group="tester" name="tester_1" address="tester_1@$(EmailDomain)"/>

<user group="tester" name="tester_2" address="tester_2@$(EmailDomain)"/>

 ModificationTriggerIntervalSeconds  源代码监测的频率(秒)  300
 ModificationDelaySeconds  源代码变更触发构建任务的延迟时间(秒)  60
 ProjectTriggerIntervalSeconds  依赖项目的状态监测频率(秒)  30
 ProjectTriggerStatus  依赖项目的设定状态  SUCCESS
 DailyBuildTriggerTime  每日构建的时间点  18:00
 SVNUsername  SVN 帐号  ci
 SVNPassword  SVN 帐号的密码  ******
 SvnCleanCopy  下载源代码前是否先删除本地源代码  FALSE
 SourceControl  源代码管理的配置  
 TestTimeout  运行测试的超时时间(秒)  1800
 CopyTimeout  拷贝文件的超时时间(秒)  60
 ReplaceTimeout  替换文件内容的超时时间(秒)  60
 BuildConfiguration  编译的配置  DEBUG
 PublishConfiguration  发布网站的配置  RELEASE

  

  

  3.通知模板

    <cc:define name="EmailPublisher">
<email mailhost="$(EmailSendHost)" mailport="$(EmailSendPort)"
mailhostUsername="$(EmailSendUser)@$(EmailDomain)" mailhostPassword="$(EmailSendPassword)"
from="$(EmailSendUser)@$(EmailDomain)"
useSSL="$(EmailUseSSL)" includeDetails="true">
<!--邮件标题配置-->
<subjectPrefix>$(EmailSubject)</subjectPrefix>
<subjectSettings>
<!-- Success/Broken/StillBroken/Fixed/Exception-->
<subject buildResult="Success" value="${CCNetProject} Build result"/>
<subject buildResult="Fixed" value="${CCNetProject} Build result"/>
<subject buildResult="Broken" value="${CCNetProject} Build result"/>
<subject buildResult="StillBroken" value="${CCNetProject} Build result" />
<subject buildResult="Exception" value="${CCNetProject} Build result" />
</subjectSettings>
<!--收件人配置-->
<converters>
<rcgexConverter find="$" replace="@$(EmailDomain)"/>
</converters>
<modifierNotificationTypes>
<notificationType>Failed</notificationType>
<notificationType>Fixed</notificationType>
</modifierNotificationTypes>
<users>
<user group="pm" name="$(PMEmailUser)" address="$(PMEmailUser)@$(EmailDomain)"/>
<user group="ci" name="$(CIEmailUser)" address="$(CIEmailUser)@$(EmailDomain)"/>
<user group="tl" name="$(TeamLeader)" address="$(TeamLeader)@$(EmailDomain)"/>
<cc:EmailTesterList/>
</users>
<groups>
<group name="pm">
<notifications>
<!--Always/Success/Change/Fixed/Failed/Exception -->
<notificationType>Change</notificationType>
</notifications>
</group>
<group name="ci">
<notifications>
<notificationType>Exception</notificationType>
</notifications>
</group>
<group name="tl">
<notifications>
<notificationType>Success</notificationType>
<notificationType>Fixed</notificationType>
<notificationType>Failed</notificationType>
</notifications>
</group>
<group name="developer">
<notifications>
<notificationType>Success</notificationType>
<notificationType>Fixed</notificationType>
<notificationType>Failed</notificationType>
</notifications>
</group>
<group name="tester">
<notifications>
<notificationType>Fixed</notificationType>
</notifications>
</group>
</groups>
</email>
</cc:define>

  模板变量:

变量名称 描述 默认值 是否必填
EmailDomain 公司邮箱域名  company.com  N
EmailSendHost 邮件服务器的地址  smtp.live.com  N
EmailSendPort 邮件服务器的端口  25  N
EmailUseSSL 是否使用 SSL(取决于邮件服务器的配置)  TRUE  N
EmailSendUser 邮件通知的发送帐号  CI  N
EmailSendPassword 邮件通知的发送帐号的密码  ******  N
PMEmailUser 部门经理的邮箱帐号  pm_1  N
CIEmailUser CI 环境维护人员的邮箱帐号  ci  N
TeamLeader 项目组负责人的邮箱帐号,各个项目组配置不同    Y
EmailSubject 邮件通知的前缀    Y

  

  例子:  

            <publishers>
<!--邮件通知-->
<cc:EmailPublisher/>
</publishers>

  4.触发器模板

  (1)源代码检测:每隔一段时间检查源代码,如果有变更,则触发构建过程

    <!-- Triggers:ModificationTrigger/DailyBuildTrigger/ProjectTrigger-->
<cc:define name="ModificationTrigger">
<!--源码修改触发-->
<intervalTrigger seconds="$(ModificationTriggerIntervalSeconds)" buildCondition="IfModificationExists" />
</cc:define>

  模板变量:

变量名称 描述 默认值 是否必填
ModificationTriggerIntervalSeconds 源码监测频率(秒) 600 N

  

  例子:

        <triggers>
<cc:ModificationTrigger/>
</triggers>

  (2)每日构建:每天到设定的时间点触发构建过程

    <cc:define name="DailyBuildTrigger">
<!--每日构建-->
<scheduleTrigger time="$(DailyBuildTriggerTime)" buildCondition="ForceBuild">
<weekDays>
<!--<weekDay>Sunday</weekDay>-->
<weekDay>Monday</weekDay>
<weekDay>Tuesday</weekDay>
<weekDay>Wednesday</weekDay>
<weekDay>Thursday</weekDay>
<weekDay>Friday</weekDay>
<!--<weekDay>Saturday</weekDay>-->
</weekDays>
</scheduleTrigger>
</cc:define>

  模板变量:

变量名称 描述 默认值 是否必填
DailyBuildTriggerTime 每日构建的时间点 18:00 N

  

  例子:

        <triggers>
<cc:DailyBuildTrigger/>
</triggers>

  (3)项目依赖:每隔一段时间检查指定项目的构建结果,如果等于指定值,则触发构建过程

    <cc:define name="ProjectTrigger">
<projectTrigger serverUri="tcp://vm-caihaihua:21234/CruiseManager.rem" project="$(ListenToProject)">
<triggerStatus>$(ProjectTriggerStatus)</triggerStatus>
<innerTrigger type="intervalTrigger" seconds="$(ProjectTriggerIntervalSeconds)" buildCondition="ForceBuild" />
<!--<triggerFirstTime>True</triggerFirstTime>-->
</projectTrigger>
</cc:define>

  模板变量:

变量名称 描述 默认值 是否必填
ProjectTriggerIntervalSeconds 监测依赖项目的频率(秒) 30 N
ProjectTriggerStatus 设定的构建结果 SUCCESS N
ListenToProject 依赖的项目名称   Y

  

  例子:

        <triggers>
<cc:ProjectTrigger ListenToProject="TestProject-Servcies"/>
</triggers>

  5.源代码管理模板

    <!-- SourceControl: SVNSourceControl -->
<cc:define name="SVNSourceControl">
<sourcecontrol type="svn">
<trunkUrl>$(SVNTrunkURL)</trunkUrl>
<executable>$(SVNPath)</executable>
<workingDirectory>$(CIDirectory)$(WorkingDirectory)</workingDirectory>
<username>$(SVNUsername)</username>
<password>$(SVNPassword)</password>
<revert>True</revert>
<cleanCopy>$(SvnCleanCopy)</cleanCopy>
<cleanUp>True</cleanUp>
<deleteObstructions>True</deleteObstructions>
</sourcecontrol>
</cc:define>

  模板变量:

变量名称 描述 默认值 是否必填
SVNUsername Svn 账户,需要项目的 checkout 权限 ci N
SVNPassword Svn 账户的密码 ****** N
SvnCleanCopy 下载源代码前是否先删除本地源代码 FALSE N
SVNTrunkURL 项目的 Svn 路径
  Y

  例子:

        <project>
<cc:SVNSourceControl SVNTrunkURL="https://vm-caihaihua/svn/testproject/services/trunk/"
SvnCleanCopy="False"/>
</project>

  6.任务模板

  (1)文件内容替换

  

    <cc:define name="Replace">
<exec>
<executable>$(FCReplacerPath)</executable>
<buildArgs>
<cc:Files/>
<cc:Rules/>
</buildArgs>
<buildTimeoutSeconds>$(ReplaceTimeout)</buildTimeoutSeconds>
<successExitCodes>0</successExitCodes>
</exec>
</cc:define>

  模板变量:

变量名称 描述 默认值 是否必填
ReplaceTimeout 替换的超时时间(秒) 60 N
Files 需要替换的文件列表   Y
Rules 替换的规则
  Y

  例子:

       <tasks>
<!-- Config -->
<cc:Replace>
<cc:define name="Files">
/file=$(CIDirectory)$(WorkingDirectory)WcfService\Web.config
/file=$(CIDirectory)$(WorkingDirectory)ManagerTest\App.config
/file=$(CIDirectory)$(WorkingDirectory)WcfServiceTest\App.config
</cc:define>
<cc:define name="Rules">
/from=Catalog=(?![^;\s']*_log[;\s']+)(=?[^;\s']*)/to=Catalog=testproject_trunk
/from=Source=(=?.*?)(=?[;\s']+)/to=Source=vm-caihaihua$2
/from=http://(=?[^\/]+)/(=?\w+).svc/to=http://vm-caihaihua/testproject_trunk_ci/WcfService/$2.svc
/from=http://(=?.*?)/(?!SSO)(=?[^\/]+)/(=?\w+).svc/to=http://vm-caihaihua/testproject_trunk_ci/WcfService/$3.svc
/from=http://(=?.*?)/SSO/(=?\w+).svc/to=http://vm-caihaihua/testproject_trunk_ci/SSO/$2.svc
</cc:define>
</cc:Replace>
</tasks>

  (2)项目编译

    <cc:define name="Build">
<msbuild>
<executable>$(MsBuildPath)</executable>
<buildArgs>/t:build /p:configuration=$(BuildConfiguration)</buildArgs>
<cc:MsBuildXmlLogger/>
<workingDirectory>$(CIDirectory)$(WorkingDirectory)</workingDirectory>
<projectFile>$(SolutionPath)</projectFile>
</msbuild>
</cc:define>

  模板变量:

变量名称 描述 默认值 是否必填
BuildConfiguration 编译的配置 DEBUG N
SolutionPath 项目的相对路径   Y

  例子:

       <tasks>
<!-- Build -->
<cc:Build SolutionPath="TestProjectService.sln"/>
</tasks>

  (3)网站发布

  

    <cc:define name="Publish">
<msbuild>
<executable>$(MsBuildPath)</executable>
<workingDirectory>$(CIDirectory)$(WorkingDirectory)</workingDirectory>
<projectFile>$(SolutionPath)</projectFile>
<buildArgs>
/t:ResolveReferences;Compile
/t:_CopyWebApplication
/p:Configuration=$(PublishConfiguration)
/p:WebProjectOutputDir=$(CIDirectory)$(To)
/p:OutputPath=$(CIDirectory)$(To)\bin
</buildArgs>
</msbuild>
</cc:define>

  模板变量:

变量名称 描述 默认值 是否必填
PublishConfiguration 编译的配置 RELACE N
SolutionPath 项目的相对路径   Y
To 目标文件夹的相对路径   Y

  例子:

       <tasks>
<!-- Publish -->
<cc:Publish SolutionPath="WcfService\WcfService.csproj"
To="$(PublishDirectory)WcfService" />
</tasks>

  (4)文件拷贝

    <cc:define name="Copy">
<exec>
<executable>$(DFCopierPath)</executable>
<buildArgs>
/from=$(CIDirectory)$(From)
/to=$(CIDirectory)$(To)
</buildArgs>
<buildTimeoutSeconds>$(CopyTimeout)</buildTimeoutSeconds>
<successExitCodes>0</successExitCodes>
</exec>
</cc:define>

  模板变量:

变量名称 描述 默认值 是否必填
CopyTimeout 拷贝的超时时间(秒) 60 N
From 需要拷贝的文件夹的相对路径   Y
To 目标文件夹的相对路径   Y

  例子:

       <tasks>
<!-- Copy-->
<cc:Copy From="$(WorkingDirectory)WcfService
To="$(PublishDirectory)WcfService"/>
</tasks>

  (5)自动化测试

    <cc:define name="RunTest">
<exec>
<executable>$(MSTestPath)</executable>
<baseDirectory>$(CIDirectory)$(WorkingDirectory)</baseDirectory>
<buildArgs>/testcontainer:$(TestContainerPath)</buildArgs>
<buildTimeoutSeconds>$(TestTimeout)</buildTimeoutSeconds>
</exec>
</cc:define>

  模板变量:

变量名称 描述 默认值 是否必填
TestTimeout 测试的超时时间(秒) 1800 N
TestContainerPath 测试列表的相对路径   Y

  例子:

       <tasks>
<!--Run Test-->
<cc:RunTest TestContainerPath="ManagerTest\bin\Debug\ManagerTest.dll"/>
<cc:RunTest TestContainerPath="WcfServiceTest\bin\Debug\WcfServiceTest.dll"/>
</tasks>

  7.项目模板

    <cc:define name="Project">
<project name="$(ProjectName)" queue="$(Queue)" queuePriority="$(QueuePriority)">
<webURL>$(CIWebSite)server/local/project/$(ProjectName)/ViewProjectReport.aspx</webURL>
<!--标签-->
<labeller type="dateLabeller"/>
<artifactDirectory>$(CIDirectory)$(ArtifactDirectory)</artifactDirectory>
<!--项目的目录-->
<workingDirectory >$(CIDirectory)$(WorkingDirectory)</workingDirectory>
<!--自动运行时间间隔-->
<triggers>
<cc:TriggerList/>
</triggers>
<!--对源码修改延迟处理时间间隔-->
<modificationDelaySeconds>$(ModificationDelaySeconds)</modificationDelaySeconds>
<maxSourceControlRetries>5</maxSourceControlRetries>
<!--源代码管理(SVN)-->
<cc:SourceControl/>
<state type="state" directory="$(CIDirectory)$(StateDirectory)"/>
<publishers>
<modificationHistory onlyLogWhenChangesFound="true"/>
<statistics/>
<xmllogger/>
<artifactcleanup cleanUpMethod="KeepLastXBuilds" cleanUpValue="$(KeepLastXBuilds)" />
<!--邮件通知-->
<cc:EmailPublisher/>
</publishers>
<tasks>
<cc:TaskList/>
</tasks>
</project>
</cc:define>

  模板变量:

变量名称 描述 默认值 是否必填
QueuePriority 项目在队列里的优先级 1 N
KeepLastXBuilds 保存最后的 X 个构建结果 300 N
ModificationDelaySeconds 源代码变更触发构建任务的延迟时间 60 N
SourceControl 源代码配置   N
Queue 项目从属的队列   Y
ProjectName 项目名称   Y
StateDirectory 构建日志的保存目录   Y
WorkingDirectory 项目的工作目录,即源代码的保存路径   Y
ArtifactDirectory 构建结果的存放目录   Y
TriggerList 触发器配置列表   Y
TaskList 任务列表   Y

  

  例子:

  TestProject 包括 Wcf Service 项目和 AdminWeb 项目

  (1)Wcf Service

  a.  自动化部署

    • 自动获取源代码
    • 源代码监测及每日构建
    • 修改配置文件中的数据库连接字符串及服务引用地址
    • Debug 编译整个解决方案
    • Release 发布 Service 到 CI 环境

  b. 自动化测试

    • 与a使用同一个工作目录(即源代码)
    • 监测自动化部署过程,如果成功则触发自动化测试
    • 运行 ManagerTest 和 ServiceTest

  (2) AdminWeb

自动化部署

  • 自动获取源代码
  • 源代码监测及每日构建
  • 修改配置文件中的数据库连接字符串及服务引用地址
  • Debug 编译整个解决方案
  • Release 发布 AdminWeb 到 CI 环境
    <!-- TestProject: Service 项目 -->
<queue name="TestProject" duplicates="ApplyForceBuildsReAdd" />
<cc:Project ProjectName="TestProject-Servcies"
Queue="TesProjectt"
WorkingDirectory="TestProject\SourceCode\service_trunk\"
ArtifactDirectory="TestProject\Artifact\service\"
StateDirectory="TestProject\State\"
PublishDirectory="TestProject\Publish\"
EmailSubject="[CI-TestProjectService]"
ModificationDelaySeconds="30"
TeamLeader="caihaihua">
<cc:define name="SourceControl">
<cc:SVNSourceControl SVNTrunkURL="https://vm-caihaihua/svn/testproject/services/trunk/"
SvnCleanCopy="False"/>
</cc:define>
<cc:define name="TriggerList">
<cc:ModificationTrigger/>
<cc:DailyBuildTrigger/>
</cc:define>
<cc:define name="TaskList">
<!-- Config -->
<cc:Replace>
<cc:define name="Files">
/file=$(CIDirectory)$(WorkingDirectory)WcfService\Web.config
/file=$(CIDirectory)$(WorkingDirectory)ManagerTest\App.config
/file=$(CIDirectory)$(WorkingDirectory)WcfServiceTest\App.config
</cc:define>
<cc:define name="Rules">
/from=Catalog=(?![^;\s']*_log[;\s']+)(=?[^;\s']*)/to=Catalog=service_trunk_ci
/from=Source=(=?.*?)(=?[;\s']+)/to=Source=localhost$2
/from=http://(=?[^\/]+)/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/WcfService/$2.svc
/from=http://(=?.*?)/(?!SSO)(=?[^\/]+)/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/WcfService/$3.svc
/from=http://(=?.*?)/SSO/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/SSO/$2.svc
</cc:define>
</cc:Replace>
<!-- Build -->
<cc:Build SolutionPath="TestProjectService.sln"/>
<!-- Publish -->
<cc:Copy From="$(WorkingDirectory)WcfService"
To="$(PublishDirectory)WcfService"/>
</cc:define>
</cc:Project>
<cc:Project ProjectName="TestProjectServcies-Test"
Queue="TestProject"
QueuePriority="2"
WorkingDirectory="TestProject\SourceCode\service_trunk\"
ArtifactDirectory="TestProject\Artifact\test\"
StateDirectory="TestProject\State\"
EmailSubject="[CI-TestProjectServcie-Test]"
ModificationDelaySeconds="30"
TeamLeader="caihaihua">
<cc:define name="TriggerList">
<cc:ProjectTrigger ListenToProject="TestProject-Servcies"/>
</cc:define>
<cc:define name="TaskList">
<!--Run Test-->
<cc:RunTest TestContainerPath="ManagerTest\bin\Debug\ManagerTest.dll"/>
<cc:RunTest TestContainerPath="WcfServiceTest\bin\Debug\WcfServiceTest.dll"/>
</cc:define>
</cc:Project> <!-- TestProject: AdminWeb 项目 -->
<cc:Project ProjectName="TestProject-AdminWeb"
Queue="TestProject"
WorkingDirectory="TestProject\SourceCode\admin_trunk\"
ArtifactDirectory="TestProject\Artifact\admin\"
StateDirectory="TestProject\State\"
PublishDirectory="TestProject\Publish\"
EmailSubject="[CI-TestProject-AdminWeb]"
TeamLeader="caihaihua">
<cc:define name="SourceControl">
<cc:SVNSourceControl SVNTrunkURL="https://vm-caihaihua/svn/testproject/adminweb/trunk/"/>
</cc:define>
<cc:define name="TriggerList">
<cc:ModificationTrigger/>
<cc:DailyBuildTrigger/>
</cc:define>
<cc:define name="TaskList">
<!-- Config -->
<cc:Replace>
<cc:define name="Files">
/file=$(CIDirectory)$(WorkingDirectory)AdminWeb\Web.config
</cc:define>
<cc:define name="Rules">
/from=http://(=?[^\/]+)/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/WcfService/$2.svc
/from=http://(=?.*?)/(?!SSO)(=?[^\/]+)/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/WcfService/$3.svc
/from=http://(=?.*?)/SSO/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/SSO/$2.svc
</cc:define>
</cc:Replace>
<!-- Build -->
<cc:Build SolutionPath="AdminWeb.sln"/>
<!-- Publish -->
<cc:Publish SolutionPath="AdminWeb\AdminWeb.csproj"
To="$(PublishDirectory)AdminWeb" />
</cc:define>
</cc:Project>

完整的 ccnet.config:

<cruisecontrol xmlns:cc="urn:ccnet.config.builder">
<!-- 全局配置 -->
<cc:define CIWebSite="http://vm-caihaihua/CCNET/"/>
<cc:define CIDirectory="C:\CI\"/>
<cc:define MsBuildPath="C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe"/>
<cc:define MsTestPath="C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\MSTest.exe"/>
<cc:define SVNPath="C:\Program Files (x86)\VisualSVN Server\bin\svn.exe"/>
<cc:define FCReplacerPath="C:\CI\Tools\FCReplacer.exe"/>
<cc:define DFCopierPath="C:\CI\Tools\DFCopier.exe"/>
<cc:define name="MsBuildXmlLogger">
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</cc:define> <!-- Publishers:EmailPublisher-->
<cc:define name="EmailPublisher">
<email mailhost="$(EmailSendHost)" mailport="$(EmailSendPort)"
mailhostUsername="$(EmailSendUser)@$(EmailDomain)" mailhostPassword="$(EmailSendPassword)"
from="$(EmailSendUser)@$(EmailDomain)"
useSSL="$(EmailUseSSL)" includeDetails="true">
<!--邮件标题配置-->
<subjectPrefix>$(EmailSubject)</subjectPrefix>
<subjectSettings>
<!-- Success/Broken/StillBroken/Fixed/Exception-->
<subject buildResult="Success" value="${CCNetProject} ${CCNetBuildDate} Build result"/>
<subject buildResult="Fixed" value="${CCNetProject} ${CCNetBuildDate} Build result"/>
<subject buildResult="Broken" value="${CCNetProject} ${CCNetBuildDate} Build result"/>
<subject buildResult="StillBroken" value="${CCNetProject} ${CCNetBuildDate} Build result" />
<subject buildResult="Exception" value="${CCNetProject} ${CCNetBuildDate} Build result" />
</subjectSettings>lo
<!--收件人配置-->
<converters>
<regexConverter find="$" replace="@$(EmailDomain)"/>
</converters>
<modifierNotificationTypes>
<notificationType>Failed</notificationType>
<notificationType>Fixed</notificationType>
</modifierNotificationTypes>
<users>
<user group="pm" name="$(PMEmailUser)" address="$(PMEmailUser)@$(EmailDomain)"/>
<user group="ci" name="$(CIEmailUser)" address="$(CIEmailUser)@$(EmailDomain)"/>
<user group="tl" name="$(TeamLeader)" address="$(TeamLeader)@$(EmailDomain)"/>
<cc:EmailTesterList/>
</users>
<groups>
<group name="pm">
<notifications>
<!--Always/Success/Change/Fixed/Failed/Exception -->
<notificationType>Change</notificationType>
</notifications>
</group>
<group name="ci">
<notifications>
<notificationType>Exception</notificationType>
</notifications>
</group>
<group name="tl">
<notifications>
<notificationType>Success</notificationType>
<notificationType>Fixed</notificationType>
<notificationType>Failed</notificationType>
</notifications>
</group>
<group name="developer">
<notifications>
<notificationType>Success</notificationType>
<notificationType>Fixed</notificationType>
<notificationType>Failed</notificationType>
</notifications>
</group>
<group name="tester">
<notifications>
<notificationType>Fixed</notificationType>
</notifications>
</group>
</groups>
</email>
</cc:define> <!-- Triggers:ModificationTrigger/DailyBuildTrigger/ProjectTrigger-->
<cc:define name="ModificationTrigger">
<!--源码修改触发-->
<intervalTrigger seconds="$(ModificationTriggerIntervalSeconds)" buildCondition="IfModificationExists" />
</cc:define>
<cc:define name="DailyBuildTrigger">
<!--每日构建-->
<scheduleTrigger time="$(DailyBuildTriggerTime)" buildCondition="ForceBuild">
<weekDays>
<!--<weekDay>Sunday</weekDay>-->
<weekDay>Monday</weekDay>
<weekDay>Tuesday</weekDay>
<weekDay>Wednesday</weekDay>
<weekDay>Thursday</weekDay>
<weekDay>Friday</weekDay>
<!--<weekDay>Saturday</weekDay>-->
</weekDays>
</scheduleTrigger>
</cc:define>
<cc:define name="ProjectTrigger">
<projectTrigger serverUri="tcp://Server12:21234/CruiseManager.rem" project="$(ListenToProject)">
<triggerStatus>$(ProjectTriggerStatus)</triggerStatus>
<innerTrigger type="intervalTrigger" seconds="$(ProjectTriggerIntervalSeconds)" buildCondition="ForceBuild" />
<!--<triggerFirstTime>True</triggerFirstTime>-->
</projectTrigger>
</cc:define> <!-- SourceControl: SVNSourceControl -->
<cc:define name="SVNSourceControl">
<sourcecontrol type="svn">
<trunkUrl>$(SVNTrunkURL)</trunkUrl>
<executable>$(SVNPath)</executable>
<workingDirectory>$(CIDirectory)$(WorkingDirectory)</workingDirectory>
<username>$(SVNUsername)</username>
<password>$(SVNPassword)</password>
<revert>True</revert>
<cleanCopy>$(SvnCleanCopy)</cleanCopy>
<cleanUp>True</cleanUp>
<deleteObstructions>True</deleteObstructions>
</sourcecontrol>
</cc:define> <!-- Tasks: Replace/Build/Publish/Copy/RunTest -->
<cc:define name="Replace">
<exec>
<executable>$(FCReplacerPath)</executable>
<buildArgs>
<cc:Files/>
<cc:Rules/>
</buildArgs>
<buildTimeoutSeconds>$(ReplaceTimeout)</buildTimeoutSeconds>
<successExitCodes>0</successExitCodes>
</exec>
</cc:define>
<cc:define name="Build">
<msbuild>
<executable>$(MsBuildPath)</executable>
<buildArgs>/t:build /p:configuration=$(BuildConfiguration)</buildArgs>
<cc:MsBuildXmlLogger/>
<workingDirectory>$(CIDirectory)$(WorkingDirectory)</workingDirectory>
<projectFile>$(SolutionPath)</projectFile>
</msbuild>
</cc:define>
<cc:define name="Publish">
<msbuild>
<executable>$(MsBuildPath)</executable>
<workingDirectory>$(CIDirectory)$(WorkingDirectory)</workingDirectory>
<projectFile>$(SolutionPath)</projectFile>
<buildArgs>
/t:ResolveReferences;Compile
/t:_CopyWebApplication
/p:Configuration=$(PublishConfiguration)
/p:WebProjectOutputDir=$(CIDirectory)$(To)
/p:OutputPath=$(CIDirectory)$(To)\bin
</buildArgs>
</msbuild>
</cc:define>
<cc:define name="Copy">
<exec>
<executable>$(DFCopierPath)</executable>
<buildArgs>
/from=$(CIDirectory)$(From)
/to=$(CIDirectory)$(To)
</buildArgs>
<buildTimeoutSeconds>$(CopyTimeout)</buildTimeoutSeconds>
<successExitCodes>0</successExitCodes>
</exec>
</cc:define>
<cc:define name="RunTest">
<exec>
<executable>$(MSTestPath)</executable>
<baseDirectory>$(CIDirectory)$(WorkingDirectory)</baseDirectory>
<buildArgs>/testcontainer:$(TestContainerPath)</buildArgs>
<buildTimeoutSeconds>$(TestTimeout)</buildTimeoutSeconds>
</exec>
</cc:define> <!-- 通用配置(模板) -->
<cc:define name="Project">
<project name="$(ProjectName)" queue="$(Queue)" queuePriority="$(QueuePriority)">
<webURL>$(CIWebSite)server/local/project/$(ProjectName)/ViewProjectReport.aspx</webURL>
<!--标签-->
<labeller type="dateLabeller"/>
<artifactDirectory>$(CIDirectory)$(ArtifactDirectory)</artifactDirectory>
<!--项目的目录-->
<workingDirectory >$(CIDirectory)$(WorkingDirectory)</workingDirectory>
<!--自动运行时间间隔-->
<triggers>
<cc:TriggerList/>
</triggers>
<!--对源码修改延迟处理时间间隔-->
<modificationDelaySeconds>$(ModificationDelaySeconds)</modificationDelaySeconds>
<maxSourceControlRetries>5</maxSourceControlRetries>
<!--源代码管理(SVN)-->
<cc:SourceControl/>
<state type="state" directory="$(CIDirectory)$(StateDirectory)"/>
<publishers>
<modificationHistory onlyLogWhenChangesFound="true"/>
<statistics/>
<xmllogger/>
<artifactcleanup cleanUpMethod="KeepLastXBuilds" cleanUpValue="$(KeepLastXBuilds)" />
<!--邮件通知-->
<cc:EmailPublisher/>
</publishers>
<tasks>
<cc:TaskList/>
</tasks>
</project>
</cc:define> <!-- 默认配置 -->
<cc:define QueuePriority="1"/>
<cc:define KeepLastXBuilds="300"/>
<!-- Email 相关 -->
<cc:define EmailDomain="company.com"/>
<cc:define EmailSendHost="smtp.live.com"/>
<cc:define EmailSendPort="25"/>
<cc:define EmailUseSSL="TRUE"/>
<cc:define EmailSendUser="ci"/>
<cc:define EmailSendPassword="******"/>
<cc:define CIEmailUser="ci"/>
<cc:define PMEmailUser="pm_1"/>
<cc:define name="EmailTesterList">
<user group="tester" name="tester_1" address="tester_1@$(EmailDomain)"/>
<user group="tester" name="tester_2" address="tester_2@$(EmailDomain)"/>
</cc:define>
<!-- Trigger 相关 -->
<cc:define ModificationTriggerIntervalSeconds="300"/>
<cc:define ModificationDelaySeconds="60"/>
<cc:define ProjectTriggerIntervalSeconds="30"/>
<cc:define ProjectTriggerStatus="SUCCESS"/>
<cc:define DailyBuildTriggerTime="18:00"/>
<!-- SVN 相关 -->
<cc:define SVNUsername="ci"/>
<cc:define SVNPassword="******"/>
<cc:define SvnCleanCopy="FALSE"/>
<cc:define name="SourceControl">
</cc:define>
<!-- Task 相关 -->
<cc:define TestTimeout="1800"/>
<cc:define CopyTimeout="60"/>
<cc:define ReplaceTimeout="60"/>
<cc:define BuildConfiguration="DEGUB"/>
<cc:define PublishConfiguration="RELEASE"/> <!-- TestProject: Service 项目 -->
<queue name="TestProject" duplicates="ApplyForceBuildsReAdd" />
<cc:Project ProjectName="TestProject-Servcies"
Queue="TesProjectt"
WorkingDirectory="TestProject\SourceCode\service_trunk\"
ArtifactDirectory="TestProject\Artifact\service\"
StateDirectory="TestProject\State\"
PublishDirectory="TestProject\Publish\"
EmailSubject="[CI-TestProjectService]"
ModificationDelaySeconds="30"
TeamLeader="caihaihua">
<cc:define name="SourceControl">
<cc:SVNSourceControl SVNTrunkURL="https://vm-caihaihua/svn/testproject/services/trunk/"
SvnCleanCopy="False"/>
</cc:define>
<cc:define name="TriggerList">
<cc:ModificationTrigger/>
<cc:DailyBuildTrigger/>
</cc:define>
<cc:define name="TaskList">
<!-- Config -->
<cc:Replace>
<cc:define name="Files">
/file=$(CIDirectory)$(WorkingDirectory)WcfService\Web.config
/file=$(CIDirectory)$(WorkingDirectory)ManagerTest\App.config
/file=$(CIDirectory)$(WorkingDirectory)WcfServiceTest\App.config
</cc:define>
<cc:define name="Rules">
/from=Catalog=(?![^;\s']*_log[;\s']+)(=?[^;\s']*)/to=Catalog=service_trunk_ci
/from=Source=(=?.*?)(=?[;\s']+)/to=Source=localhost$2
/from=http://(=?[^\/]+)/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/WcfService/$2.svc
/from=http://(=?.*?)/(?!SSO)(=?[^\/]+)/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/WcfService/$3.svc
/from=http://(=?.*?)/SSO/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/SSO/$2.svc
</cc:define>
</cc:Replace>
<!-- Build -->
<cc:Build SolutionPath="TestProjectService.sln"/>
<!-- Publish -->
<cc:Copy From="$(WorkingDirectory)WcfService"
To="$(PublishDirectory)WcfService"/>
</cc:define>
</cc:Project>
<cc:Project ProjectName="TestProjectServcies-Test"
Queue="TestProject"
QueuePriority="2"
WorkingDirectory="TestProject\SourceCode\service_trunk\"
ArtifactDirectory="TestProject\Artifact\test\"
StateDirectory="TestProject\State\"
EmailSubject="[CI-TestProjectServcie-Test]"
ModificationDelaySeconds="30"
TeamLeader="caihaihua">
<cc:define name="TriggerList">
<cc:ProjectTrigger ListenToProject="TestProject-Servcies"/>
</cc:define>
<cc:define name="TaskList">
<!--Run Test-->
<cc:RunTest TestContainerPath="ManagerTest\bin\Debug\ManagerTest.dll"/>
<cc:RunTest TestContainerPath="WcfServiceTest\bin\Debug\WcfServiceTest.dll"/>
</cc:define>
</cc:Project> <!-- TestProject: AdminWeb 项目 -->
<cc:Project ProjectName="TestProject-AdminWeb"
Queue="TestProject"
WorkingDirectory="TestProject\SourceCode\admin_trunk\"
ArtifactDirectory="TestProject\Artifact\admin\"
StateDirectory="TestProject\State\"
PublishDirectory="TestProject\Publish\"
EmailSubject="[CI-TestProject-AdminWeb]"
TeamLeader="caihaihua">
<cc:define name="SourceControl">
<cc:SVNSourceControl SVNTrunkURL="https://vm-caihaihua/svn/testproject/adminweb/trunk/"/>
</cc:define>
<cc:define name="TriggerList">
<cc:ModificationTrigger/>
<cc:DailyBuildTrigger/>
</cc:define>
<cc:define name="TaskList">
<!-- Config -->
<cc:Replace>
<cc:define name="Files">
/file=$(CIDirectory)$(WorkingDirectory)AdminWeb\Web.config
</cc:define>
<cc:define name="Rules">
/from=http://(=?[^\/]+)/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/WcfService/$2.svc
/from=http://(=?.*?)/(?!SSO)(=?[^\/]+)/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/WcfService/$3.svc
/from=http://(=?.*?)/SSO/(=?[^\/]+).svc/to=http://vm-caihaihua/testproject_trunk_ci/SSO/$2.svc
</cc:define>
</cc:Replace>
<!-- Build -->
<cc:Build SolutionPath="AdminWeb.sln"/>
<!-- Publish -->
<cc:Publish SolutionPath="AdminWeb\AdminWeb.csproj"
To="$(PublishDirectory)AdminWeb" />
</cc:define>
</cc:Project>
</cruisecontrol>

【Hello CC.NET】巧用模板简化配置的更多相关文章

  1. CC.NET模板简化配置

    [Hello CC.NET]巧用模板简化配置 从 <[Hello CC.NET]CC.NET 实现自动化集成> 到 <[Hello CC.NET]自动化发布时 Web.config ...

  2. Spring事务支持:利用继承简化配置

    因为事务代理的实现类是 TransactionProxyFactoryBean . 事务代理Bean必须注入事务管理器. 大部分情况下,每个事务代理的事务属性大同小异,对于这种情况,Spring提供了 ...

  3. C#开发中使用配置文件对象简化配置的本地保存

    C#开发中使用配置文件对象简化配置的本地保存 0x00 起因 程序的核心是数据和逻辑,开发过程中免不了要对操作的数据进行设置,而有些数据在程序执行过程中被用户或程序做出的修改是应该保存下来的,这样程序 ...

  4. WCF学习之旅—WCF4.0中的简化配置功能(十五)

    六 WCF4.0中的简化配置功能 WCF4.0为了简化服务配置,提供了默认的终结点.绑定和服务行为.也就是说,在开发WCF服务程序的时候,即使我们不提供显示的 服务终结点,WCF框架也能为我们的服务提 ...

  5. Spring注释与简化配置

      在Spring 2.5及以后的版本中,提供了注释和命名空间来简化Spring的配置.下面是一些常用配置分享. 1.@Autowired注释   以前给一个Bean配置属性时,Bean必须配置< ...

  6. ElasticSearch 模板文件配置

    首先是推荐一下参考资料 中文资料:http://kibana.logstash.es/content/elasticsearch/index.html 官方文档:https://www.elastic ...

  7. maven pom文件简单模板和配置详解

    https://blog.csdn.net/earbao/article/details/49924943 maven pom文件简单模板和配置详解

  8. 7 -- Spring的基本用法 -- 11... 基于XML Schema的简化配置方式

    7.11 基于XML Schema的简化配置方式 Spring允许使用基于XML Schema的配置方式来简化Spring配置文件. 7.11.1 使用p:命名空间简化配置 p:命名空间不需要特定的S ...

  9. smarty模板的配置

    smarty下载: http://www.smarty.net/download   建议使用一个兼容性好的smary版本. 太新的版本往往对php的版本支持不好.   php推荐使用的模板是:sma ...

随机推荐

  1. mysql通过data文件恢复数据库的方式

    1.首先定位mysql的my.ini配置文件,查找datadir的位置 #Path to the database rootdatadir="C:/ProgramData/MySQL/MyS ...

  2. MVC中的常见问题

    1.  The model backing the 'MusicStoreDBContext' context has changed since the database was created. ...

  3. tmp

    Hello 大家好,这次给大家带来的是Gear VR4代,首先我得感谢下我们的虎友Hide兄弟友情提供Gear给我们测评,感谢 感谢.之前我录的前哨战也说过,这次Gear VR 4代较3代变化并不是很 ...

  4. C#高级--通过类来理解学习委托

    namespace classanddelegate { class Program { static void Main(string[] args) { //这是类的实例化 Test test = ...

  5. Spring知识点总结大全(1)

    1.Spring的分层结构 1.Presentation layer(表示层) (1) 表示逻辑(生成界面代码) (2) 接收请求 (3) 处理业务层抛出的异常 (4) 负责规则验证(数据格式,数据非 ...

  6. Process类

    public bool Process.Start () 启动(或重用)此 Process 组件的 StartInfo 属性指定的进程资源,并将其与该组件关联. public bool Process ...

  7. javascript里的继承

    js里面继承的方式, 1. 类式继承,通过构造函数的继承 function extend(subClass, superClass){ var F = function(){}; F.prototyp ...

  8. JS各种算法小例子

    <!DOCTYPE html><html><head>    <title>js</title>    <meta charset=& ...

  9. Process 执行shell 脚本

    概述: Process类是一个抽象类(所有的方法均是抽象的),封装了一个进程(即一个执行程序). Process 类提供了执行从进程输入.执行输出到进程.等待进程完成.检查进程的退出状态以及销毁(杀掉 ...

  10. JAVA SSH 框架介绍

    SSH 为 struts+spring+hibernate 的一个集成框架,是目前较流行的一种JAVA Web应用程序开源框架. Struts Struts是一个基于Sun J2EE平台的MVC框架, ...