StyleCop in Hudson, revisited

As noted in the comments to my post on Tuesday, the original solution I had to this ended up being a lot less flexible than I thought. For one, StyleCop will apparently only parse out StyleCop.Settings files above the folder from which you began executing StyleCop. So, any StyleCop.Settings files below the directory with my controlling MSBuild file won’t actually be processed. That also means that the suggestion by Jason Allor on that post, to set the StyleCopEnabled Property in the CSProj file, didn’t have any effect, StyleCop doesn’t parse out CSProj files.

It turns out that the suggestion that I’d based my solution off of was a little too simple. It didn’t allow me to prevent StyleCop from running on a given project. It didn’t allow me to prevent StyleCop from running on a given set of files or projects. It wasn’t properly letting me modify rulesets for different projects. In short, it just flat didn’t work for anything but the most simple of circumstances. On the one hand, I can’t blame Craig Berntson, who gave that Boise Code Camp presentation, for over simplifying the situation, but on the other hand, it didn’t work well.

Of course, Mr. Allor from Microsoft has already posted on his blog about the real solution to this problem. Basically, run the code in every single CSProj file. This is a little shitty, since I had about 30 projects to modify, and Visual Studio does not make it trivial to modify the core templates that are used to create new projects. In the next month, I’m going to put together some tooling to make it easy to add custom code to every template matching a certain pattern in VS2010 (we’re going to be switching as soon as we can). This might be an external tool, but I’m looking at seeing if I can take advantage of VS2010’s extensibility model. I’m only in the earliest stages of contemplating this.

For now, I’m hand managing the CSProj files to insert the Include that is from the link above, but we did have one special requirement. At least one member on our team didn’t want StyleCop running on every build. My experience with StyleCop’s caching is that it’s not really an issue, but MSBuild makes this pretty easy to handle. We have a three-target build process: Debug, Test, and Release. When run from our controlling build script, Test will push to our Test server, and Release to our production server. Generally speaking, we always run Debug from Visual Studio, Test from CI, and Release only when we’re pushing stable builds, so the following block in all our CSProj files:

    <Import Project="$(MSBuildExtensionsPath)\Microsoft\StyleCop\v4.3\Microsoft.StyleCop.targets" />
    <PropertyGroup>
        <StyleCopEnabled>false
    </PropertyGroup>
    <PropertyGroup Condition="'$(Configuration)' == 'Test'">
        <StyleCopEnabled>true
    </PropertyGroup>

This ensures that StyleCop only runs when doing a “Test” build. For projects that I don’t want to run StyleCop against, I simply exclude the second PropertyGroup (and usually the Import as well, why bother importing what you’re not using?)

I’m not saying that you should exclude StyleCop from developer builds. But it is nice to know MSBuild makes it pretty easy to do.