Enforcing Code Styles with ReSharper and StyleCop

// February 20th, 2009 // Programming

In my previous article, Compiling Code – go.bat is your friend, I explained about using NAnt to compile your code (MSBuild, and aspnet_compiler), run unit tests, and use go.bat (as an easy way for developers to be confident their code will pass).

Having ensured your code will compile and work, this article is about making sure your code is written cleanly and in similar fashion across the whole team. This of course has many benefits especially when viewing code you haven’t written.

Before we get started you’ll need to install the following:

Configuring ReSharper

Firstly open up Visual Studio. Along the menu bar there should be a “ReSharper” heading. Go to “Options” within it.

Code Style Sharing – make sure you have “Shared across the team, per solution” selected. You’ll need to make sure your whole team have this selected. I think it is by default.

C# – Go through the C# section, and set all the rules to suit preferred style. Typically I would suggest leaving most of them as they are.

Code Cleanup – “Add” a new code cleanup profile, and again go through setting everything as you’d like it to be. I turn on as much as possible, and set it where possible to change explicit types to “var” (because I find it reads more cleanly).

UserSettings.xml

Once done, you need get your settings file. It will be located at:

“%USERPROFILE%\Application Data\JetBrains\ReSharper\v4.x\vs9.0″

Take the UserSettings.xml file and place it in source control. I placed mine at:

/trunk/build/settings/resharper/UserSettings.xml

Here’s my UserSettings.xml file as an example. Within that directory I also created an install.bat with the following inside it:

copy UserSettings.xml “%USERPROFILE%\Application Data\JetBrains\ReSharper\v4.5\vs9.0″
pause

By getting your team to run this, it will ensure you all have the same settings file. I like to enforce this by adding it to the end of go.bat. It’s a simple copy command and won’t increase the build time.

If your solution file is called MyApp.sln, you need to make sure you have a MyApp.4.x.resharper file.

MySolution.4.x.resharper

Where your solution is located, if called MySolution.sln, you should now have a resharper file called MySolution.4.x.resharper. This is your team settings file, and whenever a team member opens the solution, ReSharper will use that config.

UserSettings.xml relates to your settings, namely code cleanup. The only annoying thing of sharing a UserSettings.xml file is that team members can’t customise ReSharper themselves (do they need to?).

Here’s my older Solution.4.1.resharper file (I can’t remember if it’s compatible with v4.5) as an example.

StyleCop

If you open a solution now, you should get ReSharper suggestions regarding poorly styled code. Also the “Code Cleanup” should work quite effectively at cleaning up your code.

However, you’ll probably find ReSharper raising style errors for things you don’t see as errors. Hover over these suggestions and note down the Id. It’ll be something like “SA1004”. Spend a while going through a number of your projects and note down any rules you don’t like.

Now you need to create your Settings.StyleCop file. Right-click on any project in your solution and select “StyleCop Settings”. You can now disable any rules you don’t like (use the search, and type in the Id’s from the above step). This is my Settings.StyleCop file.

Once done go to the projects file system folder, and move the “Settings.StyleCop” file to where your solution file is. Add it to source control. If you reload Visual Studio it should now have:

  • Team .resharper settings
  • Shared UserSettings.xml file
  • StyleCop rules, and ReSharper suggestions

Enforcing Styling

The above steps set up a good framework for well styled code, but don’t enforce it. This is something that can be done using the build and NAnt.

Download StyleCopCommand, and add it to your source control. I place it in:

/trunk/tools/stylecopcommand

Using NAnt you can call StyleCopCommand using:


<project name="StyleCop" xmlns="http://nant.sf.net/release/0.86-beta1/nant.xsd" default="stylecop">
    <property name="stylecop.console" value="${source.directory}\tools\stylecopcmd\StyleCopCmd.exe" />

    <target name="stylecop">
        <exec program="${stylecop.console}">
            <arg line="-sf ${source.directory}\sln\Huddle.All.sln" />
            <arg line="-sc ${source.directory}\src\Settings.StyleCop" />
            <arg line="-of ${report.directory}\stylecop.xml" />
        </exec>

        <property name="violations.file" value="${report.directory}\stylecop.violations.count.xml" />

        <!-- Get the violation count for the previous build -->
        <property name="violations.previous" value="35000" overwrite="true" />
        <if test="${file::exists(violations.file)}">
            <xmlpeek file="${violations.file}" xpath="/Violations" property="violations.previous" failonerror="true"/>
        </if>

        <!-- Overwrite the xml, and get the violation count for the current build -->
        <style style="stylecop.xslt" in="${report.directory}\stylecop.violations.xml" out="${violations.file}.temp" />
        <xmlpeek file="${violations.file}.temp" xpath="/Violations" property="violations.current" failonerror="true" />

        <echo message="Previous style violations = ${violations.previous}" />
        <echo message="Current style violations  = ${violations.current}" />

        <fail if="${(int::parse(violations.current) > int::parse(violations.previous))}" message="More code style violations have been introduced. There are currently ${violations.current} violations. You need to reduce it by ${int::parse(violations.current) - int::parse(violations.previous)} for the build to pass." />

        <copy file="${violations.file}.temp" tofile="${violations.file}" failonerror="true" />
        <delete file="${violations.file}.temp" />
    </target>
</project>

This will generate a “stylecop.xml” report along with a “stylecop.violations.xml”. You can then do a node count on the number of violations. This is tricky with NAnt so I use XSLT to do the node count, then NAnt to read the result.


<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/">
        <Violations>
            <xsl:value-of select="count(//StyleCopViolations/Violation)"/>
        </Violations>
    </xsl:template>
</xsl:stylesheet>

I also check the violation count of the previous build, with that of the current build. If it has increased, then I fail the build. It’s strict but we currently have 34,000 6,000 (it dropped around 25,000 in a few months) violations throughout our legacy code, so there’s plenty of code someone can clean up if they break the build.

The only annoying point, is that the violation total is kept on the build server. So there’s no easy (current) way of checking your local code has added any new violations. You only find out upon commiting. It hasn’t caused us too many problems just yet.

Conclusion

It will make some of the developers grumble, but deep down they’ll know it’s a good thing, and will improve the code you work with.

Opening a C# file that is messy and styled badly, immediately makes any developer not want to work with it, feel detached from it, and less ownership of it. It may sound a bit much for code, but it’s what we work with most of the day.

We’re now removing around 500 violations a day. This will probably slow in time, but for now it’s working very well. Maybe in the future we’ll change the build rules to be less strict.

Moving Forward

There are a number of things that can be done to improve all of the above:

  • Creating a StyleCop NAnt task to wrap up a lot of the logic shown above.
  • Defining where the current violation count lives, and allowing your local dev machine to check that count. That way you can be certain you’ve not added any styling violations.
  • The StyleCop report that is generated has all the violations. This isn’t helpful if you’ve added 3 new violations as you have no way of knowing what they were. It would be good to use CruiseControl XSLT templates to compare modifications against files that have style violations. You could then only show the violations that were introduced related to that commit.
  • Related to the above point. Rather than getting StyleCop to check every file, it would be handy to get it to check only the files that were committed. I’m not sure if this is possible, but if it is, then it would reduce build time drastically.

Update 23/09/2009

I’ve actually now moved away from CruiseControl.Net and NAnt. I’m still using StyleCop, but have implemented the same functionality using Rake/Ruby. I’ll be writing a new post about Ruby and writing build scripts in the near future.

7 Responses to “Enforcing Code Styles with ReSharper and StyleCop”

  1. rajesh says:

    Nice article.

    I have few questions:

    1. Does the Settings.StyleCop file matches exactly with resharper settings file?
    2. Does the Enforcing results from StyleCop and resharper matches 100%.

    The reason is, I want to make sure that the results on build server (using StyleCop) and on developer machine using resharper are the same.

    Thanks
    Rajesh

  2. Robert says:

    @rajesh

    1) The .resharper settings file is purely for ReSharper. It’s what gets loaded with Visual Studio. You set this up to stop ReSharper writing messy, style-violating code.

    2) UserSetting.xml is also related to ReSharper. It contains a user’s specific settings, namely the “Code CleanUp” settings. These setting contain some StyleCop settings (ie how to clean up violations).

    3) The Setting.StyleCop file is what the StyleCopForReSharper plugin reads. So whatever you have in there will match in Visual Studio, or if you ran StyleCop via commandline.

    So far it matches virtually 95%. There are some odd cases, but on the whole it works virtually perfectly. It’s just a matter of tweaking your StyleCop.Settings file, and .resharper settings file so that they work in harmony.

    We have thousands of violations in our code, so even if it did only work 95% of the time, it still reduces the number of violations hugely each week.

    The main trick is to enforce is as part of your continuous integration build. I’ve mentioned the troubles between comparing results on your local pc, to the build server towards the end of the article. It’s something I want to fix in future.

  3. Liam says:

    Can you give advise on how to setup the CruiseControl dashboard to incorporate the output generated by StyleCopCmd. Many Thanks!!

  4. Robert says:

    Ah, this is something I’ve not got round to doing.

    If you look at the above snippets, you’ll notice when “exec”ing StyleCop I specify an output directory for the report, “stylecop.xml”. StyleCop will also generate a “stylecop.violations.xml file.

    Now, using CruiseControl you should be able to write a template to display the data using XSL.

    If you look in the directory where you installed CruiseControl.Net, you should notice a “webdashboard” folder. Inside that are all the templates, and XSLT’s for transforming the XML data.

    You need to:

    1) Open up dashboard.config, look at the bottom, there should be an example of integrating additional reports into CruiseControl.Net. You’ll have to have a play around with it.

    2) Either write an XSL yourself to transform “stylecop.violations.xml” or download one (google around, I’m sure someone has written one).

    I’d strongly recommend putting CruiseControl, namely the webdashboard and any .configs into source control.

  5. Murf says:

    Hi Robert,

    I have the following error:-

    Unable to find source XML file ‘D:\stylecop.violations.xml’.

    How id the stylevcop.violations file generated?

    Should the command be changed from

    09.

    to

    09.

    If not how is stylecop.violations.xml generated?

    Thanks!

  6. Murf says:

    Hi Robert,

    SORRY PREVIOUS POST HAD ERRORS

    I have the following error:-

    Unable to find source XML file ‘D:\stylecop.violations.xml’.

    How is the stylecop.violations.xml file generated?

    Should the command be changed from

    09. arg line=”-of ${report.directory}\stylecop.xml”

    to

    09. arg line=”-of ${report.directory}\stylecop.violation.xml”

    If not how is stylecop.violations.xml generated?

    Thanks!

  7. Robert says:

    Hi Murf,

    “stylecop.violations” should be generated by StyleCop itself. It should output two files, “stylecop.xml” and “stylecop.violations.xml” from what I can remember.

    The easiest way to debug this, is comment out all of the NAnt code regarding the number of violations. Just get StyleCop executing.

    Once you’ve got that working, go to the StyleCop output directory you specified. This should be the variable {report.directory}. It looks like you have it set to D:\. Check you have two xml files output there.

    Alternatively you could use “stylecop.xml” I think, but you’d need to change the XSLT I’ve provided (for counting the violations) as the Schema may differ.

    Hope that helps.

Leave a Reply