7
votes

I am trying to set/override some settings in our TEST installation of TFS with regards to forcing Code Analysis and assosicated settings during the build process (regardless of the setting sin the project file)

We currently use in our TEST TFS installation:

  • Visual Studio 2012 Ultimate on our developer machines AND build server
  • Have TFS 2012 installed on one server (application and data layer)
  • Have TFS 2012 build service (controller and agent) installed on another server

We can compile sample .net 4.5 projects (class libraries (DLLs), web applications etc) as expected. This is solely to do with overriding associated Code Analysis settings (hopefully).

Scenario 1 - In our sample applications on our developer machines when you select the project settings (right click -> properties in solution explorer), go to the Code Analysis tab if I turn on the "Enable Code Analysis on build" and select a Rule set from the drop down is performs as exepcted, hence it will generate some warnings. This technical adds <RunCodeAnalysis>false</RunCodeAnalysis> to the *.csproj file if opened up in notepad. If the build is executed to compile the sample project/solution then Code Analysis is performed as expected. I do NOT want to do this on every project because a developer could turn it off (although I am looking to have check-in policies and/or private/gated checkins as well to force this anyway).

Scenario 2 - I can disable the "Enable Code Analysis on Build" checkbox and force code analysis in our TFSBuild.proj file (we (will) use the default upgradetemplate.xaml as our process definition because we will be upgrading from TFS 2008 on our LIVE TFS installation) by having:

<RunCodeAnalysis>Always</RunCodeAnalysis>

This works and this is how we will force (lessons still to be learned :-)) Code Analysis on our builds.

The problem then comes when setting other assosicated Code Analysis settings. For example which default rule set(s) to apply/use or treat CA warnings as errors. Some of these settings can be set either in VS or all of them by editting *.csproj in notepad. If i edit the *.csproj then these values are used in the build as expected (as well as locally on the developer machine). This is not ideal as I want to do it centrally in TFSBuild.proj without having to edit every project file. I believe I can use settings such as in my TFSbuild.proj file:

<PropertyGroup>
    <RunCodeAnalysis>Always</RunCodeAnalysis>
    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
    <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
</PropertyGroup>

But they don't appear to work or I am putting them in the wrong place? How do I fix/use them correctly?

FYI i build my solutions in TFSBuild.proj by:

<Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">

  <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets" />
          <ItemGroup>
            <SolutionToBuild Include="/some folder/some solution.sln" />
            <ConfigurationToBuild Include="Debug|Any CPU">
               <FlavorToBuild>Debug</FlavorToBuild>
               <PlatformToBuild>Any CPU</PlatformToBuild>
             </ConfigurationToBuild>
          </ItemGroup>
</Project>

On the build server I did find reference to the target file for Code Analysis at c:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\CodeAnalysis but I dont want to change the default behaviour on the build server (although it does work when I do). The condition for example for CodeAnalysisTreatWarningsAsErrors must be getting evaluated as false. Its like my values are not read from TFSBuild.proj but are from the .csproj file.

Any questions feel free to ask and thanks in advance

2

2 Answers

2
votes

I had what I think is a similar problem with Cruise Control not compiling using the CODE_ANALYSIS compilation symbol, even if "Enable Code Analysis on Build (defines CODE_ANALYSIS constant)" was checked in VS.Net.

It looks like whether it is check or not, CODE_ANALYSIS is actually not explicitly added to the list of compilation symbols in the csproj (even if it appears in the text box "Conditional compilation symbols"), only <RunCodeAnalysis>true</RunCodeAnalysis> is added.

When compiling through VS.Net, the CODE_ANALYSIS is automatically added, but not when using MSBuild, which is what Cruise Control uses.

I eventually changed in VS.Net the "Conditional compilation symbols" from "CODE_ANALYSIS;MySymbol" to "MySymbol;CODE_ANALYSIS". Doing that forced CODE_ANALYSIS to also appear in the csproj.

1
votes

I remember having a similar problem - but not having the time to investigate it, I worked around it by calling FxCop directly using the exec task. I'll just give you the highlights, omitting the specification of some properties, I hope the names are clear.

I created an ItemGroup of the output dlls, FilesToAnalyze, and fed it to FxCop in a way similar to:

<PropertyGroup>
      <FxCopErrorLinePattern>: error</FxCopErrorLinePattern>
      <FxCopCommand>"$(FxCopPath)" /gac /rule:"$(FxCopRules)" /ruleset:="$(FxCopRuleSet)"  @(FilesToAnalyze->'/file:"%(identity)"', ' ') /out:$(FullFxCopLog) /console | Find "$(FxCopErrorLinePattern)" > "$(FxCopLogFile)"</FxCopCommand>
</PropertyGroup>    

<Exec Command="$(FxCopCommand)"
      ContinueOnError="true">
  <Output TaskParameter="ExitCode" PropertyName="FxCopExitCode"/>
</Exec>

<ReadLinesFromFile File="$(FxCopLogFile)">
    <Output TaskParameter="Lines" ItemName="AllErrorLines"/>
</ReadLinesFromFile>

I could then determine the number of errors in the output using an extensionpack task:

<MSBuild.ExtensionPack.Framework.MsBuildHelper TaskAction="GetItemCount" InputItems1="@(AllErrorLines)">
    <Output TaskParameter="ItemCount" PropertyName="FxErrorCount"/>
</MSBuild.ExtensionPack.Framework.MsBuildHelper>

and create a failing build step for each error:

<BuildStep TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
        BuildUri="$(BuildUri)"
        Id="$(FxCopStep)"
        Status="Failed"
        Message="FxCop Failed: $(FxErrorCount) errors."/>

<BuildStep TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
                BuildUri="$(BuildUri)"
                Status="Failed"
                Message="%(AllErrorLines.Identity)"/>

By doing code analysis on the build server this way, we also avoided having to configure each project separately. We isolated all this in a separate .targets file, so adding code analysis to a solution was a matter of importing that file, and perhaps adjusting the behavior by setting appropriate properties.