A couple of years ago I blogged Dispelling the magic!, a post explaining the internals of the Cake build orchestration tool, with that post as a proof of concept I created Cake.Bridge assembly which provided an easy way from any .NET language get access to Cake abstractions and addins from a single instance static class.
The Need
Cake has some real nice testable abstractions around working with the filesystem, processes, tools, etc. and for a .NET project, we had just that need. But a static instance isn't very testable, and for most of our .NET projects (console apps, APIs, Azure Functions, WPF, etc.) we now use dependency injection using Microsoft.Extensions.DependencyInjection.
So with that in mind, I created an extension method to IServiceCollection that easily provided me a way to get a IFileSystem injected and utilizing the FakeFileSystem provided by Cake.Testing for testing. That grew into supporting most core Cake types including the more complex ICakeContext and IScriptHost.
Introducing Cake.Bridge.DependencyInjection
If we got a need, chances are someone else has it too, so I've open-sourced the code and made it available as a NuGet package. It's early bits tailored for a specific need, so you should expect some rough edges, but sharing is caring.
Usage
Obtain
The assembly is published at NuGet.org/packages/Cake.Bridge.DependencyInjection.
.NET CLI
dotnet add package Cake.Bridge.DependencyInjection
PackageReference
<PackageReference Include="Cake.Bridge.DependencyInjection" Version="0.1.0" />
Register
using Cake.Bridge.DependencyInjection;
...
serviceCollection
.AddCakeCore();
Resolve
using Cake.Core;
...
var cakeContext = serviceProvider.GetRequiredService<ICakeContext>();
Use
Once registered you can now via dependency injection access the majority Cake.Core interfaces with ease, i.e:
- ICakeContext - Gives access to Cake built-in and addin aliases, and most Cake abstractions.
- IScriptHost - Gives access to script/task runner.
- ICakeLog - Cake logging implementation.
- IFileSystem - Cake file system abstraction.
Example ICakeContext
using Cake.Bridge.DependencyInjection;
using Cake.Core;
using Cake.Core.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
var serviceCollection = new ServiceCollection()
.AddCakeCore();
var serviceProvider = serviceCollection.BuildServiceProvider();
var cakeContext = serviceProvider.GetRequiredService<ICakeContext>();
cakeContext.Log.Write(
Verbosity.Normal,
LogLevel.Information,
"Hello World!");
will output
Hello World!
Example IScriptHost and Cake.Common
Cake.Common contains Cake aliases normally ships together with the Cake script runner, when using Cake Bridge you'll need to add it to you project (same for any Cake addin).
.NET CLI
dotnet add package Cake.Common --version 1.0.0-rc0002
PackageReference
<PackageReference Include="Cake.Common" Version="1.0.0-rc0002" />
then add the appropriate using statements and you can achieve something very similar to a Cake "script"
using Cake.Bridge.DependencyInjection;
using Cake.Core;
using Cake.Common.Diagnostics;
using Cake.Core.Scripting;
using Microsoft.Extensions.DependencyInjection;
var serviceCollection = new ServiceCollection()
.AddCakeCore();
var serviceProvider = serviceCollection.BuildServiceProvider();
var scriptHost = serviceProvider.GetRequiredService<IScriptHost>();
scriptHost.Task("Hello")
.Does(ctx => ctx.Information("Hello"));
scriptHost.Task("World")
.IsDependentOn("Hello")
.Does(ctx => ctx.Information("World"));
await scriptHost.RunTargetAsync("World");
will output
========================================
Hello
========================================
Hello
========================================
World
========================================
World
Task Duration
--------------------------------------------------
Hello 00:00:00.0226275
World 00:00:00.0002682
--------------------------------------------------
Total: 00:00:00.0228957
Complete example project
A full example console application using Spectre.Console demonstrating usage of both ICakeContext and IScriptHost can be found in project's GitHub repository at src/Cake.Bridge.DependencyInjection.Example.
Resources
- GitHub - github.com/devlead/Cake.Bridge.DependencyInjection
- NuGet - nuget.org/packages/Cake.Bridge.DependencyInjection
This post is licensed under a Creative Commons Attribution 4.0 International License