Enabling Resharper-CLI in Team Build

2013-11-28

JetBrains is working on a Commandline interface that allows you to run the Resharper Code Inspections without opening up Visual Studio. Which is pretty cool! It's still in Early Access Program mode, but you can already download it and play around with it.

It's actually not that hard to integrate it into Team Build. Though there are a few challenges... First, let's go through the steps you'll need to take to integrate it...

Map the $/TeamProject/BuildProcesstemplate folders to disk and get the latest version. Now doubleclick the template you want to edit and find the "Run MSBuild for Project" activity.

Create a new "If" conditional activity underneath it:
I named it "If compatible with Resharper-CLI", since the commandline version can only work in the context of a Visual Studio Solution file at the moment. So if you're building individual projects or are calling an msbuild script directly, the Resharper-CLI can't help you out just yet.

Add the following expression to the if statement to check for the tell tale sign of a solution file. The extension will end on .sln:

String.Equals(Path.GetExtension(localProject), ".sln", StringComparison.OrdinalIgnoreCase)

Then drag a "Invoke Process" activity in the Then branch of the if statement and configure that to call the commandline tool:

I've installed the Resharper-CLI tools in a well-known location on my build agent, but if you want to do fancy registry magic to look up the right location, or grab it from source control, I leave that up to you.

Now we'll need to set the arguments to pass the solution to the process. And to tell it where to drop the output file:


I'm actually passing it the location to write the report to (/o), the location to store the cache (/caches-home) to speed things up and the solution path.

String.Format("/o:""{0}"" /caches-home:""{1}"" ""{2}""", System.IO.Path.Combine(outputDirectoryPerProject, System.IO.Path.GetFileNameWithoutExtension(localProject)) + ".resharper.xml", "d:\resharper-cli\cache", localProject)

I wired up the Standard Output and the Standard Error like I would always do (WriteBuildMessage, WriteBuildError), but that turned out not to work. If you'd do that and check in the process template you'll see that every message is written to the Error stream. I've logged a bug at Jetbrains for that. So I added some logic to fix that, it isn't perfect, but it's as good as I could get in a few clicks.

Remove the WriteBuildError from the "Handle Error Output" item, and instead add a switch. Let that switch trigger in the first 4 characters of the line being logged and depending on the value either log a message, a warning or an error.

Now go ahead, check in the .xaml file and trigger your build, Resharper warnings and errors should now be added to your build output.

You'll end up with a piece of xaml that will look exactly like this:
<If Condition="[String.Equals(Path.GetExtension(localProject), ".sln", StringComparison.OrdinalIgnoreCase)]" DisplayName="If compatible with Resharper-CLI" sap2010:WorkflowViewState.IdRef="If_37">
  <If.Then>
    <mtbwa:InvokeProcess Arguments="[String.Format("/o:""{0}"" /caches-home:""{1}"" ""{2}""", System.IO.Path.Combine(outputDirectoryPerProject, System.IO.Path.GetFileNameWithoutExtension(localProject)) + ".resharper.xml", "d:\resharper-cli\cache", localProject)]" DisplayName="Run Resharper-CLI for Project" FileName="d:\jetbrains-CLI\InspectCode.exe" sap2010:WorkflowViewState.IdRef="InvokeProcess_1" WorkingDirectory="[SourcesDirectory]">
      <mtbwa:InvokeProcess.ErrorDataReceived>
        <ActivityAction x:TypeArguments="x:String">
          <ActivityAction.Argument>
            <DelegateInArgument x:TypeArguments="x:String" Name="errOutput" />
          </ActivityAction.Argument>
          <Switch x:TypeArguments="x:String" DisplayName="" Expression="[errOutput.Substring(0, If(errOutput.Length >= 4, 4, 0))]" sap2010:WorkflowViewState.IdRef="Switch`1_1">
            <Switch.Default>
              <mtbwa:WriteBuildMessage sap2010:WorkflowViewState.IdRef="WriteBuildMessage_3" Importance="[Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.Low]" Message="[errOutput]" mva:VisualBasic.Settings="Assembly references and imported namespaces serialized as XML namespaces" />
            </Switch.Default>
            <mtbwa:WriteBuildWarning x:Key="WARN" sap2010:WorkflowViewState.IdRef="WriteBuildWarning_3" Importance="[Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.High]" Message="[errOutput]" mva:VisualBasic.Settings="Assembly references and imported namespaces serialized as XML namespaces" />
            <mtbwa:WriteBuildError x:Key="ERRO" sap2010:WorkflowViewState.IdRef="WriteBuildError_2" Message="[errOutput]" />
          </Switch>
        </ActivityAction>
      </mtbwa:InvokeProcess.ErrorDataReceived>
      <mtbwa:InvokeProcess.OutputDataReceived>
        <ActivityAction x:TypeArguments="x:String">
          <ActivityAction.Argument>
            <DelegateInArgument x:TypeArguments="x:String" Name="stdOutput" />
          </ActivityAction.Argument>
          <mtbwa:WriteBuildMessage sap2010:WorkflowViewState.IdRef="WriteBuildMessage_2" Importance="[Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.Low]" Message="[stdOutput]" mva:VisualBasic.Settings="Assembly references and imported namespaces serialized as XML namespaces" />
        </ActivityAction>
      </mtbwa:InvokeProcess.OutputDataReceived>
    </mtbwa:InvokeProcess>
  </If.Then>
</If>

This will now drop a "[Solution].resharper.xml" in the build drop folder. I haven't yet parsed the file so that you can actually fail the build based on it, that'll be something for a future blog post.

And without me writing that future post, I was contacted over twitter to let me know that someone else has already done it for me:



[BuildActivity(HostEnvironmentOption.All)]  
    public sealed class ParseResharperCLI : CodeActivity
    {
        // Define an activity input argument of type string
        public InArgument<string> PathToXml { get; set; }
        public OutArgument<string[]> Warnings { get; set; }
        public OutArgument<string[]> Errors { get; set; }
 
        // If your activity returns a value, derive from CodeActivity<tresult>
        // and return the value from the Execute method.
        protected override void Execute(CodeActivityContext context)
        {
            var document = XDocument.Load(context.GetValue(PathToXml), LoadOptions.None);
            var issueTypes = document.Descendants("IssueType")
                 .Select(x => new
                 {
                     Id = x.Attribute("Id").Value,
                     Severity = x.Attribute("Severity").Value
                 })
                 .ToList();
 
            var issues = document.Descendants("Issue")
                .Select(x => new Issue
                {
                    File = x.Attribute("File").Value,
                    Message = x.Attribute("Message").Value,
                    Severity = issueTypes.First(t => t.Id == x.Attribute("TypeId").Value).Severity,
                    Line = x.Attribute("Line") != null ? x.Attribute("Line").Value : null,
                })
                .ToList();
 
            var warnings = issues
                .Where(i => i.Severity != "ERROR")
                .Select(i => i.ToString())
                .ToArray();
            var errors = issues
                .Where(i => i.Severity == "ERROR")
                .Select(i => i.ToString())
                .ToArray();
 
            context.SetValue<string[]>(this.Errors, errors);
            context.SetValue<string[]>(this.Warnings, warnings);
        }
    }
 
    public class Issue
    {
        public string File { get; set; }
 
        public string Message { get; set; }
 
        public string Severity { get; set; }
 
        public string Line { get; set; }
 
        public override string ToString()
        {
            return string.Format("{0}  File: {1}  Line: {2}  Message: {3} ", Severity, File, Line, Message);
        }
    }

Updated MSOCAF for Visual Studio Code Analysis rules

2013-11-18

2 years ago I worked on a huge SharePoint project where we had to run the MSOCAF wizard  before deployment to the production  environment. And of course, every time a few rules triggered that caused huge rework efforts.

So I ended up recompiling the FxCop 1.36 rules that ship with MSOCAF 2010 to work with Visual Studio 2010.

Today I redid that work and compiled the following sets of rules:
  • C:\Program Files (x86)\Microsoft Visual Studio {10|11|12}.0\Team Tools\Static Analysis Tools\FxCop\Rules
Or create a custom .ruleset file and tell it where to find the binaries.

Team foundation Service is now known as...

2013-11-14

Visual Studio Online Logo
And I've updated the tags to all posts referencing TFSvc to now also include Visual Studio Online. This helps clear up the definition of TFS is that Server or Service? So, TFS is the on premise product and VSO is the one in the cloud (with a lot of very cool features!).

Read more on this excellent blog post by Ed Blankenship.

Use Git commandline directly from Visual Studio

2013-11-08

Not many people seem to know this, but the Visual Studio Package manager is nothing more than a Powershell window inside Visual Studio with a bunch of modules loaded. Which means that you can use it to execute just about any command you'd like.

So if you need to run git commands to stash or squash something, all you need to do is type the command right into that window.

To make your life easier you can even add PoshGit to the Package Manager Console, this will give you command auto-completion. yay!

Install the Git Command Line tools.

Execute the following commands from the package manager console:

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Confirm
(new-object Net.WebClient).DownloadString("http://psget.net/GetPsGet.ps1") | iex
Import-Module PsGet
Install-Module Posh-Git –force
. $PROFILE

Now you have command completion inside Visual Studio. Nice!

My must-have extensions for Visual Studio 2013

Visual Studio 2013 has been available for a while now, and next week is the official launch party. Ever since I started using Visual Studio my life has been made easier by all the great extensions that people write for it. This is the list of things I install almost as soon as I see the "Installation Completed" screen of Visual Studio itself:

Resharper
This product shouldn't need any introductions. It has been one of the most-used commercial Visual Studio productivity extensions. The only alternative that is equally valuable for me would be Code Rush, but somehow most of my clients have already standardized on Resharper. I miss some of the features from Code Rush (debug helpers, dynamic templates), but can do without them.

+Plugins: AgentMulder, AgentRalph, InternalsVisibleTo Helper, JsLint, Razer Plugin, TestCop
Resharper 8 now comes with NuGet support for plugins, which is great, as it helps you keep your plugins up to date! I have the above mentioned plugins installed to make life easier when doing a lot of Unit Testing and ASP.NET MVP development.

VSCommands
VsCommands adds some small features that are really handy. Think of Command Line Here, Locate in Solution Explorer, And for those of you that work a lot in MsBuild to write their own before/after build targets, the Edit Project File option is ideal. Plus it shows the current branch name in the title of your Visual studio window.

Reflector .NET
Resharper comes with dotPeek and Code Rush has a decompiler window, but only Reflector has one feature that's even better: Debug symbol generation. Using Reflector you can generate debug symbols for assemblies that you don't have symbols or sources for, making it possible to debug nasty issues in e.g SharePoint or any other closed source product for that matter. It has saved me on multiple occasions. To make it work with Resharper you do need to tweak the Resharper code Navigation settings:


This will allow Reflector to hook into the F12 handling of Visual Studio so you'll still see a decompiled version of any method you navigate to, just not from dotPeek/Resharper.

TFS Source Control Explorer Extensions
If you're, like me, an ALM support to any team you've been added to, then you'll probably see a lot of branch plans that got completely out of hand. In these cases (and even when you do have a working branch plan), the TFS Source Control Explorer Extensions are invaluable. It adds the Branch commands that are normally only possible from the command line directly to the Source Control Explorer and enabled drag&drop for files and folders to quickly and easily move things around.

I do disable two features:

The change files date on Get adds a long waiting period to large gets and I never look at the dates on my file system anyway and the Files icon change changes the icons around for branches and folders, but this doesn't add any value to me.

Branch Info Team Explorer
Ever wondered which branch your Solution was rooted in? Ever accidentally changed code in the wrong branch and then had to roll back and backport into the right one? That's why I have this little gem installed. Unless you're using a very complex workspace mapping, this extension to Team Explorer shows you exactly which branch your solution is coming from.


It also allows you to quickly switch to the same solution in another branch. That's very handy for people working on multiple feature branches or supporting multiple versions of the same product!

Visual Studio Team Foundation Server Power Tools
One more add-on for TFS. This one should be installed on all systems by default. Even just the extended commandline tools (tfpt). If you're into the command line stuff, then you'll also like the TfsTeamTools, the TfsBranchTools. If you've ever had to edit the Process Template of a TFS Project, then you're also going to love this set of extensions.

Codelens Code Health Indicator
If you're lucky enough to run Visual Studio Ultimate, then you'll love Codelens. It adds a lot of valuable information right into the editor, making it easier to see what has been going on with the code you're working on.

The Code Health Indicator provides a way to show the metrics from the Metrics Tool Window directly in your source window. This little add-on gives me back one of the features from Code Rush that I missed since installing Resharper.

The download page says it only works on Visual Studio 2013 RC, but so far it's been working on the RTM version as well with no issues (for me at least)...

Web Essentials
As you can tell by my inclusion of the Code Health indicator, quality code is important to me. Web Essentials adds JsHint support to Visual Studio and it helps define Stylesheets with the maximum cross-browser compatibility! Combine that with jsdoc, minification, less and coffeescript support and you can make many-a-html5-guru happy! If Sass support is important to you, install the Web Developer Workbench as well.

JSHint

I'd love it when Web Essentials would provide MsBuild support for minification, JsHint and CssLint as well, but though it has been on the feature request llist a long time, it hasn't been added so far. This would also allow integration of WebEssentials into Team Build.

Chutzpah Javascript Test Runner
When talking about WebEssentials, a way to execute Javascript tests is next on the list of achieving high quality code in a Web Development environment. Chutzpah does just that, it can execute Jasmin and QUnit tests written for Javascript and it integrates directly into the Visual Studio test runner. The beauty of that, is that it also integrates in Team Build and can thus pass or fail a build based on Javascript tests passing or failing.

NUnit & XUnit test runners
Should Mstest not be your tool of trade, since Visual Studio you can now add test runners to other test frameworks as well. So instead of adding a test runner for a whole different language, as is the case with Chutzpah, this adds support for additional test frameworks your managed code unit tests. Full support for team build as well, which is nice!

With the NUnit test runner you can also execute tests that were generated by Selenium as an alternative to the standard Visual Studio CodedUI tests.

Team Room extension
Are you working in a Distributed team, or people work from home a lot, then this addition to Team Explorer is really nice! It puts Team Rooms, a new feature of Team Foundation Server 2013 and Team Foundation Service directly into Visual Studio. No need to leave Visual Studio to chat with your team members or see their updates. Plus is was built by my own colleagues, what more could you wish for ;)!

Wix Toolset
Ever since the removal of the Visual Studio Setup Projects (or actually way before that, ever since I started using Team Build), I've been using Wix for my setup requirements. Though I usually don't create fancy UI's or extensively configurable stuff, I do like my installers to register themselves into the Programs and Features window and to be able to upgrade  (and downgrade) my application gracefully. Wix can help you do that!

StyleCop
Yay! A Visual Studio  2013 and Resharper 8.0.2000.2660 compatible version has been released. Stylecop helps you write your code in a clean way and helps ensure that team members all use the same  coding style. In itself it's a huge  pain, since I never seem to be able to remember all the rules in the style guide, but when combined with Resharper and it's magic alt-enter, it is incredibly helpful.

There are a few things that are still missing
Though almost every add-on for visual studio I regularly use has been ported to Visual Studio 2013 already, there are still a few that are missing. These will probably follow suit int he near future.


 

Most Reading