C# interactive build automation system makes it easy to build .NET projects. It can be part of your solution as a regular .NET console project or run C# scripts without compiling them, or even run in REPL mode - allowing you to run C# interactively.
✔️ Three Integrated Execution Modes
Flexible interoperability between modes for diverse workflow requirements.
Seamless operation across Windows, Linux, and macOS environments.
Ability to debug in “.NET build project” mode, allowing developers to efficiently identify and fix problems during the compilation and build process.
No restrictive abstractions (e.g., Tasks, Targets, DependsOn) to limit script design:
- Pure .NET codebase – no proprietary syntax or hidden layers
- Adheres to industry-standard coding practices for maintainability
Granular control over builds, tests, and deployments with streamlined project configuration.
Consolidated build statistics.
Interactive
REPL (Read-Eval-Print-Loop) interface for interactive code evaluation. Please see this page for installation details.
Launch the tool in the interactive mode:
dotnet csi
Simply enter C# commands sequentially one line after another and get the result in console output.
Running C# script
Direct execution of C# scripts without prior compilation:
- Zero-Compilation Workflow - execute .csx files directly using Roslyn scripting engines, bypassing traditional dotnet build steps for rapid iteration.
- Cross-Platform Scripting
- Windows - integrate with PowerShell/PowerShell Core automation pipelines
- Linux/macOS - combine with bash/zsh scripts via shebang directives (#!/usr/bin/env dotnet-script)
- Dependency Management - resolve NuGet packages in scripts via #r "nuget: PackageName/Version" syntax, with local cache optimization.
Run a specified script with a given argument:
dotnet csi ./MyDirectory/hello.csx World
Run a single script located in the MyDirectory directory:
dotnet csi ./MyDirectory World
Usage details
dotnet csi [options] [--] [script] [script arguments]
Executes a script if specified, otherwise launches an interactive REPL (Read Eval Print Loop).
--
- Indicates that the remaining arguments should not be treated as options.
script
- The path to the script file to run. If no such file is found, the command will treat it as a directory and look for a single script file inside that directory.
script arguments
- Script arguments are accessible in a script via the global list Args[index]
by an argument index.
@file
- Read the response file for more options.
Supported options:
Option | Description | Alternative form |
---|---|---|
--help | Show how to use the command. | /? , -h , /h , /help |
--version | Display the tool version. | /version |
--source | Specify the NuGet package source to use. Supported formats: URL, or a UNC directory path. | -s , /s , /source |
--property <key=value> | Define a key-value pair(s) for the script properties called Props, which is accessible in scripts. | -p , /property , /p |
--property:<key=value> | Define a key-value pair(s) in MSBuild style for the script properties called Props, which is accessible in scripts. | -p:<key=value> , /property:<key=value> , /p:<key=value> , --property:key1=val1;key2=val2 |
.NET build project
Seamless integration into existing solutions as a standard .NET console project. Please see this page for details on how to install the project template.
Create a console project Build containing a script from the template build
dotnet new build -o ./Build
The created project contains 2 entry points:
- Program.csx to run as a script
dotnet csi ./Build
- Program.cs to run as .NET application
dotnet run --project ./Build
- Build project example
- CSharp Interactive build project
- Pure.DI build project
- Immutype build project
- Comparison with Cake and Nuke
- Output, logging and tracing
- Writing a line to a build log
- Writing a line highlighted with "Header" color to a build log
- Writing an empty line to a build log
- Registering errors in the build log
- Registering warnings in the build log
- Registering a summary in the build log
- Registering information in the build log
- Registering trace information in the build log
- Arguments and parameters
- Microsoft DI
- NuGet
- Command Line
- Docker CLI
- .NET CLI
- Adding a NuGet package
- Adding a NuGet source
- Adding a project reference
- Adding projects to the solution file
- Adding project-to-project (P2P) references
- Building a project
- Building a project using MSBuild
- Cleaning a project
- Clearing the specified NuGet cache type
- Creating a new project, configuration file, or solution based on the specified template
- Deleting a NuGet package to the server
- Disabling a NuGet source
- Displaing template package metadata
- Enabling a NuGet source
- Enabling or disabling workload-set update mode
- Executing a dotnet application
- Fixing (non code style) analyzer issues
- Fixing code style issues
- Formatting a code
- Getting a value of a specified NuGet configuration setting
- Installing a template package
- Installing optional workloads
- Installing the .NET local tools that are in scope for the current directory
- Installing the specified .NET tool
- Installing workloads needed for a project or a solution
- Invoking a local tool
- Packing a code into a NuGet package
- Printing a dependency graph for NuGet package
- Printing all .NET tools of the specified type currently installed
- Printing all configured NuGet sources
- Printing all projects in a solution file
- Printing available templates to be run using dotnet new
- Printing installed workloads
- Printing nuget configuration files currently being applied to a directory
- Printing NuGet packages for a project
- Printing project references for a project
- Printing the latest available version of the .NET SDK and .NET Runtime, for each feature band
- Printing the location of the specified NuGet cache type
- Publishing an application and its dependencies to a folder for deployment to a hosting system
- Pushing a NuGet package to the server
- Removing a NuGet package
- Removing a project or multiple projects from the solution file
- Removing an existing source from your NuGet configuration files
- Repairing workloads installations
- Restoring the dependencies and tools of a project
- Running a .NET application
- Running a custom .NET command
- Running source code without any explicit compile or launch commands
- Running tests from the specified assemblies
- Running tests under dotCover
- Searching all .NET tools that are published to NuGet
- Searching for a NuGet package
- Searching for optional workloads
- Searching for the templates
- Setting the value of a specified NuGet configuration setting
- Signing with certificate
- Storing the specified assemblies in the runtime package store.
- Testing a project using the MSBuild VSTest target
- Testing from the specified project
- Uninstalling a specified workload
- Uninstalling a template package
- Uninstalling the specified .NET tool
- Unsetting the value of a specified NuGet configuration setting
- Updating a NuGet source
- Updating installed template packages
- Updating installed workloads
- Updating the specified .NET tool
- Working with development certificates
- Running C# script
- Shutting down build servers
- TeamCity API
WriteLine("Hello");
WriteLine("Hello", Header);
WriteLine("Hello ".WithColor(Header), "world!");
WriteLine();
Error("Error info");
Error("Error info", "Error identifier");
Error("Error: ".WithColor(), "datails".WithColor(Color.Details));
Warning("Warning info");
Warning("Warning ", "info".WithColor(Color.Details));
Summary("Summary message");
Summary("Summary ", "message".WithColor(Color.Details));
Info("Some info");
Info("Some ", "info".WithColor(Color.Details));
Trace("Some trace info");
Trace("Some trace ", "info".WithColor(Color.Details));
Args have got from the script arguments.
if (Args.Count > 0)
{
WriteLine(Args[0]);
}
if (Args.Count > 1)
{
WriteLine(Args[1]);
}
WriteLine(Props["version"]);
WriteLine(Props.Get("configuration", "Release"));
// Some CI/CDs have integration of these properties.
// For example in TeamCity this property with all changes will be available in the next TeamCity steps.
Props["version"] = "1.1.6";
Host is actually the provider of all global properties and methods.
var packages = Host.GetService<INuGet>();
Host.WriteLine("Hello");
This method might be used to get access to different APIs like INuGet or ICommandLine.
GetService<INuGet>();
var serviceProvider = GetService<IServiceProvider>();
serviceProvider.GetService(typeof(INuGet));
Besides that, it is possible to get an instance of System.IServiceProvider to access APIs.
public void Run()
{
var serviceProvider =
GetService<IServiceCollection>()
.AddTransient<MyTask>()
.BuildServiceProvider();
var myTask = serviceProvider.GetRequiredService<MyTask>();
var exitCode = myTask.Run();
exitCode.ShouldBe(0);
}
private class MyTask(ICommandLineRunner runner)
{
public int? Run() => runner
.Run(new CommandLine("whoami"))
.EnsureSuccess()
.ExitCode;
}
using HostApi;
IEnumerable<NuGetPackage> packages = GetService<INuGet>()
.Restore(new NuGetRestoreSettings("IoC.Container").WithVersionRange(VersionRange.All));
using HostApi;
var packagesPath = Path.Combine(
Path.GetTempPath(),
Guid.NewGuid().ToString()[..4]);
var settings = new NuGetRestoreSettings("IoC.Container")
.WithVersionRange(VersionRange.Parse("[1.3, 1.3.8)"))
.WithTargetFrameworkMoniker("net5.0")
.WithPackagesPath(packagesPath);
IEnumerable<NuGetPackage> packages = GetService<INuGet>().Restore(settings);
using HostApi;
// Creates and run a simple command line
"whoami".AsCommandLine().Run().EnsureSuccess();
// Creates and run a simple command line
new CommandLine("whoami").Run().EnsureSuccess();
// Creates and run a command line with arguments
new CommandLine("cmd", "/c", "echo", "Hello").Run();
// Same as previous statement
new CommandLine("cmd", "/c")
.AddArgs("echo", "Hello")
.Run().EnsureSuccess();
(new CommandLine("cmd") + "/c" + "echo" + "Hello")
.Run().EnsureSuccess();
"cmd".AsCommandLine("/c", "echo", "Hello")
.Run().EnsureSuccess();
("cmd".AsCommandLine() + "/c" + "echo" + "Hello")
.Run().EnsureSuccess();
// Just builds a command line with multiple environment variables
var cmd = new CommandLine("cmd", "/c", "echo", "Hello")
.AddVars(("Var1", "val1"), ("var2", "Val2"));
// Same as previous statement
cmd = new CommandLine("cmd") + "/c" + "echo" + "Hello" + ("Var1", "val1") + ("var2", "Val2");
// Builds a command line to run from a specific working directory
cmd = new CommandLine("cmd", "/c", "echo", "Hello")
.WithWorkingDirectory("MyDyrectory");
// Builds a command line and replaces all command line arguments
cmd = new CommandLine("cmd", "/c", "echo", "Hello")
.WithArgs("/c", "echo", "Hello !!!");
using HostApi;
GetService<ICommandLineRunner>()
.Run(new CommandLine("cmd", "/c", "DIR")).EnsureSuccess();
// or the same thing using the extension method
new CommandLine("cmd", "/c", "DIR")
.Run().EnsureSuccess();
// using operator '+'
var cmd = new CommandLine("cmd") + "/c" + "DIR";
cmd.Run().EnsureSuccess();
// with environment variables
cmd = new CommandLine("cmd") + "/c" + "DIR" + ("MyEnvVar", "Some Value");
cmd.Run().EnsureSuccess();
using HostApi;
await GetService<ICommandLineRunner>()
.RunAsync(new CommandLine("cmd", "/C", "DIR")).EnsureSuccess();
// or the same thing using the extension method
var result = await new CommandLine("cmd", "/c", "DIR")
.RunAsync().EnsureSuccess();
using HostApi;
var lines = new List<string>();
var result = new CommandLine("cmd", "/c", "SET")
.AddVars(("MyEnv", "MyVal"))
.Run(output => lines.Add(output.Line)).EnsureSuccess();
lines.ShouldContain("MyEnv=MyVal");
using HostApi;
var task = new CommandLine("cmd", "/c", "DIR")
.RunAsync().EnsureSuccess();
var result = new CommandLine("cmd", "/c", "SET")
.Run().EnsureSuccess();
await task;
Cancellation will destroy the process and its child processes.
using HostApi;
var cancellationTokenSource = new CancellationTokenSource();
var task = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120")
.RunAsync(null, cancellationTokenSource.Token);
cancellationTokenSource.CancelAfter(TimeSpan.FromMilliseconds(100));
task.IsCompleted.ShouldBeFalse();
If timeout expired a process will be killed.
using HostApi;
var exitCode = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120")
.Run(null, TimeSpan.FromMilliseconds(1))
.ExitCode;
using HostApi;
// Creates a base docker command line
var dockerRun = new DockerRun()
.WithAutoRemove(true)
.WithInteractive(true)
.WithImage("mcr.microsoft.com/dotnet/sdk")
.WithPlatform("linux")
.WithContainerWorkingDirectory("/MyProjects")
.AddVolumes((ToAbsoluteLinuxPath(Environment.CurrentDirectory), "/MyProjects"));
// Creates a new library project in a docker container
dockerRun
.WithCommandLine(new DotNetCustom("new", "classlib", "-n", "MyLib", "--force"))
.Run().EnsureSuccess();
// Builds the library project in a docker container
var result = dockerRun
.WithCommandLine(new DotNetBuild().WithProject("MyLib/MyLib.csproj"))
.Build().EnsureSuccess();
string ToAbsoluteLinuxPath(string path) =>
"/" + path.Replace(":", "").Replace('\\', '/');
using HostApi;
// Creates some command line to run in a docker container
var cmd = new CommandLine("whoami");
// Runs the command line in a docker container
var result = new DockerRun(cmd, "mcr.microsoft.com/dotnet/sdk")
.WithAutoRemove(true)
.Run().EnsureSuccess();
using HostApi;
var result = new DotNetAddPackage()
.WithWorkingDirectory("MyLib")
.WithPackage("Pure.DI")
.Run().EnsureSuccess();
using HostApi;
new DotNetNuGetAddSource()
.WithName("TestSource")
.WithSource(source)
.Run().EnsureSuccess();
using HostApi;
new DotNetAddReference()
.WithProject(Path.Combine("MyTests", "MyTests.csproj"))
.WithReferences(Path.Combine("MyLib", "MyLib.csproj"))
.Run().EnsureSuccess();
new DotNetRemoveReference()
.WithProject(Path.Combine("MyTests", "MyTests.csproj"))
.WithReferences(Path.Combine("MyLib", "MyLib.csproj"))
.Run().EnsureSuccess();
var lines = new List<string>();
new DotNetListReference()
.WithProject(Path.Combine("MyTests", "MyTests.csproj"))
.Run(output => lines.Add(output.Line));
lines.Any(i => i.Contains("MyLib.csproj")).ShouldBeFalse();
using HostApi;
new DotNetNew()
.WithTemplateName("sln")
.WithName("NySolution")
.WithForce(true)
.Run().EnsureSuccess();
new DotNetSlnAdd()
.WithSolution("NySolution.sln")
.AddProjects(
Path.Combine("MyLib", "MyLib.csproj"),
Path.Combine("MyTests", "MyTests.csproj"))
.Run().EnsureSuccess();
using HostApi;
var result = new DotNetAddReference()
.WithProject(Path.Combine("MyTests", "MyTests.csproj"))
.WithReferences(Path.Combine("MyLib", "MyLib.csproj"))
.Run().EnsureSuccess();
using HostApi;
var messages = new List<BuildMessage>();
var result = new DotNetBuild()
.WithWorkingDirectory("MyTests")
.Build(message => messages.Add(message)).EnsureSuccess();
result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(result.ToString());
result.ExitCode.ShouldBe(0, result.ToString());
using HostApi;
// Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force"
new DotNetNew()
.WithTemplateName("classlib")
.WithName("MyLib")
.WithForce(true)
.Build().EnsureSuccess();
// Builds the library project, running a command like: "dotnet msbuild /t:Build -restore /p:configuration=Release -verbosity=detailed" from the directory "MyLib"
var result = new MSBuild()
.WithWorkingDirectory("MyLib")
.WithTarget("Build")
.WithRestore(true)
.AddProps(("configuration", "Release"))
.WithVerbosity(DotNetVerbosity.Detailed)
.Build().EnsureSuccess();
// The "result" variable provides details about a build
result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(result.ToString());
result.ExitCode.ShouldBe(0, result.ToString());
using HostApi;
// Clean the project, running a command like: "dotnet clean" from the directory "MyLib"
new DotNetClean()
.WithWorkingDirectory("MyLib")
.Build().EnsureSuccess();
using HostApi;
new DotNetNuGetLocalsClear()
.WithCacheLocation(NuGetCacheLocation.Temp)
.Run().EnsureSuccess();
using HostApi;
new DotNetNew()
.WithTemplateName("classlib")
.WithName("MyLib")
.WithForce(true)
.Run().EnsureSuccess();
using HostApi;
new DotNetNuGetDelete()
.WithPackage("MyLib")
.WithPackageVersion("1.0.0")
.WithSource(repoUrl)
.Run().EnsureSuccess();
using HostApi;
new DotNetNuGetDisableSource()
.WithName("TestSource")
.Run().EnsureSuccess();
using HostApi;
new DotNetNewDetails()
.WithTemplateName("CSharpInteractive.Templates")
.Run().EnsureSuccess();
using HostApi;
new DotNetNuGetEnableSource()
.WithName("TestSource")
.Run().EnsureSuccess();
using HostApi;
new DotNetWorkloadConfig()
.WithUpdateMode(DotNetWorkloadUpdateMode.WorkloadSet)
.Run().EnsureSuccess();
using HostApi;
new DotNetExec()
.WithPathToApplication(Path.Combine(path, "MyApp.dll"))
.Run().EnsureSuccess();
using HostApi;
new DotNetFormatAnalyzers()
.WithWorkingDirectory("MyLib")
.WithProject("MyLib.csproj")
.AddDiagnostics("CA1831", "CA1832")
.WithSeverity(DotNetFormatSeverity.Warning)
.Run().EnsureSuccess();
using HostApi;
new DotNetFormatStyle()
.WithWorkingDirectory("MyLib")
.WithProject("MyLib.csproj")
.AddDiagnostics("IDE0005", "IDE0006")
.WithSeverity(DotNetFormatSeverity.Information)
.Run().EnsureSuccess();
using HostApi;
new DotNetFormat()
.WithWorkingDirectory("MyLib")
.WithProject("MyLib.csproj")
.AddDiagnostics("IDE0005", "IDE0006")
.AddIncludes(".", "./tests")
.AddExcludes("./obj")
.WithSeverity(DotNetFormatSeverity.Information)
.Run().EnsureSuccess();
using HostApi;
string? repositoryPath = null;
new DotNetNuGetConfigGet()
.WithConfigKey("repositoryPath")
.Run(output => repositoryPath = output.Line).EnsureSuccess();
using HostApi;
new DotNetNewInstall()
.WithPackage("Pure.DI.Templates")
.Run().EnsureSuccess();
using HostApi;
new DotNetWorkloadInstall()
.AddWorkloads("aspire")
.Run().EnsureSuccess();
using HostApi;
// Creates a local tool manifest
new DotNetNew()
.WithTemplateName("tool-manifest")
.Run().EnsureSuccess();
new DotNetToolRestore()
.Run().EnsureSuccess();
using HostApi;
new DotNetToolInstall()
.WithLocal(true)
.WithPackage("dotnet-csi")
.WithVersion("1.1.2")
.Run().EnsureSuccess();
using HostApi;
new DotNetWorkloadRestore()
.WithProject(Path.Combine("MyLib", "MyLib.csproj"))
.Run().EnsureSuccess();
using HostApi;
var script = Path.GetTempFileName();
File.WriteAllText(script, "Console.WriteLine($\"Hello, {Args[0]}!\");");
var stdOut = new List<string>();
new DotNetToolRun()
.WithCommandName("dotnet-csi")
.AddArgs(script)
.AddArgs("World")
.Run(output => stdOut.Add(output.Line))
.EnsureSuccess();
// Checks stdOut
stdOut.Contains("Hello, World!").ShouldBeTrue();
using HostApi;
// Creates a NuGet package of version 1.2.3 for the project
new DotNetPack()
.WithWorkingDirectory("MyLib")
.WithOutput(path)
.AddProps(("version", "1.2.3"))
.Build().EnsureSuccess();
using HostApi;
new DotNetNuGetWhy()
.WithProject(Path.Combine("MyLib", "MyLib.csproj"))
.WithPackage("MyLib.1.2.3.nupkg")
.Run().EnsureSuccess();
using HostApi;
new DotNetToolList()
.WithLocal(true)
.Run().EnsureSuccess();
new DotNetToolList()
.WithGlobal(true)
.Run().EnsureSuccess();
using HostApi;
new DotNetNuGetListSource()
.WithFormat(NuGetListFormat.Short)
.Run().EnsureSuccess();
using HostApi;
var lines = new List<string>();
new DotNetSlnList()
.WithSolution("NySolution.sln")
.Run(output => lines.Add(output.Line))
.EnsureSuccess();
using HostApi;
new DotNetNewList()
.Run().EnsureSuccess();
using HostApi;
new DotNetWorkloadList()
.Run().EnsureSuccess();
using HostApi;
var configPaths = new List<string>();
new DotNetNuGetConfigPaths()
.Run(output => configPaths.Add(output.Line)).EnsureSuccess();
using HostApi;
new DotNetAddPackage()
.WithWorkingDirectory("MyLib")
.WithPackage("Pure.DI")
.Run().EnsureSuccess();
var lines = new List<string>();
new DotNetListPackage()
.WithProject(Path.Combine("MyLib", "MyLib.csproj"))
.WithVerbosity(DotNetVerbosity.Minimal)
.Run(output => lines.Add(output.Line));
lines.Any(i => i.Contains("Pure.DI")).ShouldBeTrue();
using HostApi;
new DotNetAddReference()
.WithProject(Path.Combine("MyTests", "MyTests.csproj"))
.WithReferences(Path.Combine("MyLib", "MyLib.csproj"))
.Run().EnsureSuccess();
var lines = new List<string>();
new DotNetListReference()
.WithProject(Path.Combine("MyTests", "MyTests.csproj"))
.Run(output => lines.Add(output.Line));
lines.Any(i => i.Contains("MyLib.csproj")).ShouldBeTrue();
using HostApi;
var sdks = new List<Sdk>();
new DotNetSdkCheck()
.Run(output =>
{
if (output.Line.StartsWith("Microsoft."))
{
var data = output.Line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (data.Length >= 2)
{
sdks.Add(new Sdk(data[0], NuGetVersion.Parse(data[1])));
}
}
})
.EnsureSuccess();
sdks.Count.ShouldBeGreaterThan(0);
record Sdk(string Name, NuGetVersion Version);
using HostApi;
new DotNetNuGetLocalsList()
.WithCacheLocation(NuGetCacheLocation.GlobalPackages)
.Run().EnsureSuccess();
using HostApi;
new DotNetPublish()
.WithWorkingDirectory("MyLib")
.WithFramework(framework)
.WithOutput("bin")
.Build().EnsureSuccess();
using HostApi;
new DotNetNuGetPush()
.WithWorkingDirectory("MyLib")
.WithPackage(Path.Combine("packages", "MyLib.1.0.0.nupkg"))
.WithSource(repoUrl)
.Run().EnsureSuccess();
using HostApi;
new DotNetAddPackage()
.WithWorkingDirectory("MyLib")
.WithPackage("Pure.DI")
.Run().EnsureSuccess();
new DotNetRemovePackage()
.WithWorkingDirectory("MyLib")
.WithPackage("Pure.DI")
.Run().EnsureSuccess();
using HostApi;
new DotNetSlnRemove()
.WithSolution("NySolution.sln")
.AddProjects(
Path.Combine("MyLib", "MyLib.csproj"))
.Run().EnsureSuccess();
using HostApi;
new DotNetNuGetRemoveSource()
.WithName("TestSource")
.Run().EnsureSuccess();
using HostApi;
new DotNetWorkloadRepair()
.Run().EnsureSuccess();
using HostApi;
new DotNetRestore()
.WithProject(Path.Combine("MyLib", "MyLib.csproj"))
.Build().EnsureSuccess();
// Adds the namespace "HostApi" to use .NET build API
using HostApi;
new DotNet()
.WithPathToApplication(Path.Combine(path, "MyApp.dll"))
.Run().EnsureSuccess();
using HostApi;
// Gets the dotnet version, running a command like: "dotnet --version"
NuGetVersion? version = null;
new DotNetCustom("--version")
.Run(message => NuGetVersion.TryParse(message.Line, out version))
.EnsureSuccess();
version.ShouldNotBeNull();
using HostApi;
var stdOut = new List<string>();
new DotNetRun()
.WithProject(Path.Combine("MyApp", "MyApp.csproj"))
.Build(message => stdOut.Add(message.Text))
.EnsureSuccess();
using HostApi;
// Runs tests
var result = new VSTest()
.AddTestFileNames(Path.Combine("bin", "MyTests.dll"))
.WithWorkingDirectory(path)
.Build().EnsureSuccess();
// The "result" variable provides details about build and tests
result.ExitCode.ShouldBe(0, result.ToString());
result.Summary.Tests.ShouldBe(1, result.ToString());
result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1, result.ToString());
using HostApi;
new DotNetToolInstall()
.WithLocal(true)
.WithPackage("JetBrains.dotCover.GlobalTool")
.Run().EnsureSuccess();
// Creates a test command
var test = new DotNetTest()
.WithProject("MyTests");
var dotCoverSnapshot = Path.Combine("MyTests", "dotCover.dcvr");
var dotCoverReport = Path.Combine("MyTests", "dotCover.html");
// Modifies the test command by putting "dotCover" in front of all arguments
// to have something like "dotnet dotcover test ..."
// and adding few specific arguments to the end
var testUnderDotCover = test.Customize(cmd =>
cmd.ClearArgs()
+ "dotcover"
+ cmd.Args
+ $"--dcOutput={dotCoverSnapshot}"
+ "--dcFilters=+:module=TeamCity.CSharpInteractive.HostApi;+:module=dotnet-csi"
+ "--dcAttributeFilters=System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage");
// Runs tests under dotCover
var result = testUnderDotCover
.Build().EnsureSuccess();
// The "result" variable provides details about a build
result.ExitCode.ShouldBe(0, result.ToString());
result.Tests.Count(i => i.State == TestState.Finished).ShouldBe(1, result.ToString());
// Generates a HTML code coverage report.
new DotNetCustom("dotCover", "report", $"--source={dotCoverSnapshot}", $"--output={dotCoverReport}", "--reportType=HTML")
.Run().EnsureSuccess();
using HostApi;
new DotNetToolSearch()
.WithPackage("dotnet-csi")
.WithDetail(true)
.Run().EnsureSuccess();
using System.Text;
using System.Text.Json;
using HostApi;
var packagesJson = new StringBuilder();
new DotNetPackageSearch()
.WithSearchTerm("Pure.DI")
.WithFormat(DotNetPackageSearchResultFormat.Json)
.Run(output => packagesJson.AppendLine(output.Line)).EnsureSuccess();
var result = JsonSerializer.Deserialize<Result>(
packagesJson.ToString(),
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
result.ShouldNotBeNull();
result.SearchResult.SelectMany(i => i.Packages).Count(i => i.Id == "Pure.DI").ShouldBe(1);
record Result(int Version, IReadOnlyCollection<Source> SearchResult);
record Source(string SourceName, IReadOnlyCollection<Package> Packages);
record Package(
string Id,
string LatestVersion,
int TotalDownloads,
string Owners);
using HostApi;
new DotNetWorkloadSearch()
.WithSearchString("maui")
.Run().EnsureSuccess();
using HostApi;
new DotNetNewSearch()
.WithTemplateName("build")
.Run().EnsureSuccess();
using HostApi;
new DotNetNuGetConfigSet()
.WithConfigFile(configFile)
.WithConfigKey("repositoryPath")
.WithConfigValue("MyValue")
.Run().EnsureSuccess();
using HostApi;
new DotNetNuGetSign()
.AddPackages("MyLib.1.2.3.nupkg")
.WithCertificatePath("certificate.pfx")
.WithCertificatePassword("Abc")
.WithTimestampingServer("http://timestamp.digicert.com/")
.Run().EnsureSuccess();
using HostApi;
new DotNetStore()
.AddManifests(Path.Combine("MyLib", "MyLib.csproj"))
.WithFramework("net8.0")
.WithRuntime("win-x64")
.Build();
using HostApi;
// Runs tests via a command
var result = new MSBuild()
.WithTarget("VSTest")
.WithWorkingDirectory("MyTests")
.Build().EnsureSuccess();
// The "result" variable provides details about a build
result.ExitCode.ShouldBe(0, result.ToString());
result.Summary.Tests.ShouldBe(1, result.ToString());
result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1, result.ToString());
using HostApi;
// Runs tests
var result = new DotNetTest()
.WithProject("MyTests")
.Build().EnsureSuccess();
using HostApi;
new DotNetWorkloadUninstall()
.AddWorkloads("aspire")
.Run().EnsureSuccess();
using HostApi;
new DotNetNewUninstall()
.WithPackage("Pure.DI.Templates")
.Run();
using HostApi;
new DotNetToolUninstall()
.WithPackage("dotnet-csi")
.Run().EnsureSuccess();
using HostApi;
new DotNetNuGetConfigUnset()
.WithConfigKey("repositoryPath")
.Run().EnsureSuccess();
using HostApi;
new DotNetNuGetUpdateSource()
.WithName("TestSource")
.WithSource(newSource)
.Run().EnsureSuccess();
using HostApi;
new DotNetNewUpdate()
.Run().EnsureSuccess();
using HostApi;
new DotNetWorkloadUpdate()
.Run().EnsureSuccess();
using HostApi;
new DotNetToolUpdate()
.WithLocal(true)
.WithPackage("dotnet-csi")
.WithVersion("1.1.2")
.Run().EnsureSuccess();
using HostApi;
// Create a certificate, trust it, and export it to a PEM file.
new DotNetDevCertsHttps()
.WithExportPath("certificate.pem")
.WithTrust(true)
.WithFormat(DotNetCertificateFormat.Pem)
.WithPassword("Abc")
.Run().EnsureSuccess();
using HostApi;
var script = Path.GetTempFileName();
File.WriteAllText(script, "Console.WriteLine($\"Hello, {Args[0]}!\");");
var stdOut = new List<string>();
new DotNetCsi()
.WithScript(script)
.AddArgs("World")
.Run(output => stdOut.Add(output.Line))
.EnsureSuccess();
// Checks stdOut
stdOut.Contains("Hello, World!").ShouldBeTrue();
using HostApi;
// Shuts down all build servers that are started from dotnet.
new DotNetBuildServerShutdown()
.Run().EnsureSuccess();
For more details how to use TeamCity service message API please see this page. Instead of creating a root message writer like in the following example:
using JetBrains.TeamCity.ServiceMessages.Write.Special;
using var writer = new TeamCityServiceMessages().CreateWriter(Console.WriteLine);
use this statement:
using JetBrains.TeamCity.ServiceMessages.Write.Special;
using var writer = GetService<ITeamCityWriter>();
This sample opens a block My Tests and reports about two tests:
// Adds a namespace to use ITeamCityWriter
using JetBrains.TeamCity.ServiceMessages.Write.Special;
using var writer = GetService<ITeamCityWriter>();
using (var tests = writer.OpenBlock("My Tests"))
{
using (var test = tests.OpenTest("Test1"))
{
test.WriteStdOutput("Hello");
test.WriteImage("TestsResults/Test1Screenshot.jpg", "Screenshot");
test.WriteDuration(TimeSpan.FromMilliseconds(10));
}
using (var test = tests.OpenTest("Test2"))
{
test.WriteIgnored("Some reason");
}
}
For more information on TeamCity Service Messages, see this page.