-
Notifications
You must be signed in to change notification settings - Fork 0
Migrating From Cake
Cake (Cake.Tool / dotnet cake build.cake) and Tamp solve the same problem with different shapes. This is a concept-by-concept guide for moving an existing Cake build to Tamp.
- Tool wrapper philosophy. Cake's "addins" model — independently-versioned packages that wrap external tools — is the model Tamp adopted (with explicit version pinning per ADR 0002).
-
Target authoring. "Run X, then Y, then Z" via declarative dependencies. Cake's
Task("Build").IsDependentOn("Clean")↔ Tamp'sTarget Build => _ => _.DependsOn(nameof(Clean)). - Multiple targets per build. Both projects let you invoke specific targets and run the full pipeline by default.
-
Argument injection. Cake's
Argument("configuration", "Release")↔ Tamp's[Parameter] string Configuration = "Release". -
Global tool installation flow.
dotnet tool install -g Cake.Tool && dotnet cake build.cake↔dotnet tool install -g dotnet-tamp && dotnet tamp ci.
Cake builds are C# scripts (build.cake) that the Cake runner compiles and executes on each invocation. There's no separate project, no .csproj, no compile phase you control.
Tamp builds are regular .NET console projects. You have a build/Build.csproj, you reference Tamp.Core like any other dependency, you get full IDE support, refactoring tools work, and the build itself is just dotnet run --project build. The global tool exists for ergonomics but nothing depends on it.
This is the biggest change in feel. Pros and cons of the Tamp model:
- ✅ Real IDE support — IntelliSense, F12 navigation, refactoring, debugging.
- ✅ Standard NuGet dependency management — same
Directory.Packages.propsyou already use elsewhere. - ✅ Type-safe everything; Cake's preprocessor directives (
#addin,#tool,#load) become<PackageReference>and ordinary C# namespaces. - ❌ Not a single-file script anymore.
build/is a small project with one or two files.
Cake: #addin nuget:?package=Cake.Docker at the top of the script.
Tamp: <PackageReference Include="Tamp.Docker.V27" /> in build/Build.csproj, then using Tamp.Docker.V27; in Build.cs.
Cake: #tool nuget:?package=ReportGenerator at the top of the script.
Tamp: [NuGetPackage("ReportGenerator")] readonly Tool ReportGenerator; as a property on the build class. The first run installs into a Tamp-managed cache; subsequent runs reuse.
Cake's task definition shape (Task("Build").IsDependentOn(...).Does(() => {...})) becomes Tamp's Target Build => _ => _.DependsOn(nameof(Clean)).Executes(() => {...}).
// Cake (build.cake)
Task("Clean")
.Does(() => CleanDirectory("./artifacts"));
Task("Build")
.IsDependentOn("Clean")
.Does(() => DotNetBuild("./MySln.sln"));
Task("Default")
.IsDependentOn("Build");
RunTarget(Argument("target", "Default"));// Tamp (Build.cs)
using Tamp;
using Tamp.NetCli.V10;
class Build : TampBuild
{
public static int Main(string[] args) => Execute<Build>(args);
AbsolutePath Artifacts => RootDirectory / "artifacts";
Target Clean => _ => _.Executes(() => Artifacts.Delete());
Target Compile => _ => _
.DependsOn(nameof(Clean))
.Executes(() => DotNet.Build(s => s.SetProject("./MySln.slnx")));
Target Default => _ => _.DependsOn(nameof(Compile));
}Cake aliases like DotNetBuild("./MySln.sln") become Tamp's DotNet.Build(s => s.SetProject("./MySln.slnx")). Configuration is a fluent chain on a settings object rather than overloads of free functions.
// Cake
DotNetBuild("./MySln.sln", new DotNetBuildSettings
{
Configuration = "Release",
NoRestore = true,
});
// Tamp
DotNet.Build(s => s
.SetProject("./MySln.slnx")
.SetConfiguration(Configuration.Release)
.SetNoRestore(true));Cake reads Argument<T>(name, default) and EnvironmentVariable(name) imperatively in the script body. Tamp uses [Parameter] attributes on properties; resolution happens once before any target runs, with CLI > env > default precedence.
| Cake | Tamp |
|---|---|
var cfg = Argument("configuration", "Debug"); |
[Parameter] string Configuration = "Debug"; |
EnvironmentVariable("CI") |
[Parameter(EnvironmentVariable = "CI")] bool IsCi; |
Cake has DirectoryPath and FilePath distinct types. Tamp has a single AbsolutePath covering both — same operations whether the path is a file or a directory.
// Cake
DirectoryPath src = "./src";
FilePath csproj = src.CombineWithFilePath("MyApp/MyApp.csproj");
// Tamp
AbsolutePath src = RootDirectory / "src";
AbsolutePath csproj = src / "MyApp" / "MyApp.csproj";Cake: OnError is a per-task setter that runs cleanup on failure.
Tamp:
-
OnFailureOf(nameof(X))— explicit catch handler that runs only when X failed -
AssuredAfterFailure()— cleanup that always runs -
FailureMode(FailureMode.Continue)— this target's failure shouldn't stop the build
The decision matrix is in Failure Handling.
-
Project setup.
mkdir build && cd build && dotnet new console -n Build -o .. Add references toTamp.Core+ the modules your script used. Each Cake#addinbecomes a<PackageReference>. -
Convert the script. Move
build.cake→Build.cs(or several files inbuild/). The class derives fromTampBuild;MaincallsExecute<Build>(args). -
Rewrite tasks. Each
Task("X")becomes aTarget Xproperty. EachIsDependentOnbecomesDependsOn(nameof(Y)). - Wrappers. Replace each Cake alias with the corresponding Tamp wrapper call. Most names are similar; settings move from anonymous-object initializer to fluent chain.
-
Arguments. Convert each
Argument(...)to a[Parameter]property. Defaults move to the property's declared default. -
Cleanup paths. Cake's
CleanDirectorybecomespath.Delete()orpath.GlobDirectories("**/bin", "**/obj").ForEach(d => d.Delete()). -
Tool resolution.
#tool nuget:?package=Foobecomes[NuGetPackage("Foo")] readonly Tool Foo;. -
Test it locally.
dotnet run --project build -- Default— should run the full pipeline. -
Install the global tool (optional).
dotnet tool install -g dotnet-tampif you want the samedotnet cake-shaped invocation, justdotnet tamp Default.
- Build Script Authoring — full DSL surface
- Module Catalog — what's available
- Migrating from NUKE — sibling guide
Start here
Modules
- Module Catalog (canonical list, 50+ satellites)
- .NET toolchain
- Containers
- JS toolchain
- Supply-chain security
Analyzers
Tooling
Execution
CI integration
Editor integration
Migration
Reference
Project