2014年4月23日 星期三

TeamCity整合Source Monitor報表

Source Monitor是用來分析程式碼度量的工具,先到官網下載

安裝後的預設路徑為C:\Program Files (x86)\SourceMonitor

先淮備一個用來產生報告的設定檔SourceMonitorCommands.xml

<?xml version="1.0" encoding="utf-8"?>
<sourcemonitor_commands>
    <write_log>true</write_log>
    <command>
        <project_file>SourceMonitor.smp</project_file>
        <checkpoint_name>Baseline</checkpoint_name>
        <project_language>C#</project_language>
        <!-- 要分析專案的相對路徑 -->
        <source_directory>..</source_directory>
        <source_subdirectory_list>
            <exclude_subdirectories>true</exclude_subdirectories>
            <source_subtree>bin\</source_subtree>
            <source_subdirectory>obj\</source_subdirectory>
        </source_subdirectory_list>
        <parse_utf8_files>True</parse_utf8_files>
        <ignore_headers_footers>True</ignore_headers_footers>
        <export>
            <!-- 最後輸出的檔名 -->
            <export_file>SourceMonitorReport.xml</export_file>
            <export_type>2</export_type>
        </export>
    </command>
</sourcemonitor_commands>

因為輸出的是XML格式,所以需要透過XSL轉成HTML格式
先下載轉換的工具msxsl.exe

SourceMonitor.xsl
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/xhtml1/strict">
  <xsl:output method="html"/>
  
  <xsl:template match="/">
  <html>
        <head>
        <style type="text/css">
    /* 
 Web20 Table Style
 written by Netway Media, http://www.netway-media.com
*/
    table
    {
        border-collapse: collapse;
        border: 1px solid #666666;
        font: normal 11px verdana, arial, helvetica, sans-serif;
        color: #363636;
        background: #f6f6f6;
        text-align: left;
    }
    caption
    {
        text-align: center;
        font: bold 16px arial, helvetica, sans-serif;
        background: transparent;
        padding: 6px 4px 8px 0px;
        color: #CC00FF;
        text-transform: uppercase;
    }
    thead, tfoot
    {
        background: url(bg1.png) repeat-x;
        text-align: left;
        height: 30px;
    }
    thead th, tfoot th
    {
        padding: 5px;
    }
    table a
    {
        color: #333333;
        text-decoration: none;
    }
    table a:hover
    {
        text-decoration: underline;
    }
    tr.odd
    {
        background: #f1f1f1;
    }
    tbody th, tbody td
    {
        padding: 5px;
        padding-left: 10px;
    }
    td.sectionheader
    {
        color: Navy;
        font-size: 20px;
        font-weigth: bold;
        text-align: center;
    }
</style>
        </head>
        <body>
    <xsl:apply-templates select="//SourceMonitorComplexitySummary" />     
    </body>
    </html>
  </xsl:template>
  
 <!-- The most complex methods -->
  <xsl:template match="SourceMonitorComplexitySummary">
    <table class="section-table" cellpadding="2" cellspacing="0" border="0" width="98%">
      <!--<colgroup>
        <col width="300px" />
        <col width="50px" />
        <col />
        <col width="50px" />
      </colgroup>-->
      <tr>
        <td class="sectionheader" colspan="4">
           SourceMonitor - <xsl:value-of select="count(MostComplexMethods/Method)" /> Most Complex Methods
        </td>
      </tr>
      <tr>
        <th class="header-label">
          Complexity
        </th>
        <th class="header-label">
          File
        </th>
        <th class="header-label">
          Method
        </th>        
        <th class="header-label">
          Line
        </th>
      </tr>
      <xsl:apply-templates select="MostComplexMethods/Method" />
    </table>
    
    <br/>
    
    <!-- The most deeply nested code blocks -->
    <table class="section-table" cellpadding="2" cellspacing="0" border="0" width="98%">
      <!--<colgroup>
        <col width="50px"/>
        <col />
        <col width="50px" />
      </colgroup>-->
      <tr>
        <td class="sectionheader" colspan="4">           
           SourceMonitor - <xsl:value-of select="count(MostDeeplyNestedCode/Block)" /> Most Deeply Nested Code Blocks
        </td>
      </tr>
      <tr>
        <th class="header-label">
          Depth
        </th>
        <th class="header-label">
          File
        </th>
        <th class="header-label">
          Line
        </th>
      </tr>
      <xsl:apply-templates select="MostDeeplyNestedCode/Block" />
    </table>
  </xsl:template>

  <!-- Complex Method List -->
  <xsl:template match="MostComplexMethods/Method">
      <tr>
        <xsl:if test="position() mod 2 = 1">
          <xsl:attribute name="class">section-oddrow odd</xsl:attribute>          
        </xsl:if>
        <td>
          <xsl:value-of select="Complexity" />
        </td>
        <td >
          <xsl:value-of select="File" />
        </td>
        <td>
          <xsl:value-of select="Name"/>
        </td>        
        <td>
          <xsl:value-of select="Line" />
        </td>
      </tr>
  </xsl:template>

  <!-- Deeply Nested Blocks List -->
  <xsl:template match="MostDeeplyNestedCode/Block">
      <tr>
        <xsl:if test="position() mod 2 = 1">
          <xsl:attribute name="class">section-oddrow odd</xsl:attribute>
        </xsl:if>
        <td>
          <xsl:value-of select="Depth" />
        </td>
        <td>
          <xsl:value-of select="File" />
        </td>
        <td>
          <xsl:value-of select="Line" />
        </td>
      </tr>
  </xsl:template>

</xsl:stylesheet>


SourceMonitorSummaryGeneration.xsl
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
  <!--- SourceMonitor Summary Xml File Generation created by Eden Ridgway -->
  <xsl:output method="xml"/>
  
  <xsl:template match="/">
    <xsl:apply-templates select="/sourcemonitor_metrics" />
  </xsl:template>
  
  <!-- Transform the results into a simpler more intuitive and summarised format -->
  <xsl:template match="sourcemonitor_metrics">
      <SourceMonitorComplexitySummary>
        <MostComplexMethods>
          <xsl:call-template name="MostComplexMethods"/>
        </MostComplexMethods>
        
        <LinePerMethod>
          <xsl:call-template name="LinesPerMethod"/>
        </LinePerMethod>

        <MostDeeplyNestedCode>
          <xsl:call-template name="MostDeeplyNestedCode"/>
        </MostDeeplyNestedCode>
        
      </SourceMonitorComplexitySummary>
  </xsl:template>

  <!-- Complexity Metrics -->
  <xsl:template name="MostComplexMethods">
    <xsl:for-each select=".//file">
      <xsl:sort select="metrics/metric[@id='M10']" order="descending" data-type="number" />
      
      <xsl:choose>
        <xsl:when test="position() &lt; 16">
           <Method>
              <File><xsl:value-of select="@file_name"/></File>
              <Name><xsl:value-of select="metrics/metric[@id='M9']"/></Name>
              <Line><xsl:value-of select="metrics/metric[@id='M8']"/></Line>
              <Complexity><xsl:value-of select="metrics/metric[@id='M10']"/></Complexity>
           </Method>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>

  <!-- Complexity Metrics -->
  <xsl:template name="LinesPerMethod">
    <xsl:for-each select=".//file">
      <xsl:sort select="metrics/metric[@id='M5']" order="descending" data-type="number" />
      
      <xsl:choose>
        <xsl:when test="position() &lt; 16">
           <Method>
              <File><xsl:value-of select="@file_name"/></File>
              <Lines><xsl:value-of select="metrics/metric[@id='M5']"/></Lines>
           </Method>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>

  <!-- Nesting Metrics -->
  <xsl:template name="MostDeeplyNestedCode">
    <xsl:for-each select=".//file">
        <xsl:sort select="metrics/metric[@id='M12']" order="descending" data-type="text" />
      
        <xsl:choose>
          <xsl:when test="position() &lt; 16">
             <Block>
                <File><xsl:value-of select="@file_name"/></File>
                <Depth><xsl:value-of select="metrics/metric[@id='M12']"/></Depth>
                <Line><xsl:value-of select="metrics/metric[@id='M11']"/></Line>
             </Block>
          </xsl:when>
        </xsl:choose>
    </xsl:for-each>
  </xsl:template>
  
</xsl:stylesheet>


透過批次檔得到HTML格式
SourceMonitor.exe /C SourceMonitorCommands.xml
msxsl.exe SourceMonitorReport.xml SourceMonitorSummaryGeneration.xsl -o SourceMonitorSummaryGeneration.xml
msxsl.exe SourceMonitorSummaryGeneration.xml SourceMonitor.xsl -o SourceMonitorResult.html

在TeamCity上面利用Command Line的Build Step來產出檔案
方便請見所以建立一個SourceMonitor的資料夾,把相關的執行檔和設定檔都放進去

新增一個建置報告
給一個用來識別的名稱和輸入產生的檔案

在一般設定中的Artifact Paths加入輸出的檔案


設定正確的話,建置後就可以看到這個報表了