StyleCop の結果を Jenkins Violations Plugin で表示すると違反箇所のソースコードが表示されないことがある 解決策その2

StyleCop の結果を Jenkins Violations Plugin で表示すると違反箇所のソースコードが表示されないことがある - お だ のスペース で書いてた、第1回 Jenkins駆込み寺 in 大阪 - connpass のときに発表した内容をまとめます。


解決方法としては、StyleCop の結果を Jenkins Violations Plugin で表示すると違反箇所のソースコードが表示されないことがある - お だ のスペース の方がシンプルですので、使う方は前回の方を参考に。


Jenkins の Violation Plugin の画面を見てみましょう。


この状態だと、StyleCop 側ではソースのリンクを押してもブランクのページが表示されます。FxCop の方では、正しくソースが表示されます。
FxCop と StyleCop では、ファイルパスの出方が違っています。
リンクを押してもソースが表示されないのはここが問題なのかなと考えて、FxCop と StyleCop が出力する xml を確認してみました。

〜.CodeAnalysisLog.xml (FxCop の結果ファイル) の抜粋

<Message TypeName="MarkMembersAsStatic" Category="Microsoft.Performance" CheckId="CA1822" Status="Active" Created="2012-12-30 10:42:09Z" FixCategory="NonBreaking">
  <Issue Certainty="95" Level="Warning" Path="c:\Users\Shinsuke\.jenkins\workspace\test\ConsoleApplication1\ConsoleApplication1" File="Class1.cs" Line="10"></Issue>
</Message>

Path と File の属性が分かれています。対して StyleCop では、

StyleCopReport.xml (StyleCop の結果ファイル) の抜粋

<Violation RuleId="SA1600" Rule="ElementsMustBeDocumented" RuleNamespace="StyleCop.CSharp.DocumentationRules" Source="C:\Users\Shinsuke\.jenkins\workspace\test\ConsoleApplication1\ConsoleApplication1\Class1.cs" LineNumber="8" Section="Root.ConsoleApplication1.class1"></Violation>

Source に絶対パスが書かれています。
Jenkins の Violation Plugin の画面では、StyleCop の結果はドライブレターが無いだけで、結果ファイルほぼそのままのパスが出ています。


では、StyleCop の結果ファイルの Source 属性を無理矢理編集して、FxCop と同じ位置まで削ってみました。

C:\Users\Shinsuke\.jenkins\workspace\test\ を削った

<Violation RuleId="SA1600" Rule="ElementsMustBeDocumented" RuleNamespace="StyleCop.CSharp.DocumentationRules" Source="ConsoleApplication1\ConsoleApplication1\Class1.cs" LineNumber="8" Section="Root.ConsoleApplication1.class1"></Violation>

Violation Plugin で確認すると、パスは FxCop と同じ様に表示されています。

また、リンクをクリックしても正しくソースファイルが表示されています。


というわけで、StyleCop の結果ファイルから、.csproj が置いてあるディレクトリを除けば良いということになりました。
これも MSBuild でやってしまいましょう。タスク用の dll を作るのは面倒なので以前にも書いたインラインタスクで処理します。
MSBuild 4.0 からインラインタスクが書けます - お だ のスペース

.csproj の抜粋

  <UsingTask TaskName="ReplaceStyleCopResult" TaskFactory="CodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
    <ParameterGroup>
      <PATH ParameterType="System.String" Required="true" />
      <WORKSPACE ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Code Type="Fragment" Language="cs">
        <![CDATA[
        var content = File.ReadAllText(PATH);
        File.WriteAllText(PATH, content.Replace(WORKSPACE, ""));
]]>
      </Code>
    </Task>
  </UsingTask>
  <Target Name="StyleCop">
    <!-- Create a collection of files to scan -->
    <CreateItem Include=".\**\*.cs">
      <Output TaskParameter="Include" ItemName="StyleCopFiles" />
    </CreateItem>
    <StyleCopTask ProjectFullPath="$(MSBuildProjectFile)" 
      SourceFiles="@(StyleCopFiles)" ForceFullAnalysis="true" 
      TreatErrorsAsWarnings="true" OutputFile="StyleCopReport.xml" 
      CacheResults="true" />
    <ReplaceStyleCopResult PATH="StyleCopReport.xml" WORKSPACE="$(MSBuildProjectDirectory)" />
  </Target>

StyleCop ターゲットの中で StyleCopTask、ReplaceStyleCopResult タスクを実行しています。
ReplaceStyleCopResult は C# で実装したインラインタスクです。
これは、StyleCop の結果ファイルと、.csproj ファイルがあるパスを受け取って置換するだけのタスクです。

ReplaceStylleCopResult の実装

var content = File.ReadAllText(PATH);
File.WriteAllText(PATH, content.Replace(WORKSPACE, ""));

これで、Jenkins Violation Plugin の結果画面でも正しく表示される結果ファイルが出来ました。


という解決方法を取ったのですが、前回紹介した解決方法の方が楽そう*1なのでそちらをお薦めします。

*1:StyleCop の結果ファイルをJenkins のワークスペース直下になるようにする