Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / PowerShell

Cake Build Tool

4.92/5 (12 votes)
20 Feb 2018CPOL3 min read 36K  
The Cake build tool is a build tool that utilizes the Roslyn (compiler as a service) from .NET.

I don’t know exactly when or where I first came across the Cake build tool, and at the time I made a mental note to look at it in more detail (as I am not a massive fan of MSBuild). That time came and went, and I did nothing about it. Then Cake came across my radar again so this time I decided to dig into it a bit more.

So What is this Cake Build Tool?

The Cake build tool is a build tool that utilizes the Roslyn (compiler as a service) from .NET. What this means is that you can write very precise build scripts using very familiar C# language syntax that you know and love.

Getting Started

The best way to get started is to clone the example repo: https://github.com/cake-build/example

The repo is a simple C# class library and a test project all within a single solution.

image

As you can see, this project is very simple. What we would like to do with this project is the following things:

  • Clean solution
  • Restore Nugets
  • Build solution
  • Run tests
  • And also have ability to push out Nuget package (nupkg file)

Most of this is already available within the example repo: https://github.com/cake-build/example, with the exception of pushing a nuget package at the end.

What Bits Do You Need to Run a Cake Build?

So what do you need to provide to run a cake build?

You just need these 2 files:

  • build.ps1 (bootstrapper that doesn’t change, grab it from repo example above)
  • build. cake (this is your specific build and should contain the targets/tasks you need for your build)

The .cake File

As the build.ps1 is a standard thing, I won’t worry about that, but let's now turn our attention to the build.cake file which for this post looks like this:

PowerShell
#tool nuget:?package=NUnit.ConsoleRunner&version=3.4.0

//////////////////////////////////////////////////////////////////////
// ARGUMENTS
//////////////////////////////////////////////////////////////////////

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

//////////////////////////////////////////////////////////////////////
// PREPARATION
//////////////////////////////////////////////////////////////////////

// Define directories.
var buildDir = Directory("./src/Example/bin") + Directory(configuration);

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

Task("Clean")
    .Does(() =>
{
    CleanDirectory(buildDir);
});

Task("Restore-NuGet-Packages")
    .IsDependentOn("Clean")
    .Does(() =>
{
    NuGetRestore("./src/Example.sln");
});

Task("Build")
    .IsDependentOn("Restore-NuGet-Packages")
    .Does(() =>
{
    if(IsRunningOnWindows())
    {
      // Use MSBuild
      MSBuild("./src/Example.sln", settings =>
        settings.SetConfiguration(configuration));
    }
    else
    {
      // Use XBuild
      XBuild("./src/Example.sln", settings =>
        settings.SetConfiguration(configuration));
    }
});

Task("Run-Unit-Tests")
    .IsDependentOn("Build")
    .Does(() =>
{
    NUnit3("./src/**/bin/" + configuration + "/*.Tests.dll", new NUnit3Settings {
        NoResults = true
        });
});


var nugetPackageDir = Directory("./artifacts");
var nuGetPackSettings = new NuGetPackSettings
{   
  OutputDirectory = nugetPackageDir  
};

Task("Package")
  .Does(() => NuGetPack("./src/Example/Example.nuspec", nuGetPackSettings));


//////////////////////////////////////////////////////////////////////
// TASK TARGETS
//////////////////////////////////////////////////////////////////////

Task("Default")
    .IsDependentOn("Run-Unit-Tests");

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

RunTarget(target);

There are a couple of concepts to call out there:

  • We have some top level arguments/ variables
  • Nice C# features that we have used before
  • We have Tasks just like other build systems. We can make one task depend on another using .IsDependantOn(“”)
  • There seems to be wide range of inbuilt things we can use for example these guys below. These are all prebuilt items in the cake DSL that we can make use of. There are loads of these, the full list is available here: https://cakebuild.net/dsl/
    • CleanDirectory
    • NUnit3
    • NuGetPack

Have a look at the DSL web site - there are quite a few cool things you can use:

image

Running the Build

So with this build.cake and build.ps1 (bootstrapper file) in place, we would like to run the build. Here is how we do that:

  1. Open PowerShell window as Administrator
  2. Issue this command in PowerShell: Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
  3. Change to the correct directory with the .cake file in it, and issue this command : .\build.ps1
  4. You should see some output, where it eventually completes
  5. You should also see a tools folder

This is the tail end of the build I just ran above.

image

And this is the sort of thing that we should see in the tools folder that the cake build created.

image

Deploying a Nuget

So I stated that I also wanted to be able to deploy a Nuget Package as a Nupkg. To do this, I need to create the following .nuspec file for the Example project.

XML
<?xml version="1.0"?>
<package >
  <metadata>
    <id>Example</id>
    <version>1.0.0</version>
    <title>Cake Example</title>
    <authors>Sacha Barber</authors>
    <owners>Sacha Barber</owners>
    <licenseUrl>http://github.com/sachabarber</licenseUrl>
    <projectUrl>http://github.com/sachabarber</projectUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Simple Cake Build Tool Example</description>
    <releaseNotes>1st and only release</releaseNotes>
    <copyright>Copyright 2018</copyright>
    <tags>C# Cake</tags>
  </metadata>
  <files>  
   <file src="bin\Release\Example.dll" target="lib\net45"></file>  
</files> 
</package>

So with that in place, we can also try the Nuget publish Task that our build.cake file has in it like this:

  1. Open PowerShell window as Administrator
  2. Issue this command in PowerShell: Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
  3. Issue this command in PowerShell: .\build.ps1 -Target Package

After running that, we should see artifacts folder with the following artifact in it:

image

Conclusion

I was pretty happy with this, I went from not using Cake at all to carrying out ALL my requirements in 1 hour on a train ride with limited WiFi. It just seems to work, and I imagine it would be a good fit for working with something like https://about.gitlab.com/.

I think I will be looking to use this little build tool a lot more.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)