TeamCity整合Source Monitor報表

Apr 23, 2014

12 mins read

Source Monitor是用來分析程式碼度量的工具,先到[官網](http://www.campwoodsw.com/sourcemonitor.html)下載
[![](http://1.bp.blogspot.com/-aUW-QXGVCtE/U1drxYfiw4I/AAAAAAAABSk/phO8_RBI2Os/s1600/01.%E4%B8%8B%E8%BC%89.png)](http://1.bp.blogspot.com/-aUW-QXGVCtE/U1drxYfiw4I/AAAAAAAABSk/phO8_RBI2Os/s1600/01.%E4%B8%8B%E8%BC%89.png)
安裝後的預設路徑為C:\Program Files (x86)\SourceMonitor
[![](http://4.bp.blogspot.com/-MKLglO_Layc/U1dr6iQoHSI/AAAAAAAABSs/JSEVH5l68VE/s1600/02.%E5%AE%89%E8%A3%9D%E8%B7%AF%E5%BE%91.png)](http://4.bp.blogspot.com/-MKLglO_Layc/U1dr6iQoHSI/AAAAAAAABSs/JSEVH5l68VE/s1600/02.%E5%AE%89%E8%A3%9D%E8%B7%AF%E5%BE%91.png)
先淮備一個用來產生報告的設定檔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](http://www.microsoft.com/en-us/download/details.aspx?id=21714)
[![](http://4.bp.blogspot.com/-1zIhVE-ezj0/U1dsCkgZ1AI/AAAAAAAABS0/CSALVxR5RMw/s1600/03.%E4%B8%8B%E8%BC%89msxsl.png)](http://4.bp.blogspot.com/-1zIhVE-ezj0/U1dsCkgZ1AI/AAAAAAAABS0/CSALVxR5RMw/s1600/03.%E4%B8%8B%E8%BC%89msxsl.png)
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>

&lt;br/&gt;

&lt;!-- The most deeply nested code blocks --&gt;
&lt;table class="section-table" cellpadding="2" cellspacing="0" border="0" width="98%"&gt;
  &lt;!--&lt;colgroup&gt;
    &lt;col width="50px"/&gt;
    &lt;col /&gt;
    &lt;col width="50px" /&gt;
  &lt;/colgroup&gt;--&gt;
  &lt;tr&gt;
    &lt;td class="sectionheader" colspan="4"&gt;           
       SourceMonitor - &lt;xsl:value-of select="count(MostDeeplyNestedCode/Block)" /&gt; Most Deeply Nested Code Blocks
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;th class="header-label"&gt;
      Depth
    &lt;/th&gt;
    &lt;th class="header-label"&gt;
      File
    &lt;/th&gt;
    &lt;th class="header-label"&gt;
      Line
    &lt;/th&gt;
  &lt;/tr&gt;
  &lt;xsl:apply-templates select="MostDeeplyNestedCode/Block" /&gt;
&lt;/table&gt;

</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>

    &lt;LinePerMethod&gt;
      &lt;xsl:call-template name="LinesPerMethod"/&gt;
    &lt;/LinePerMethod&gt;

    &lt;MostDeeplyNestedCode&gt;
      &lt;xsl:call-template name="MostDeeplyNestedCode"/&gt;
    &lt;/MostDeeplyNestedCode&gt;

  &lt;/SourceMonitorComplexitySummary&gt;

</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” />

  &lt;xsl:choose&gt;
    &lt;xsl:when test="position() &amp;lt; 16"&gt;
       &lt;Method&gt;
          &lt;File&gt;&lt;xsl:value-of select="@file_name"/&gt;&lt;/File&gt;
          &lt;Name&gt;&lt;xsl:value-of select="metrics/metric[@id='M9']"/&gt;&lt;/Name&gt;
          &lt;Line&gt;&lt;xsl:value-of select="metrics/metric[@id='M8']"/&gt;&lt;/Line&gt;
          &lt;Complexity&gt;&lt;xsl:value-of select="metrics/metric[@id='M10']"/&gt;&lt;/Complexity&gt;
       &lt;/Method&gt;
    &lt;/xsl:when&gt;
  &lt;/xsl:choose&gt;
&lt;/xsl:for-each&gt;

</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” />

  &lt;xsl:choose&gt;
    &lt;xsl:when test="position() &amp;lt; 16"&gt;
       &lt;Method&gt;
          &lt;File&gt;&lt;xsl:value-of select="@file_name"/&gt;&lt;/File&gt;
          &lt;Lines&gt;&lt;xsl:value-of select="metrics/metric[@id='M5']"/&gt;&lt;/Lines&gt;
       &lt;/Method&gt;
    &lt;/xsl:when&gt;
  &lt;/xsl:choose&gt;
&lt;/xsl:for-each&gt;

</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” />

    &lt;xsl:choose&gt;
      &lt;xsl:when test="position() &amp;lt; 16"&gt;
         &lt;Block&gt;
            &lt;File&gt;&lt;xsl:value-of select="@file_name"/&gt;&lt;/File&gt;
            &lt;Depth&gt;&lt;xsl:value-of select="metrics/metric[@id='M12']"/&gt;&lt;/Depth&gt;
            &lt;Line&gt;&lt;xsl:value-of select="metrics/metric[@id='M11']"/&gt;&lt;/Line&gt;
         &lt;/Block&gt;
      &lt;/xsl:when&gt;
    &lt;/xsl:choose&gt;
&lt;/xsl:for-each&gt;

</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的資料夾,把相關的執行檔和設定檔都放進去
[![](http://2.bp.blogspot.com/-fB6efdi3sLY/U1dt1d9N2lI/AAAAAAAABTo/sM9uAiTT144/s1600/04.%E5%BB%BA%E7%BD%AE%E5%8B%95%E4%BD%9C.png)](http://2.bp.blogspot.com/-fB6efdi3sLY/U1dt1d9N2lI/AAAAAAAABTo/sM9uAiTT144/s1600/04.%E5%BB%BA%E7%BD%AE%E5%8B%95%E4%BD%9C.png)
新增一個建置報告
[![](http://3.bp.blogspot.com/-d6YFhZeqscQ/U1dsmWfvj9I/AAAAAAAABTE/m8iJnDT3NjY/s1600/05.%E6%96%B0%E5%A2%9EBuild+Report.png)](http://3.bp.blogspot.com/-d6YFhZeqscQ/U1dsmWfvj9I/AAAAAAAABTE/m8iJnDT3NjY/s1600/05.%E6%96%B0%E5%A2%9EBuild+Report.png)
給一個用來識別的名稱和輸入產生的檔案
[![](http://1.bp.blogspot.com/-HWTCgjCV7ao/U1dsw1-UY8I/AAAAAAAABTM/agiFf-B1Uqk/s1600/06.Build+Report.png)](http://1.bp.blogspot.com/-HWTCgjCV7ao/U1dsw1-UY8I/AAAAAAAABTM/agiFf-B1Uqk/s1600/06.Build+Report.png)
在一般設定中的Artifact Paths加入輸出的檔案
[![](http://4.bp.blogspot.com/-M548qVSUE3s/U1dtAFUY41I/AAAAAAAABTU/mgfaj3i2UV8/s1600/07.%E4%B8%80%E8%88%AC%E8%A8%AD%E5%AE%9A.png)](http://4.bp.blogspot.com/-M548qVSUE3s/U1dtAFUY41I/AAAAAAAABTU/mgfaj3i2UV8/s1600/07.%E4%B8%80%E8%88%AC%E8%A8%AD%E5%AE%9A.png)
設定正確的話,建置後就可以看到這個報表了
[![](http://4.bp.blogspot.com/-aMSRvswmn08/U1dtFFT5nKI/AAAAAAAABTc/ClKODzPaZFo/s1600/08.Report.png)](http://4.bp.blogspot.com/-aMSRvswmn08/U1dtFFT5nKI/AAAAAAAABTc/ClKODzPaZFo/s1600/08.Report.png)
參考資料 [CI Server 16 - 整合程式碼複雜度及深度報表 (Source Monitor)](http://ithelp.ithome.com.tw/question/10107051)

Sharing is caring!