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


    网址:https://blog.csdn.net/cxzhq2002/article/details/50056885

    持续集成想必大家很多人都听说过,甚至都实践过,最近我又一次亲历了一次持续集成,现将我的经验分享给大家。关于持续集成的理论在本文概不涉及,本文的主要目的是实战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:dailybuild</workingDirectory>
    <artifactDirectory>E:dailybuild</artifactDirectory>
    <category>TestProject</category>
    <sourcecontrol type="vsts" autoGetSource="true"  applyLabel="false">
      <server>http://tfs1.TestProject.com:8080</server>
      <domain>TestProject.com</domain>
      <project>$/TestProject projects/Analysis and DesignConciergePrototype</project>
      <workingDirectory>E:dailybuildTestProject</workingDirectory>
      <cleanCopy>true</cleanCopy>
    </sourcecontrol>
    View Code

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

    <artifactDirectory>d:svnLogMyProject</artifactDirectory>
    <sourcecontrol type="svn">
      <executable>C:Program FilesTortoiseSVNinsvn.exe</executable>
      <username>UserName</username>
      <password>******</password>
      <autoGetSource>true</autoGetSource>
      <trunkUrl>http://svnserver/trunk/MyProject</trunkUrl>
      <workingDirectory>d:svn	runkMyProject</workingDirectory>
    </sourcecontrol>
    View Code 

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

    <tasks>
      <msbuild>
        <executable>C:WindowsMicrosoft.NETFrameworkv4.0.30319MSBuild.exe</executable>
        <buildArgs>/p:OutputPath=D:BuildOutput</buildArgs>
        <workingDirectory>D:svnranchproject</workingDirectory>
        <projectFile>mysolution.sln</projectFile>
        <targets>Build</targets>
        <timeout>9000</timeout>
      </msbuild>
    </tasks>
    View Code

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

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

    CodeCoverage.runsettings的配置内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <RunSettings>
      <RunConfiguration>
        <!-- Path relative to solution directory -->
        <ResultsDirectory>d:svnlogTestResults</ResultsDirectory>
    
        <!-- [x86] | x64  
          - You can also change it from menu Test, Test Settings, Default Processor Architecture -->
        <TargetPlatform>x86</TargetPlatform>
    
        <!-- Framework35 | [Framework40] | Framework45 -->
        <TargetFrameworkVersion>Framework40</TargetFrameworkVersion>
      </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>
                <!-- Match assembly file paths: -->
                <ModulePaths>
                  <Include>
                    <ModulePath>.*.dll$</ModulePath>
                    <ModulePath>.*.exe$</ModulePath>
                  </Include>
                  <Exclude>
                    <ModulePath>.*CPPUnitTestFramework.*</ModulePath>
                  </Exclude>
                </ModulePaths>
    
                <!-- Match fully qualified names of functions: -->
                <!-- (Use "." to delimit namespaces in C# or Visual Basic, "::" in C++.)  -->
                <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>
    
                <!-- Match attributes on any code element: -->
                <Attributes>
                  <Exclude>
                    <!-- Don’t forget "Attribute" at the end of the name -->
                    <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>
    
                <!-- Match the path of the source files in which each method is defined: -->
                <Sources>
                  <Exclude>
                    <Source>.*\atlmfc\.*</Source>
                    <Source>.*\vctools\.*</Source>
                    <Source>.*\public\sdk\.*</Source>
                    <Source>.*\microsoft sdks\.*</Source>
                    <Source>.*\vc\include\.*</Source>
                  </Exclude>
                </Sources>
    
                <!-- Match the company name property in the assembly: -->
                <CompanyNames>
                  <Exclude>
                    <CompanyName>.*microsoft.*</CompanyName>
                  </Exclude>
                </CompanyNames>
    
                <!-- Match the public key token of a signed assembly: -->
                <PublicKeyTokens>
                  <!-- Exclude Visual Studio extensions: -->
                  <Exclude>
                    <PublicKeyToken>^B77A5C561934E089$</PublicKeyToken>
                    <PublicKeyToken>^B03F5F7F11D50A3A$</PublicKeyToken>
                    <PublicKeyToken>^31BF3856AD364E35$</PublicKeyToken>
                    <PublicKeyToken>^89845DCD8080CC91$</PublicKeyToken>
                    <PublicKeyToken>^71E9BCE111E9429C$</PublicKeyToken>
                    <PublicKeyToken>^8F50407C4E9E73B6$</PublicKeyToken>
                    <PublicKeyToken>^E361AF139669C375$</PublicKeyToken>
                  </Exclude>
                </PublicKeyTokens>
    
    
                <!-- We recommend you do not change the following values: -->
                <UseVerifiableInstrumentation>True</UseVerifiableInstrumentation>
                <AllowLowIntegrityProcesses>True</AllowLowIntegrityProcesses>
                <CollectFromChildProcesses>True</CollectFromChildProcesses>
                <CollectAspDotNet>False</CollectAspDotNet>
    
              </CodeCoverage>
            </Configuration>
          </DataCollector>
        </DataCollectors>
      </DataCollectionRunSettings>
    </RunSettings>
    View Code

    里面最重要的信息室配置了单元测试结果存放路径:<ResultsDirectory>d:svnlogTestResults</ResultsDirectory>,以便我们后来生成测试结果。

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

    <!--删除上次单元测试结果-->
    <exec>
      <executable>D:svn	ooldelfile.bat</executable>
      <buildArgs>D:svnLogTestResultsRealmstest-results.trx</buildArgs>
      <buildTimeoutSeconds>300</buildTimeoutSeconds>
      <successExitCodes>-1,0</successExitCodes>
    </exec>
    <exec>
      <executable>D:svn	ooldelfile.bat</executable>
      <buildArgs>D:svnLogTestResultsRealmstest-coverage.xml</buildArgs>
      <buildTimeoutSeconds>300</buildTimeoutSeconds>
      <successExitCodes>-1,0</successExitCodes>
    </exec>
    <!--执行单元测试-->
    <exec>
      <executable>C:Program Files (x86)Microsoft Visual Studio 12.0Common7IDECommonExtensionsMicrosoftTestWindowVSTest.Console.exe</executable>
      <baseDirectory>D:svnUnitTest.dll所在的文件目录</baseDirectory>
      <buildArgs>UnitTest.dll /Enablecodecoverage /Settings:D:svn	oolCodeCoverage.runsettings /logger:trx</buildArgs>
      <buildTimeoutSeconds>300</buildTimeoutSeconds>
    </exec>
    <!--生成测试覆盖率-->
    <exec>
      <executable>
        <!--删除上次单元测试结果-->
        <exec>
          <executable>D:svn	ooldelfile.bat</executable>
          <buildArgs>D:svnLogTestResultsRealmstest-results.trx</buildArgs>
          <buildTimeoutSeconds>300</buildTimeoutSeconds>
          <successExitCodes>-1,0</successExitCodes>
        </exec>
        <exec>
          <executable>D:svn	ooldelfile.bat</executable>
          <buildArgs>D:svnLogTestResultsRealmstest-coverage.xml</buildArgs>
          <buildTimeoutSeconds>300</buildTimeoutSeconds>
          <successExitCodes>-1,0</successExitCodes>
        </exec>
        <!--执行单元测试-->
        <exec>
          <executable>C:Program Files (x86)Microsoft Visual Studio 12.0Common7IDECommonExtensionsMicrosoftTestWindowVSTest.Console.exe</executable>
          <baseDirectory>D:svnUnitTest.dll所在的文件目录</baseDirectory>
          <buildArgs>UnitTest.dll /Enablecodecoverage /Settings:D:svn	oolCodeCoverage.runsettings /logger:trx</buildArgs>
          <buildTimeoutSeconds>300</buildTimeoutSeconds>
        </exec>
        <!--生成测试覆盖率-->
        <exec>
          <executable>D:svn	oolcoverageAuto.Dealer.UnitTest.Tool.exe</executable>
          <buildArgs>D:svnlogTestResults D:svnlogTestResultsRealmstest-results.trx D:svnlogTestResultsRealmstest-coverage.xml</buildArgs>
          <buildTimeoutSeconds>300</buildTimeoutSeconds>
          <successExitCodes>-1,0</successExitCodes>
        </exec>
    
        <!--合并xml文件-->
        <merge>
          <files>
            <file>D:svnLogTestResultsRealmstest-results.trx</file>
            <!--这个文件是用于合并UnitTest result-->
          </files>
        </merge>
        <merge>
          <files>
            <file>D:svnLogTestResultsRealmstest-coverage.xml</file>
            <!--这个文件是用于合并UnitTest result-->
          </files>
        </merge>D:svn	oolcoverageAuto.Dealer.UnitTest.Tool.exe</executable>
      <buildArgs>D:svnlogTestResults D:svnlogTestResultsRealmstest-results.trx D:svnlogTestResultsRealmstest-coverage.xml</buildArgs>
      <buildTimeoutSeconds>300</buildTimeoutSeconds>
      <successExitCodes>-1,0</successExitCodes>
    </exec>
    
    <!--合并xml文件-->
    <merge>
      <files>
        <file>D:svnLogTestResultsRealmstest-results.trx</file>
        <!--这个文件是用于合并UnitTest result-->
      </files>
    </merge>
    <merge>
      <files>
        <file>D:svnLogTestResultsRealmstest-coverage.xml</file>
        <!--这个文件是用于合并UnitTest result-->
      </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\_PublishedWebsitesMyWeb</sourceDir>
      <publishDir>\IP地址website</publishDir>
      <useLabelSubDirectory>false</useLabelSubDirectory>
    </buildpublisher>
    View Code

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

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

    6. 邮件提醒功能

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

    <publishers>
      <email mailport="25" includeDetails="TRUE" mailhostUsername="my@sina.com" mailhostPassword="******" useSSL="FALSE">
        <from>my@sina.com</from>
        <mailhost>smtp.sina.net</mailhost>
        <users>
          <user name="张三" group="developers" address="123@sina.com" />
          <user name="李四" group="developers" address="456@sina.com" />
          <user name="王五" group="developers" address="789@sina.com" />
        </users>
        <groups>
          <group name="developers">
            <notifications>
              <notificationType>Failed</notificationType>
              <notificationType>Fixed</notificationType>
            </notifications>
          </group>
          <group name="buildmaster">
            <notifications>
              <notificationType>Always</notificationType>
            </notifications>
          </group>
        </groups>
        <converters>
          <regexConverter find="$" replace="@sina.com" />
        </converters>
        <modifierNotificationTypes>
          <NotificationType>Failed</NotificationType>
          <NotificationType>Fixed</NotificationType>
        </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/,可以看到如下连接,下载并安装。就可以监控制定的项目了。

    8.应用plugin显示集成结果

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

    <buildPlugins>
      <buildReportBuildPlugin>
        <xslFileNames>
          <xslFile>xslheader.xsl</xslFile>
          <xslFile>xslmodifications.xsl</xslFile>
          <xslFile>xslunittests.xsl</xslFile>
          <xslFile>xslMsTestSummary2008.xsl</xslFile>
          <xslFile>xslcompile-msbuild.xsl</xslFile>
          <xslFile>xslSimianSummary.xsl</xslFile>
          <xslFile>xslMsTestSummary2010.xsl</xslFile>
          <xslFile>xslMsTestSummary.xsl</xslFile>
          <xslFile>xslMsTestReport2010.xsl</xslFile>
          <xslFile>xslMsTestCover2010.xsl</xslFile>
        </xslFileNames>
      </buildReportBuildPlugin>
    </buildPlugins>
    View Code

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

    9.设置集成策略

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

    <scheduleTrigger time="23:30" buildCondition="ForceBuild" name="Scheduled">
      <weekDays>
        <weekDay>Monday</weekDay>
        <weekDay>Tuesday</weekDay>
        <weekDay>Wednesday</weekDay>
        <weekDay>Thursday</weekDay>
        <weekDay>Friday</weekDay>
      </weekDays>
    </scheduleTrigger>
    View Code

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

  • 相关阅读:
    我的友情链接
    我的友情链接
    区块链:权益证明设计哲学
    区块链:权益证明与错误的工程思维
    区块链:Ethereum Casper 101
    区块链:Casper 机制的历史起源-第五篇
    区块链:Casper 机制的历史起源-第四篇
    区块链:Casper 机制的历史起源-第三篇
    区块链:Casper 机制的历史起源:第二篇
    区块链:Casper 机制的历史起源:第一篇
  • 原文地址:https://www.cnblogs.com/zxtceq/p/10735548.html
Copyright © 2020-2023  润新知