使用CruiseControl.Net全面实现持续集成



持续集成想必大家很多人都听说过,甚至都实践过,最近我又一次亲历了一次持续集成,现将我的经验分享给大家。关于持续集成的理论在本文概不涉及,本文的主要目的是实战CruiseControl.Net,用它来全面实现持续集成。

在配置ccnet.config时会用到一些小工具,一并附上:小工具下载

首先,我们来看看用CC.Net能为我们做哪些事情:

自动获取源代码

自动Build

自动执行UnitTest,并生成单元测试报告

自动部署

触发自动化(回归)测试

邮件提醒

使用CCTray进行监控

应用plugin显示集成结果

设置集成策略

在开始之前,第一件事是配置我们的持续集成环境

  获取SVN或TFS工具,TFS可通过安装VisualStudio获得,SVN可通过安装TortoiseSVN来获得。

  安装和配置IIS,因为我们要使用Web页面查看持续集成的结果,所以需要配置IIS,安装CruiseControl.Net时会为我们创建一个名为ccnet的web应用程序。

  从http://www.cruisecontrolnet.org/这个站点上现在我们需要的工具CruiseControl.Net并将其安装。

  安装VisualStudio2013(当然也可选其它版本)。安装它的目的有两个,1. 使用了VSTest.Console.exe产生单元测试结果数据(UnitTest结果和测试覆盖率),2. 当编译不能通过时用它可以发现问题。

到此为止,集成环境已经OK,下面,我们来逐一来通过配置ccnet.config实现上述功能。

1.自动获取源代码

首先需要了解,持续集成的单位是以项目为单位,在ccnet.config文件里体现为Project,如下:

<project name="MyProject"
             description="demoproject showing a small config" queue="Q1">
  
project>
View Code

配置项目的源代地址,包括本地工作地址和源代码管理服务地址,对于使用TFS的源码管理器,向Project下添加如下配置:

<workingDirectory>E:\dailybuildworkingDirectory>
<artifactDirectory>E:\dailybuildartifactDirectory>
<category>TestProjectcategory>
<sourcecontrol type="vsts" autoGetSource="true"  applyLabel="false">
  <server>http://tfs1.TestProject.com:8080server>
  <domain>TestProject.comdomain>
  <project>$/TestProject projects/Analysis and Design\Concierge\Prototypeproject>
  <workingDirectory>E:\dailybuild\TestProjectworkingDirectory>
  <cleanCopy>truecleanCopy>
sourcecontrol>
View Code

对于使用svn源码管理器,可以使用以下配置:

<artifactDirectory>d:\svn\Log\MyProjectartifactDirectory>
<sourcecontrol type="svn">
  <executable>C:\Program Files\TortoiseSVN\bin\svn.exeexecutable>
  <username>UserNameusername>
  <password>******password>
  <autoGetSource>trueautoGetSource>
  <trunkUrl>http://svnserver/trunk/MyProjecttrunkUrl>
  <workingDirectory>d:\svn\trunk\MyProjectworkingDirectory>
sourcecontrol>
View Code 

2.实现自动Build,向Project节点下增加tasks节点,如下

<tasks>
  <msbuild>
    <executable>C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exeexecutable>
    <buildArgs>/p:OutputPath=D:\BuildOutputbuildArgs>
    <workingDirectory>D:\svn\branch\project\workingDirectory>
    <projectFile>mysolution.slnprojectFile>
    <targets>Buildtargets>
    <timeout>9000timeout>
  msbuild>
tasks>
View Code

3.自动执行UnitTest,并生成单元测试报告

如果要生成单元测试报告和单元测试覆盖率,这里需要多下写功夫去配置。首先在创建Runsettings文件,如下:

使用CruiseControl.Net全面实现持续集成_第1张图片

CodeCoverage.runsettings的配置内容如下:

xml version="1.0" encoding="utf-8"?>
<RunSettings>
  <RunConfiguration>
    
    <ResultsDirectory>d:\svn\log\TestResultsResultsDirectory>

    
    <TargetPlatform>x86TargetPlatform>

    
    <TargetFrameworkVersion>Framework40TargetFrameworkVersion>
  RunConfiguration>
  <DataCollectionRunSettings>
    <DataCollectors>
      <DataCollector friendlyName="Code Coverage" uri="datacollector://Microsoft/CodeCoverage/2.0" assemblyQualifiedName="Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
        <Configuration>
          <CodeCoverage>
            
            <ModulePaths>
              <Include>
                <ModulePath>.*\.dll$ModulePath>
                <ModulePath>.*\.exe$ModulePath>
              Include>
              <Exclude>
                <ModulePath>.*CPPUnitTestFramework.*ModulePath>
              Exclude>
            ModulePaths>

            
            
            <Functions>
              <Exclude>
                <Function>^Fabrikam\.UnitTest\..*Function>
                <Function>^std::.*Function>
                <Function>^ATL::.*Function>
                <Function>.*::__GetTestMethodInfo.*Function>
                <Function>^Microsoft::VisualStudio::CppCodeCoverageFramework::.*Function>
                <Function>^Microsoft::VisualStudio::CppUnitTestFramework::.*Function>
              Exclude>
            Functions>

            
            <Attributes>
              <Exclude>
                
                <Attribute>^System.Diagnostics.DebuggerHiddenAttribute$Attribute>
                <Attribute>^System.Diagnostics.DebuggerNonUserCodeAttribute$Attribute>
                <Attribute>^System.Runtime.CompilerServices.CompilerGeneratedAttribute$Attribute>
                <Attribute>^System.CodeDom.Compiler.GeneratedCodeAttribute$Attribute>
                <Attribute>^System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute$Attribute>
              Exclude>
            Attributes>

            
            <Sources>
              <Exclude>
                <Source>.*\\atlmfc\\.*Source>
                <Source>.*\\vctools\\.*Source>
                <Source>.*\\public\\sdk\\.*Source>
                <Source>.*\\microsoft sdks\\.*Source>
                <Source>.*\\vc\\include\\.*Source>
              Exclude>
            Sources>

            
            <CompanyNames>
              <Exclude>
                <CompanyName>.*microsoft.*CompanyName>
              Exclude>
            CompanyNames>

            
            <PublicKeyTokens>
              
              <Exclude>
                <PublicKeyToken>^B77A5C561934E089$PublicKeyToken>
                <PublicKeyToken>^B03F5F7F11D50A3A$PublicKeyToken>
                <PublicKeyToken>^31BF3856AD364E35$PublicKeyToken>
                <PublicKeyToken>^89845DCD8080CC91$PublicKeyToken>
                <PublicKeyToken>^71E9BCE111E9429C$PublicKeyToken>
                <PublicKeyToken>^8F50407C4E9E73B6$PublicKeyToken>
                <PublicKeyToken>^E361AF139669C375$PublicKeyToken>
              Exclude>
            PublicKeyTokens>


            
            <UseVerifiableInstrumentation>TrueUseVerifiableInstrumentation>
            <AllowLowIntegrityProcesses>TrueAllowLowIntegrityProcesses>
            <CollectFromChildProcesses>TrueCollectFromChildProcesses>
            <CollectAspDotNet>FalseCollectAspDotNet>

          CodeCoverage>
        Configuration>
      DataCollector>
    DataCollectors>
  DataCollectionRunSettings>
RunSettings>
View Code

里面最重要的信息室配置了单元测试结果存放路径:d:\svn\log\TestResults,以便我们后来生成测试结果。

接着来配置ccnet.config,以执行单元测试


<exec>
  <executable>D:\svn\tool\delfile.batexecutable>
  <buildArgs>D:\svn\Log\TestResultsReal\mstest-results.trxbuildArgs>
  <buildTimeoutSeconds>300buildTimeoutSeconds>
  <successExitCodes>-1,0successExitCodes>
exec>
<exec>
  <executable>D:\svn\tool\delfile.batexecutable>
  <buildArgs>D:\svn\Log\TestResultsReal\mstest-coverage.xmlbuildArgs>
  <buildTimeoutSeconds>300buildTimeoutSeconds>
  <successExitCodes>-1,0successExitCodes>
exec>

<exec>
  <executable>C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\VSTest.Console.exeexecutable>
  <baseDirectory>D:\svn\UnitTest.dll所在的文件目录baseDirectory>
  <buildArgs>UnitTest.dll /Enablecodecoverage /Settings:D:\svn\tool\CodeCoverage.runsettings /logger:trxbuildArgs>
  <buildTimeoutSeconds>300buildTimeoutSeconds>
exec>

<exec>
  <executable>
    
    <exec>
      <executable>D:\svn\tool\delfile.batexecutable>
      <buildArgs>D:\svn\Log\TestResultsReal\mstest-results.trxbuildArgs>
      <buildTimeoutSeconds>300buildTimeoutSeconds>
      <successExitCodes>-1,0successExitCodes>
    exec>
    <exec>
      <executable>D:\svn\tool\delfile.batexecutable>
      <buildArgs>D:\svn\Log\TestResultsReal\mstest-coverage.xmlbuildArgs>
      <buildTimeoutSeconds>300buildTimeoutSeconds>
      <successExitCodes>-1,0successExitCodes>
    exec>
    
    <exec>
      <executable>C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\VSTest.Console.exeexecutable>
      <baseDirectory>D:\svn\UnitTest.dll所在的文件目录baseDirectory>
      <buildArgs>UnitTest.dll /Enablecodecoverage /Settings:D:\svn\tool\CodeCoverage.runsettings /logger:trxbuildArgs>
      <buildTimeoutSeconds>300buildTimeoutSeconds>
    exec>
    
    <exec>
      <executable>D:\svn\tool\coverage\Auto.Dealer.UnitTest.Tool.exeexecutable>
      <buildArgs>D:\svn\log\TestResults\ D:\svn\log\TestResultsReal\mstest-results.trx D:\svn\log\TestResultsReal\mstest-coverage.xmlbuildArgs>
      <buildTimeoutSeconds>300buildTimeoutSeconds>
      <successExitCodes>-1,0successExitCodes>
    exec>

    
    <merge>
      <files>
        <file>D:\svn\Log\TestResultsReal\mstest-results.trxfile>
        
      files>
    merge>
    <merge>
      <files>
        <file>D:\svn\Log\TestResultsReal\mstest-coverage.xmlfile>
        
      files>
    merge>D:\svn\tool\coverage\Auto.Dealer.UnitTest.Tool.exeexecutable>
  <buildArgs>D:\svn\log\TestResults\ D:\svn\log\TestResultsReal\mstest-results.trx D:\svn\log\TestResultsReal\mstest-coverage.xmlbuildArgs>
  <buildTimeoutSeconds>300buildTimeoutSeconds>
  <successExitCodes>-1,0successExitCodes>
exec>


<merge>
  <files>
    <file>D:\svn\Log\TestResultsReal\mstest-results.trxfile>
    
  files>
merge>
<merge>
  <files>
    <file>D:\svn\Log\TestResultsReal\mstest-coverage.xmlfile>
    
  files>
merge>
View Code

这里,想必大家已经注意到有两处删除操作,因为持续集成式一个不断重复的过程,如果不删除原来的测试结果就会发生错误。另外,用到的一个工具(这个工具里的代码很简单,一并提供出来如下),用来将trx文件转化为xml文件,即单元测试覆盖率结果。最后将它们一起合并到CruiseControl的执行日志里。

生成单元测试覆盖率代码如下:

    class Program
    {
        static void Main(string[] args)
        {
            string dirName = args[0];
            string trxUutPutFileName = args[1];
            string coverageoutPutFileName = args[2];

            if (Directory.Exists(dirName))
            {
                DirectoryInfo dirc = new DirectoryInfo(dirName);
                foreach (FileInfo file in dirc.GetFiles("*.trx"))
                {
                    file.CopyTo(trxUutPutFileName, true);
                    break;
                }

                foreach (FileInfo file in dirc.GetFiles("*.coverage", SearchOption.AllDirectories))
                {
                    ConvertToXML(file.FullName, coverageoutPutFileName);
                    break;
                }

                dirc.Delete(true);
            }
            else
            {
                Console.WriteLine("没找到目录:"+dirName);
            }
        }

        public static void ConvertToXML(string coverageFile, string outputFile)
        {
            using( CoverageInfo coverageInfo = CoverageInfo.CreateFromFile(coverageFile))
            {
                using (CoverageDS ds = coverageInfo.BuildDataSet())
                {
                    ds.ExportXml(outputFile);
                }
            }
        }
    }
View Code

4.自动部署


<buildpublisher>
  <sourceDir>d:\svn\_PublishedWebsites\MyWebsourceDir>
  <publishDir>\\IP地址\website\publishDir>
  <useLabelSubDirectory>falseuseLabelSubDirectory>
buildpublisher>
View Code

5. 触发自动化(回归)测试

如果有自动化测试框架,则可以考虑部署完毕后自动触发执行自动化测试,由于自动化测试框架可能会有很大差异,这里就不在给出配置,总的来说,使用可以很灵活地实现我们的需求。

6. 邮件提醒功能

无论持续集成执行成功,还是失败,都可以配置相应的邮件接收人员。邮件配置要放到。这样,邮件发送的失败就不会阻塞持续集成。

<publishers>
  <email mailport="25" includeDetails="TRUE" mailhostUsername="[email protected]" mailhostPassword="******" useSSL="FALSE">
    <from>[email protected]from>
    <mailhost>smtp.sina.netmailhost>
    <users>
      <user name="张三" group="developers" address="[email protected]" />
      <user name="李四" group="developers" address="[email protected]" />
      <user name="王五" group="developers" address="[email protected]" />
    users>
    <groups>
      <group name="developers">
        <notifications>
          <notificationType>FailednotificationType>
          <notificationType>FixednotificationType>
        notifications>
      group>
      <group name="buildmaster">
        <notifications>
          <notificationType>AlwaysnotificationType>
        notifications>
      group>
    groups>
    <converters>
      <regexConverter find="$" replace="@sina.com" />
    converters>
    <modifierNotificationTypes>
      <NotificationType>FailedNotificationType>
      <NotificationType>FixedNotificationType>
    modifierNotificationTypes>
    <subjectSettings>
      <subject buildResult="StillBroken" value="Build is still broken for {CCNetProject}" />
    subjectSettings>
  email>
  <statistics />
  <xmllogger />
publishers>
View Code

7. 使用CCTray监控持续集成

打开http://CruiseControl所在机的IP/ccnet/,可以看到如下连接,下载并安装。就可以监控制定的项目了。

使用CruiseControl.Net全面实现持续集成_第2张图片

8.应用plugin显示集成结果

最后,做了以上所有的事情以后,在http://CruiseControl所在机的IP/ccnet/这个站点上并不能看到我们所有的持续集成结构,CruiseControl为我们提供了一些Plugins,即一些xsl文件,使用它们就可以显示我们想要的结果了。这些xsl文件的地址为:CruiseControl的安装路径\CruiseControl.NET\webdashboard\xsl。我们需要修改一下dashboard.config这个文件,我向其中添加了如下内容:

<buildPlugins>
  <buildReportBuildPlugin>
    <xslFileNames>
      <xslFile>xsl\header.xslxslFile>
      <xslFile>xsl\modifications.xslxslFile>
      <xslFile>xsl\unittests.xslxslFile>
      <xslFile>xsl\MsTestSummary2008.xslxslFile>
      <xslFile>xsl\compile-msbuild.xslxslFile>
      <xslFile>xsl\SimianSummary.xslxslFile>
      <xslFile>xsl\MsTestSummary2010.xslxslFile>
      <xslFile>xsl\MsTestSummary.xslxslFile>
      <xslFile>xsl\MsTestReport2010.xslxslFile>
      <xslFile>xsl\MsTestCover2010.xslxslFile>
    xslFileNames>
  buildReportBuildPlugin>
buildPlugins>
View Code

这样,重启ccnet站点后,我们的测试结果也会被格式化地显示出来。

9.设置集成策略

以每日构建为例,需要在里配置如下结果:

<scheduleTrigger time="23:30" buildCondition="ForceBuild" name="Scheduled">
  <weekDays>
    <weekDay>MondayweekDay>
    <weekDay>TuesdayweekDay>
    <weekDay>WednesdayweekDay>
    <weekDay>ThursdayweekDay>
    <weekDay>FridayweekDay>
  weekDays>
scheduleTrigger>
View Code

 

至此,我们的持续集成也基本上可以告一段落了。可以使用它来进行一些自动化的工作了。

你可能感兴趣的:(使用CruiseControl.Net全面实现持续集成)