Finding typos with ReSharper Command Line Tools, ReSpeller and Cake

1. Introduction

I tend to do a lot of typos when I write a code and I mean a lot. This is quite annoying for me so I decided to somehow automate the process of finding the spelling errors during the build. My first thought was to use some kind of Roslyn analyzer, however, I failed to find any working one. This is why I decided to give a try to ReSharper Command Line Tools (also known as CLIT) combined with ReSpeller plugin. For those who don’t know, ReSharper Command Line Tools is set of tools which allow you to use ReSharper inspections without Visual Studio

2. First attempt

This was supposed to be a rather straightforward task because according to documentation command line inspections support extensions out of the box. The example presented in the help page was supposed to be the perfect one for me

Unfortunately, it turned out that extensions support is broken for some time and it wasn’t working for me either (tested on Command Line Tools version 2017.2).

3. The workaround

Even though extension support is not working as expected I was able to make it work with some workaround. The workaround itself is a combination of helpful tips taken from this YouTrack issue. Long story short, we have to manually install the plugin and then force ReSharper to use it. Assuming that you have command line tools installed this can be achieved in following way. First of all we have to get our hands on ReSpeller plugin. We can install it using NuGet but before you do it, remember to add additional feed to nuget.config file.

The feed url can be found in the ReSharper’s option page and for version 2017.2 it is

Having our NuGet sources updated we can retrieve the package using following command

The next step is to copy ReSpeller’s DLLs from following folders

directly to CLIT tools folder – JetBrains.ReSharper.CommandLineTools\tools. What is more, ReSpeller comes together with dictionary files which also have to be copied to the tools folder. This time, however, we have to copy entire etherealcode.respeller.4.6.9.2\EtherealCode.ReSpeller\lib\net45\dic directory, not only its content. The very last thing is to make ReSharper aware of the plugin, in order to do that we have to find EtherealCode.ReSpeller.JetMetadata.sstg file. The file itself doesn’t come together with the package but it is generated by ReSharper during plugin installation. So the easiest way of getting that file is to install ReSpeller as a ReSharper plugin in Visual Studio and then copy the sstg file to tools folder. After all that work now if you run

(note lack of -x switch) you will see spellcheck inspections in output file.

4. Cake integration

Doing all that stuff manually is error-prone and time-consuming and of course, I wanted to have the spellcheck up and running on the CI server, that is why I’ve also automated all above steps with Cake build script. The core concept is to use ReSpeller and ReSharper Command Line Tools as so-called “Cake tools” to run the inspections and Cake.Issues and Cake.Issues.InspectCode plugins for analyzing the output file.
Adding tools and add-ins is straightforward we just have to add following lines on top of the build file.

We also have to add nuget.config file to our build directory in order to point Cake to ReSharper feed (you could also modify the global nuget.config but I don’t want a build process to change the behavior of entire system)

Before calling InspectCode.exe we have to make sure that all of the files and folders exist

Having all of the items in place now we are ready to run the actual spellcheck and verify the results

As you can see I start InspectCode.exe process with a bunch of parameters. Once the process returns successful exit code I can go ahead and process the results thanks to ReadIssues and InspectCodeIssuesFromFilePath methods provided by the add-ins. Because of the fact that ReSharper can produce a ton of inspections I only care about the ones which are typos. Simple and very naĂŻve LINQ query can do it for me

If any typos were found I just throw exception with a listing of all the issues. Note that I aggregate all the issues into one big message because if you have lots of typos (just like I do) rendering them can take some time

The source code for slightly enhanced version of that script can be found here

Finding typos with ReSharper Command Line Tools, ReSpeller and Cake

VS Code – forcing partial IntelliSense support for Cake scripts

1. Introduction

I’ve been using Cake for quite some time now, and I really like this tool, however the more complex my build scripts are, the more painful lack of IntelliSense is. Inspired a bit by this post, I decided to see what it takes to enable at least partial IntelliSense for Cake scripts in Visual Studio Code.

2. Investigation

The proper way of providing the code completion for Cake scripts would probably be a plugin to Omnisharp-Roslyn, as Cake script is basically a valid c# snippet. Unfortunately, at this moment Omnisharp-Roslyn doesn’t have plugin infrastructure ready, that is why I decided to go with a bit different path. As you might or might not be aware, VS Code already supports csx files, so if you add an empty project.json file (by empty I mean file with empty JSON object) to your build directory and change extension of your scripts to csx, you will immediately get a C# syntax highlighting and some IntelliSense support. Sadly this will not provide code completion for Cake method aliases. The reason why it fails on that is the fact that the Cake alias is ICakeContext extension method

but you use it as it was written as

The Cake engine generates additional alias overloads during script compilation, and as these overloads exist only on runtime, VS Code just can’t “see” them.

3. My approach

Having in mind the way Cake works I decided to write an application which would be able to take any Cake or Cake add-in and produce a library containing proper alias overloads. For instance, if original Cake method looks as follows

the application will rewrite it into

The algorithm looks more or less like that

  • Retrieve Cake or Cake add-in via NuGet
  • Scan an assembly and find all classes containing alias methods
  • Use CSharpCodeGenerationService to generate metadata for Cake alias methods
  • Parse generated code with Roslyn and produce SyntaxTree
  • Append Metadata suffix to classes containing alias method
  • Remove ICakeContext parameter from alias method
  • Generate dummy body for methods which require that (methods which have return type or which have out parameters)
  • Update xml documentation
  • Compile generated code and produce dll

There is no point of doing more detailed description in here so if you want to take a closer look here is source code.

4. Generating metadata libraries

Before we start “hacking” VS Code to have IntelliSense, we have to prepare metadata libraries which will contain all necessary Cake alias overloads. In order to do that grab the application from NuGet and generate Cake.Common and Cake.Core metadata libraries. The simplest way of doing it is to run these commands

As a result, the application will produce following files:

  • Cake.CommonMetadata.dll
  • Cake.CommonMetadata.xml
  • Cake.CoreMetadata.dll
  • Cake.CoreMetadata.xml

5. Enabling IntelliSense in VS Code

Having our metadata libraries prepared now we can adjust our build scripts to have code completion in VS Code. Here are the steps:

  • Add project.json file with empty JSON object into your build directory.
  • Change extension of all your build scripts to csx.
  • Copy metadata libraries into your Build directory.
  • Create imports.csx file. This is the file which contains all original namespace imports. It may look as follows
  • Create metadataimports.csx file. This is the file which contains metadata namespaces imports and loads Cake and metadata references. Each original Cake alias class has corresponding metadata class with Metadata suffix, for instance
    Cake.Common.ArgumentAliases -> Cake.Common.ArgumentAliasesMetadata
    Cake.Common.EnvironmentAliases -> Cake.Common.EnvironmentAliasesMetadata
  • Load imports.csx to your build.csx file via
  • Run VS Code install ms-vscode.csharp 1.7.0, open Build directory and write your build script with IntelliSense support
  • Before running the script remember to comment out from imports.csx file
  • Run the build

I do realize this is quite convoluted explanation so in case of any troubles take a look at my build

6. Known issues

  • Cake.Intellisense can only generate metadata libraries for a standard .NET frameworks, it will fail if you try to create metadata targeting .NETStandard or .NET Core framework
  • Due to some breaking changes in Omnisharp-Roslyn scripting support, IntelliSense will only work with Omnisharp 1.7.0

7. Summary

This approach is just a temporary solution. As you can see, it requires significant amount of work to have a code completion in VS Code. I believe that once Omnisharp-Roslyn has proper plugin support it should be possible to write some kind of custom IntelliSense provider for Cake scripts. There are already people who forked Omnisharp-Roslyn and play around with that, so we just have to wait for something better than this solution.

VS Code – forcing partial IntelliSense support for Cake scripts

Cake – Data at the root level is invalid

Couple of weeks ago I mentioned that in my current project we use Cake as a build mechanism. Recently we wanted to add simple functionality to our build script, which would allow us to modify one of the App.config‘s properties. According to the documentation it should be a straightforward tasks, as all the heavy lifting can be done via XmlPeek and XmlPoke aliases.
Our initial script looked as follows

And what was surprising for us, it didn’t work.
dataattherootlevel
We got a bit weird error “Data at the root level is invalid. Line 1, position 1”. The exception suggested that there was something wrong with our App.config file. However if you look at the picture presented above, you will see that we were able to successfully read the file and retrieve value of Version with XmlPeek method. After a bit of digging it turned out that XmlPoke and XmlPokeString are not able to work with relative paths and we have to use absolute one in order to make it work. Fortunately there is an easy way to do that, namely MakeAbsolute method. Out script after modifications looks that way

And now everything works fine
after

Source code for this post can be found here

Cake – Data at the root level is invalid

Debugging cake scripts

We’ve been using Cake in our project for quite some time and it has been working great. However for time to time lack of debugging support was really annoying for me. Fortunately it seems that these times are gone now. During NDC Oslo 2016 Gary Ewan Park showed that it is possible to attach debugger to the build process. Here are the steps to achieve that. Let’s assume that we have following simple cake script.

In order to make the debugging possible it is necessary to add

preprocessor directive to the task we want the debugger to stop.

This operation doesn’t affect the default build process, so if you run in console

the build will run as usual. In order to be able to attach the debugger we have to call Cake with

flag. You can’t do it directly via

script so assuming that you didn’t change directory structure created by bootstrapper, go to Tools/Cake folder and run from PowerShell

where

is path to your cake script and

is task you want to start. Once you run the command, cake will wait for attaching the debugger
WaitingForDebugger
Now launch Visual Studio, go to Debug-> Attach to Process…, find process id listed in console
Attach
and click Attach. After couple of seconds Visual Studio will load your cake script and you will be able to debug it like normal application.
attached

Debugging cake scripts