How to use Cake with Rider

I am a big fan of Cake  a free and open source cross-platform build automation system with a C# DSL for tasks such as compiling code, copying files and folders, running unit tests, compressing files and building NuGet packages.

I have previously posted about how I use cake to automate my Continuous Integration Check-In Dance. Essentially creating a script to run my build and tests for me. I also try to take this further when possible to use cake to create the entire build pipeline for my applications.

Back in 2017, I posted about How to write a Cake Build script for ASP.net core project , which for the most part is still relevant, but there have been some great improvements that have really helped simply and improve the experience in working with cake. Especially, if like me you develop .net core applications on Linux and use Rider as your IDE of choice.

Installing Cake

In my opinion this is one of the best improvements made to Cake over the years, the fact that it is now available as dotnet tool. A .NET tool is a special NuGet package that contains a console application.

The .NET CLI uses manifest files to keep track of which tools are installed as local to a directory. When the manifest file is saved in the root directory of a source code repository, a contributor can clone the repository and invoke a single .NET CLI command that installs all of the tools listed in the manifest files.

Check out How to manage .NET tools to learn more about this feature of .net, which brings the .net framework inline with all the other common software development frameworks.

For the purpose of this guide I will focus on installing Cake as as CLI tool, and will assume already have some basic knowledge about .net cli tools.

Our first step will be to enable the tool manifest file which is basically a json file which stores the locations of tools on your machine.

Tools can be installed in the following ways:

  • As a global tool.The tool binaries are installed in a default directory that is added to the PATH environment variable. You can invoke the tool from any directory on the machine without specifying its location. One version of a tool is used for all directories on the machine.
  • As a global tool in a custom location (also known as a tool-path tool).The tool binaries are installed in a location that you specify. You can invoke the tool from the installation directory or by providing the directory with the command name or by adding the directory to the PATH environment variable. One version of a tool is used for all directories on the machine.
  • As a local tool (applies to .NET Core SDK 3.0 and later).The tool binaries are installed in a default directory. You invoke the tool from the installation directory or any of its subdirectories. Different directories can use different versions of the same tool.The .NET CLI uses manifest files to keep track of which tools are installed as local to a directory. When the manifest file is saved in the root directory of a source code repository, a contributor can clone the repository and invoke a single .NET CLI command that installs all of the tools listed in the manifest files.

To create a tool manifest simply execute the following in a terminal window

dotnet new tool-manifest

Then we can install the Cake.Tool globally on our machine. We will install this globally for reason which will become apparent later in this article.

dotnet tool install Cake.Tool --global

Cake is now ready for us to use. In any .net project.

Simple Cake Script

In general most of projects follow a kind of defacto standard directory structure most Open Source Projects tend to follow.

Shell

All my CSharp project files are usually stored in the src folder. Unit and Integration test projects are stored in the tests directory and the Solution file(s) are stored in the root directory. Taken the project structure in mind we will start creating a first simple Cake Build Script. We create a text file to the our root folder and name it build.cake.

Shell

In this example Cake script, we want to build our application and once that is complete run all our tests both Unit and Integration tests.

var target = Argument("target", "Default");
var configuration = Argument("configuration", "Release");

//////////////////////////////////////////////////////////////////////
// TASKS
//////////////////////////////////////////////////////////////////////

Task("Clean")
    .Does(() => {
    DotNetCoreClean("./");
});

Task("Build")
    .IsDependentOn("Clean")
    .Does(() => {
     var buildSettings = new DotNetCoreBuildSettings {
                        Configuration = configuration,
                       };
     var projects = GetFiles("./src/*.csproj");
     foreach(var project in projects )
     {
         Information($"Building {project.ToString()}");
         DotNetCoreBuild(project.ToString(),buildSettings);
     }
});

Task("Restore")
    .Description("Restoring the solution dependencies")
    .Does(() => {
           var projects = GetFiles("./**/*.csproj");

              foreach(var project in projects )
              {
                  Information($"Building { project.ToString()}");
                  DotNetCoreRestore(project.ToString());
              }

});

Task("Test")
    .IsDependentOn("Build")
    .Does(() => {

       var testSettings = new DotNetCoreTestSettings  {
                                  Configuration = configuration,
                                  NoBuild = true,
                              };
     var projects = GetFiles("./tests/*.csproj");
     foreach(var project in projects )
     {
       Information($"Running Tests : { project.ToString()}");
       DotNetCoreTest(project.ToString(), testSettings );
     }


});


//////////////////////////////////////////////////////////////////////
// EXECUTION
//////////////////////////////////////////////////////////////////////

Task("Default")
       .IsDependentOn("Clean")
       .IsDependentOn("Restore")
       .IsDependentOn("Build")
       .IsDependentOn("Test");

RunTarget(target);

Check out the sample project for the general idea

Once we have created our file we can now run the build anytime we like from the terminal just by using the command that is available to us from the Cli tool we installed previously

dotnet cake

This will execute the build process, where we will clean the solution, restore the dependency build our projects and run the tests. We will also have the results printed out in the terminal window.

I find this really handy and having a repeatable and reusable build script really helps to ensure we have a consistent and reliable quality check process.

We have found that having Build Scripts available to every developer, in the core language and the same language as the project itself provides such a huge improvement in productivity because our developers never have to context shift, or even flick between different IDE’s or other tools because everything they need is all in one place.

We have been able to reduce bugs and build failures because the build automation scripts are in the exact same language (C#) and location (source control) as the production system code, regular developers felt more comfortable jumping in and contributing, fixing, and extending as necessary.

We also found that by placing all build automation logic in scripts that live under the same source control as production code we leverage the tight coupling instead of fighting it.  Build automation logic will flow smoothly through branches and merges, and no one ever needs to remember to update build definition logic, across different branches etc. because all build definitions are identical.

The other key advantage we’ve discovered making use make-like scripts and eliminating Continuous Integration Logic is that is completely improve the developer experience . When things go wrong on a CI server with custom logic you can’t set breakpoints, environmental differences are inaccessible, logging options are limited, and you frequently have to wait very long times to see the results of any changes (i.e. the build manager inner loop, to coin another phrase).

The Cake for Rider Plugin

In Januray 2021, the team behind Cake have launched an official Cake for Rider plugin which in my opinion will take Cake to the next level on developer experience. The plugin at this stage of it’s evolution is still the bare bones basic, but it is still stable and ready for daily use.

After you have installed the plugin in Rider, you can quickly and easily configure it in your project, to provide facility to run your build script right in your IDE.

To do this in Rider simply go to Edit your Build Configurations.

Then you can select Cake from the configuration choices after you have clicked the + button

The you simply configure the which Cake script you want to run and provide any additional arguments etc. and Provide a name for your option

This will now enable you to run the Cake Script using the play button

Top Tip

If you have issues running the script and receive error messages. Just ensure you have installed the Cake.Tool globally
dotnet tool install Cake.Tool --global

Using Cake Tasks Window

Once you have installed the Cake for Rider plugin you may well notice an additional tab will appear on the right hand side tools options of your IDE

If you open this view you will be presented with a list of your individual Cake tasks in your script and you now have the ability to run each of these tasks individually as well, which is really handy during development if you want to run your tests on their own, or just want to kick a quick build or whatever.

Information

Please do bear in mind that at the time of writing the Cake for rider plugin was still only in 0.2.0 release, so it was still early days and there were still some glitches that need to be ironed out.

However after raising a Github Issue, the team behind the plugin were really quick to jump in and help to get it sorted.

Instead of replicating the details on this post I suggest you take peak at the issue as we did try and document the issue and fix as best we could.

Conclusion

Cake plays big role in my own CI/CD pipeline and it is also my favourite approach to writing Build Scripts, I have found that the Cake For Rider plugin really helps in not only streamlining the process but also really improves the over all User experience of Cake. I really look forward to the additional enhancements the team behind Cake For Rider implement over time.

Download it today and have a play, I’m sure you’ll enjoy it is as much as I do.