-
Notifications
You must be signed in to change notification settings - Fork 0
Migrating From NUKE
Tamp is deliberately NUKE-shaped at the surface — the target authoring DSL syntax is similar because the syntax is good. The architecture underneath is what was rebuilt. This guide is a concept-by-concept mapping for someone porting an existing NUKE build.
-
Build class shape. Derive from a base class, declare
Target-typed properties, lambda configurer with_ => _.X().Y().Z(). NUKE'sclass Build : NukeBuild→ Tamp'sclass Build : TampBuild. -
Target authoring.
DependsOn,Before,After,Triggers,TriggeredBy,OnlyWhen(split here intoOnlyWhenStatic/OnlyWhenDynamicin NUKE),Requires,Executes,Description. Same idioms. -
Parameter injection.
[Parameter]attribute with environment-variable + CLI override. Same precedence (CLI > env > default). -
Built-in statics.
RootDirectory,TemporaryDirectory,IsLocalBuild,IsServerBuild— same names. -
AbsolutePath. First-class path type with
/operator, glob, hash, copy/move. Tamp'sAbsolutePathis a near-port. -
Tool-wrapper shape.
Tool.Build(s => s.SetX(...))— typed configurer returning a plan. Tamp's wrappers follow the same pattern.
NUKE: one big Nuke.Common package with all the wrapper extensions inside, plus Nuke.Build, Nuke.GlobalTool, etc.
Tamp: each tool wrapper is an independently versioned package, with the wrapped-tool major in the name when the CLI surface breaks across majors:
| NUKE | Tamp |
|---|---|
using Nuke.Common.Tools.DotNet; |
using Tamp.NetCli.V10; (or .V8, .V9) |
using Nuke.Common.Tools.Docker; |
using Tamp.Docker.V27; |
Recorded in ADR 0002. The motivation is the lifecycle problem that broke NUKE: every wrapper bottlenecked on one repo's release cadence. Tamp pushes wrappers out where each can move independently.
NUKE has AssuredAfterFailure (always run after the build) and ProceedAfterFailure (this target's failure shouldn't stop the build, equivalent to Tamp's FailureMode.Continue). Tamp adds OnFailureOf(name) — a true catch handler that runs only when the named target fails. NUKE has nothing like this; the closest in NUKE is wrapping the failing target in try/catch inside a single Executes block.
// Tamp:
Target Notify => _ => _
.OnFailureOf(nameof(Deploy))
.Executes(() => Slack.Post(...));See Failure Handling for the full decision matrix.
NUKE: DependsOn, DependentFor, Before, After, Triggers, TriggeredBy. Tamp has the same except DependentFor (the inverse direction of DependsOn) — you can express the same thing by adding DependsOn on the receiving end, and we found this clearer in practice.
NUKE: Unlisted() hides a target from --list.
Tamp 1.1.0+: every target is top-level (listed) by default; mark internal helpers with .Internal(). Same shape as NUKE's Unlisted() — different name to avoid implying the target is unreachable. Hidden targets stay invokable by name and surface under --list --all. The pre-1.1.0 inverse TopLevel() marker is obsolete and a no-op; remove it during the upgrade.
NUKE has Nuke.Components — IRestore, ICompile, ITest, IPack, IPublish, IHazSolution, IHazGitRepository, etc. — interface-based mixin pattern for target reuse. Tamp does not ship this yet. It's a Tier 3 plan; deliberately staged after the small core and module catalog stabilize. If your NUKE build leaned heavily on components, you'll write the targets out by hand for now.
NUKE generates CI YAML from build code ([GitHubActions(...)], [AzurePipelines(...)], etc.). Tamp does not ship this. Configuration is hand-written YAML for now. The thinking: most teams treat their CI YAML as the source of truth for when things run, and the build script as the source of truth for what runs. Tamp builds the latter and stays out of the former.
NUKE has Nuke.Tooling.Generator — JSON schemas describe each tool's CLI; codegen produces the wrapper classes. Tamp's wrappers are hand-authored today. Codegen is on the roadmap (deferred ADR 0013) and will eliminate the V8/V9/V10 duplication; for the moment it's small enough to maintain manually.
NUKE uses Serilog. Tamp ships a minimal in-house Logger with Trace/Debug/Info/Warn/Error levels, no external deps. Output flows through a RedactingTextWriter so registered secrets are scrubbed automatically. A future Tamp.Logging.Serilog package would adapt the calls into a Serilog pipeline for consumers who want it.
| NUKE | Tamp |
|---|---|
class Build : NukeBuild |
class Build : TampBuild |
[Parameter] string Configuration |
[Parameter] string Configuration |
[Solution] readonly Solution Solution |
[Solution] readonly Solution Solution |
[GitRepository] readonly GitRepository GitRepository |
[GitRepository] readonly GitRepository Git |
[GitVersion] readonly GitVersion GitVersion |
(not yet — Tamp.GitVersion planned) |
[NuGetPackage("foo")] readonly Tool Foo |
[NuGetPackage("foo")] readonly Tool Foo |
Target Compile => _ => _.DependsOn(Restore).Executes(...) |
Target Compile => _ => _.DependsOn(nameof(Restore)).Executes(...) |
OnlyWhenStatic / OnlyWhenDynamic |
OnlyWhen (single method; expression always captured) |
Requires(() => Solution) |
Requires(() => Solution != null) |
Triggers(...) / TriggeredBy(...)
|
same |
AssuredAfterFailure() |
same |
ProceedAfterFailure() |
FailureMode(FailureMode.Continue) |
| (no equivalent) |
OnFailureOf(nameof(X)) — catch handler |
Unlisted() |
Internal() (1.1.0+) — same shape, renamed to remove the "unreachable" implication |
DotNetTasks.DotNetBuild(...) |
DotNet.Build(...) (different namespace per major: Tamp.NetCli.V10) |
DockerTasks.DockerBuild(...) |
Docker.Build(...) (Tamp.Docker.V27) |
RootDirectory / TemporaryDirectory
|
same |
-
Project setup. Create
build/Build.csprojreferencingTamp.Core+ the modules you need. Replace NUKE references. -
Class. Change
: NukeBuildto: TampBuild. -
Imports.
using Nuke.Common.Tools.DotNet;→using Tamp.NetCli.V10;(pick the V matching your dotnet SDK). -
Targets. Convert wrapper calls —
DotNetTasks.DotNetBuild→DotNet.Build. Most flag setters keep identical names. -
Parameter expressions.
Requires(() => Solution)becomesRequires(() => Solution != null). -
nameoffor dep references. Tamp'sDependsOntakes target names; NUKE accepts both delegates and names. Usenameof(OtherTarget). -
Unlisted→Internal(). Targets are visible by default in Tamp 1.1.0+; mark helpers you don't want surfaced in--listwith.Internal(). If you've migrated from a pre-1.1.0 Tamp build, strip the obsolete.TopLevel()calls — they're now no-ops. -
Components. If you used
Nuke.Componentsinterfaces, you'll inline those for now. - CI YAML. If NUKE was generating your YAML, hand-write it. Tamp ships GitHub Actions / Azure DevOps / TeamCity vendor adapters but doesn't generate the workflow files themselves.
- Build Script Authoring — full DSL surface
- Module Catalog — every wrapper Tamp ships
- Migrating from Cake — 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