5

I'm trying out Cake (C# Make). So far all the examples and documentation have the script file declaring all of its code inside delegates, like this:

Task("Clean")
    .Does(() =>
{
    // Delete a file.
    DeleteFile("./file.txt");

    // Clean a directory.
    CleanDirectory("./temp");
});

However, one of the reasons I'm interested in using Cake is the possibility of writing my build scripts in a similar way to how I write code, as the scripts use a C#-based DSL. Included in this possibility is the ability to separate code that I use into methods (or functions / subroutines, whatever terminology is appropriate) so I can separate concerns and reuse code. For example, I may want to run the same set of steps for a multiple SKUs.

While I realize that I could create my own separate DLL with Script Aliases, I would like to avoid having to recompile a separate project every time I want to change these bits of shared code when working on the build script. Is there a way to define, inline with the normal build.cake file, methods that can still run the Cake aliases (e.g., DeleteFile) and can themselves be called from my Cake tasks?

Joe Sewell
  • 6,067
  • 1
  • 21
  • 34

1 Answers1

12

Cake is C#, so you can create classes, methods, just like in regular C#

I.e. declare a class in a cake file

public class MyClass
{
    public void MyMethod()
    {

    }

    public static void MyStaticMethod()
    {

    }
}

and then use it a script like

var myClass = new MyClass();

// Call instance method
myClass.MyMethod();

//Call static method
MyClass.MyStaticMethod();

The Cake DSL is based on Roslyn scripting so there are some differences, code is essentially already in a type so you can declare a method without a class for reuse

public void MyMethod()
{

}

and then it can be called like a global methods

MyMethod();

A few gotchas, doing class will change scoping so you won't have access to aliases / context and global methods. You can get around this by i.e. passing ICakeContext as a parameter to class

public class MyClass
{
    ICakeContext Context { get; }
    public MyClass(ICakeContext context)
    {
        Context = context;
    }

    public void MyMethod()
    {
        Context.Information("Hello");
    }
}

then used like this

// pass reference to Cake context
var myClass = new MyClass(Context);

// Call instance method which uses an Cake alias.
myClass.MyMethod();

You can have extension methods, but these can't be in a class, example:

public static void MyMethod(this ICakeContext context, string message)
{
    context.Information(message);
}


Context.MyMethod("Hello");
devlead
  • 4,935
  • 15
  • 36
  • Can the function be declared in a separate file (to keep things neat, and/or to be able to reuse it from another cake script)? – lonix Aug 07 '22 at 04:25
  • 1
    Yes, use the #load directive for that https://cakebuild.net/docs/writing-builds/preprocessor-directives/load – devlead Aug 08 '22 at 05:51