【Hello CC.NET】巧用模板简化配置

  从 《【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>
View Code

 

 

posted @ 2013-08-24 14:16  海华  阅读(1681)  评论(1编辑  收藏  举报