-
Notifications
You must be signed in to change notification settings - Fork 0
Tamp NetCli
Wrapper for the dotnet SDK CLI. Three sibling packages — Tamp.NetCli.V8, Tamp.NetCli.V9, Tamp.NetCli.V10 — each pinned to its respective .NET major. Pick the package that matches the SDK version you're driving. The wrapper code today is byte-for-byte identical across the three; the version pin in the package name is the consumer-facing contract per ADR 0002.
The namespace mirrors the package: using Tamp.NetCli.V10;.
DotNet.Restore(s => …) // dotnet restore
DotNet.Build(s => …) // dotnet build
DotNet.Test(s => …) // dotnet test
DotNet.Pack(s => …) // dotnet pack
DotNet.Publish(s => …) // dotnet publishEach takes an optional Action<TSettings> configurer and returns a CommandPlan. Calling with no configurer is permitted — produces dotnet <verb> with no arguments.
Inherited from DotNetSettingsBase:
| Setter | Effect |
|---|---|
SetProject(string?) |
The .csproj / .sln / directory the command targets. Null lets dotnet auto-discover. |
SetVerbosity(DotNetVerbosity) |
Quiet / Minimal / Normal / Detailed / Diagnostic → --verbosity <level>. |
SetWorkingDirectory(string?) |
Sets the spawned process's CWD. |
EnvironmentVariables[k] = v |
Per-invocation env vars on top of the inherited environment. |
Every plan automatically sets DOTNET_NOLOGO=1 and DOTNET_CLI_TELEMETRY_OPTOUT=1.
DotNet.Restore(s => s
.SetProject("./src/MyApp.csproj")
.SetUseLockFile(true)
.SetLockedMode(true) // CI-friendly: fail if lock file is out of date
.AddSource("https://api.nuget.org/v3/index.json")
.SetForce(true));Settings: Project, NoCache, Force, Sources (list, repeated as multiple --source), PackagesDirectory, Runtime, ConfigFile, DisableParallel, ForceEvaluate, UseLockFile, LockedMode, LockFilePath.
DotNet.Build(s => s
.SetConfiguration(Configuration.Release)
.SetNoRestore(true) // pair with explicit Restore target
.SetFramework("net10.0")
.SetProperty("Version", "1.2.3")
.SetProperty("ContinuousIntegrationBuild", "true"));Settings: Project, Configuration, NoRestore, NoIncremental, NoDependencies, Output, Runtime, Framework, VersionSuffix, plus arbitrary MSBuild properties via SetProperty(name, value) → emitted as -p:Name=value pairs.
DotNet.Test(s => s
.SetConfiguration(Configuration.Release)
.SetNoBuild(true)
.SetFilter("Category!=Integration")
.AddLogger("trx;LogFileName=results.trx")
.AddLogger("console;verbosity=normal")
.SetResultsDirectory("./TestResults")
.SetBlameHang(true)
.SetBlameHangTimeout(TimeSpan.FromMinutes(5)));Settings: Project, Configuration, NoBuild, NoRestore, Filter, Loggers (list, repeated), ResultsDirectory, Settings, Runtime, Framework, BlameHang, BlameHangTimeout, MSBuild properties.
DotNet.Pack(s => s
.SetConfiguration(Configuration.Release)
.SetNoBuild(true)
.SetOutput(ArtifactsDirectory)
.SetVersionSuffix(Git.Commit[..7])
.SetIncludeSymbols(true));Settings: Project, Configuration, NoBuild, NoRestore, NoDependencies, Output, VersionSuffix, IncludeSymbols, IncludeSource, Serviceable, Runtime, MSBuild properties.
DotNet.Publish(s => s
.SetConfiguration(Configuration.Release)
.SetOutput("./out")
.SetRuntime("linux-x64")
.SetSelfContained(true) // emits --self-contained or --no-self-contained
.SetPublishSingleFile(true)
.SetPublishTrimmed(true));Settings: Project, Configuration, NoBuild, NoRestore, NoDependencies, Output, Runtime, Framework, SelfContained (nullable bool — null omits the flag), PublishSingleFile, PublishTrimmed, PublishReadyToRun, VersionSuffix, MSBuild properties.
Publish a .nupkg (or a glob of them) to a NuGet feed. Wrapper-symmetric across local-dev and CI: the same target call works whether you're running tamp push from your laptop or the equivalent step in TeamCity / Azure DevOps / GitHub Actions. No need for vendor-specific publish plugins.
[Secret("NuGet API key", EnvironmentVariable = "NUGET_API_KEY")]
Secret NuGetApiKey = null!;
Target Push => _ => _
.DependsOn(nameof(Pack))
.OnlyWhen(() => Git.Branch == "main")
.Requires(() => NuGetApiKey != null)
.Executes(() => Artifacts.GlobFiles("*.nupkg")
.Select(p => DotNet.NuGetPush(s => s
.SetPackagePath(p)
.SetSource("https://api.nuget.org/v3/index.json")
.SetApiKey(NuGetApiKey)
.SetSkipDuplicate(true))));Settings: PackagePath (required, supports globs like artifacts/*.nupkg), Source (defaults to nuget.org if unset), ApiKey (typed Secret — value is registered with the runner's redaction table so any echo in the log is scrubbed), SymbolSource and SymbolApiKey (Secret) for separate symbol feeds, NoSymbols, SkipDuplicate (recommended for CI re-runs — makes the push idempotent), Timeout, DisableBuffering, NoServiceEndpoint, ForceEnglishOutput.
The --api-key flag has to be on the command line — dotnet nuget push doesn't accept the value via stdin. So the API key is briefly visible to the OS process table while the child process runs (a standard OS-level limitation). Tamp's redaction layer scrubs the value from any log output that flows through the executor's writer.
For CI publishes, prefer trusted publishing over long-lived API keys. NuGet's Trusted Publishing on GitHub Actions uses OIDC to mint a 1-hour API key per workflow run — no secret in CI configuration, automatic rotation, scoped to a specific workflow file. The same DotNet.NuGetPush wrapper handles both modes; only the source of the API key differs.
A worked GitHub Actions release workflow using trusted publishing is in this repo's .github/workflows/release.yml.
Target Restore => _ => _.Executes(() => DotNet.Restore());
Target Compile => _ => _
.DependsOn(nameof(Restore))
.Executes(() => DotNet.Build(s => s
.SetConfiguration(Configuration)
.SetNoRestore(true)));
Target Test => _ => _
.DependsOn(nameof(Compile))
.Executes(() => DotNet.Test(s => s
.SetConfiguration(Configuration)
.SetNoBuild(true)
.AddLogger("trx;LogFileName=results.trx")));
Target Pack => _ => _
.DependsOn(nameof(Test))
.Executes(() => DotNet.Pack(s => s
.SetConfiguration(Configuration)
.SetNoBuild(true)
.SetOutput(Artifacts)));[GitRepository] readonly GitRepository Git;
Target Compile => _ => _.Executes(() => DotNet.Build(s => s
.SetConfiguration(Configuration.Release)
.SetProperty("Version", "1.0.0")
.SetProperty("VersionSuffix", $"ci.{Git.Commit[..7]}")
.SetProperty("ContinuousIntegrationBuild", "true")
.SetProperty("Deterministic", "true")));Target Test => _ => _.Executes(() => DotNet.Test(s => s
.SetNoBuild(true)
.AddLogger("trx;LogFileName=test-results.trx")
.AddLogger($"console;verbosity={(IsServerBuild ? "minimal" : "normal")}")));The wrapper surface is identical today — adding Tamp.NetCli.V8 and Tamp.NetCli.V9 was a sed from V10 modulo namespace. Where the wrapped CLI surface diverges in the future (a new flag in V11, a removed flag in V12), the version-pinned packages will branch independently per ADR 0002.
Pick the V matching your build script's <TargetFramework>. Mixing — e.g., a net10.0 build script that uses Tamp.NetCli.V8 to drive dotnet 8 builds — is also fine; the wrapper just emits commands, it doesn't run them itself.
- Module Catalog — every module Tamp ships
- Tamp.Docker — Docker CLI wrapper
- Build Script Authoring — consumer side
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