From 912f1af5c6a42cdb311a7878426cc25303c5f534 Mon Sep 17 00:00:00 2001 From: Nikolay Pianikov Date: Thu, 18 Jul 2024 23:48:54 +0300 Subject: [PATCH] Update examples --- CSharpInteractive.Tests/README_TEMPLATE.md | 226 ++++++++++++---- .../UsageScenarios/BaseScenario.cs | 2 + .../CommandLineAsyncCancellation.cs | 5 +- .../CommandLineAsyncScenario.cs | 12 +- .../CommandLineInParallelScenario.cs | 14 +- .../CommandLineOutputScenario.cs | 7 +- .../UsageScenarios/CommandLineScenario.cs | 8 +- .../CommandLineWithTimeoutScenario.cs | 5 +- .../UsageScenarios/CommandLinesScenario.cs | 19 +- .../DockerDotNetBuildScenario.cs | 6 +- .../UsageScenarios/DockerRunScenario.cs | 2 + .../UsageScenarios/DotNetBuildScenario.cs | 16 +- .../DotNetBuildServerShutdownScenario.cs | 4 +- .../UsageScenarios/DotNetCleanScenario.cs | 16 +- .../UsageScenarios/DotNetCustomScenario.cs | 2 +- .../DotNetMSBuildVSTestScenario.cs | 9 +- .../UsageScenarios/DotNetPackScenario.cs | 8 +- .../UsageScenarios/DotNetPublishScenario.cs | 12 +- .../UsageScenarios/DotNetRestoreScenario.cs | 11 +- .../UsageScenarios/DotNetRunScenario.cs | 10 +- .../UsageScenarios/DotNetTestScenario.cs | 10 +- .../DotNetTestWithDotCoverScenario.cs | 17 +- .../DotNetToolRestoreScenario.cs | 10 +- .../UsageScenarios/DotNetVSTestScenario.cs | 30 ++- .../UsageScenarios/MSBuildScenario.cs | 8 +- .../UsageScenarios/NuGetRestoreScenario.cs | 3 +- .../ServiceCollectionScenario.cs | 6 +- CSharpInteractive/Composition.cs | 2 +- CSharpInteractive/Core/Environment.cs | 16 ++ CSharpInteractive/Core/ExitTracker.cs | 3 +- CSharpInteractive/Core/IEnvironment.cs | 2 + CSharpInteractive/Core/ITestEnvironment.cs | 8 + CSharpInteractive/Root.cs | 1 + README.md | 253 +++++++++++++----- README_BODY.md | 27 +- 35 files changed, 590 insertions(+), 200 deletions(-) create mode 100644 CSharpInteractive/Core/ITestEnvironment.cs diff --git a/CSharpInteractive.Tests/README_TEMPLATE.md b/CSharpInteractive.Tests/README_TEMPLATE.md index 68e32915..c76d000f 100644 --- a/CSharpInteractive.Tests/README_TEMPLATE.md +++ b/CSharpInteractive.Tests/README_TEMPLATE.md @@ -123,8 +123,10 @@ public void Run() private class MyTask(ICommandLineRunner runner) { - public int? Run() => - runner.Run(new CommandLine("whoami")).ExitCode; + public int? Run() => runner + .Run(new CommandLine("whoami")) + .EnsureSuccess() + .ExitCode; } ``` @@ -210,10 +212,10 @@ Trace("Some trace info"); using HostApi; // Creates and run a simple command line -"whoami".AsCommandLine().Run(); +"whoami".AsCommandLine().Run().EnsureSuccess(); // Creates and run a simple command line -new CommandLine("whoami").Run(); +new CommandLine("whoami").Run().EnsureSuccess(); // Creates and run a command line with arguments new CommandLine("cmd", "/c", "echo", "Hello").Run(); @@ -221,13 +223,20 @@ new CommandLine("cmd", "/c", "echo", "Hello").Run(); // Same as previous statement new CommandLine("cmd", "/c") .AddArgs("echo", "Hello") - .Run(); + .Run() + .EnsureSuccess(); -(new CommandLine("cmd") + "/c" + "echo" + "Hello").Run(); +(new CommandLine("cmd") + "/c" + "echo" + "Hello") + .Run() + .EnsureSuccess(); -"cmd".AsCommandLine("/c", "echo", "Hello").Run(); +"cmd".AsCommandLine("/c", "echo", "Hello") + .Run() + .EnsureSuccess(); -("cmd".AsCommandLine() + "/c" + "echo" + "Hello").Run(); +("cmd".AsCommandLine() + "/c" + "echo" + "Hello") + .Run() + .EnsureSuccess(); // Just builds a command line with multiple environment variables var cmd = new CommandLine("cmd", "/c", "echo", "Hello") @@ -255,10 +264,14 @@ cmd = new CommandLine("cmd", "/c", "echo", "Hello") // Adds the namespace "HostApi" to use Command Line API using HostApi; -GetService().Run(new CommandLine("cmd", "/c", "DIR")).EnsureSuccess(); +GetService() + .Run(new CommandLine("cmd", "/c", "DIR")) + .EnsureSuccess(); // or the same thing using the extension method -new CommandLine("cmd", "/c", "DIR").Run().EnsureSuccess(); +new CommandLine("cmd", "/c", "DIR") + .Run() + .EnsureSuccess(); // using operator '+' var cmd = new CommandLine("cmd") + "/c" + "DIR"; @@ -279,10 +292,14 @@ cmd.Run().EnsureSuccess(); // Adds the namespace "HostApi" to use Command Line API using HostApi; -var task = await GetService().RunAsync(new CommandLine("cmd", "/C", "DIR")); +await GetService() + .RunAsync(new CommandLine("cmd", "/C", "DIR")) + .EnsureSuccess(); // or the same thing using the extension method -task = await new CommandLine("cmd", "/c", "DIR").RunAsync(); +var result = await new CommandLine("cmd", "/c", "DIR") + .RunAsync() + .EnsureSuccess(); ``` @@ -296,9 +313,10 @@ task = await new CommandLine("cmd", "/c", "DIR").RunAsync(); using HostApi; var lines = new List(); -int? exitCode = new CommandLine("cmd", "/c", "SET") +var result = new CommandLine("cmd", "/c", "SET") .AddVars(("MyEnv", "MyVal")) - .Run(output => lines.Add(output.Line)).ExitCode; + .Run(output => lines.Add(output.Line)) + .EnsureSuccess(); lines.ShouldContain("MyEnv=MyVal"); ``` @@ -313,23 +331,30 @@ lines.ShouldContain("MyEnv=MyVal"); // Adds the namespace "HostApi" to use Command Line API using HostApi; -var task = new CommandLine("cmd", "/c", "DIR").RunAsync(); -var result = new CommandLine("cmd", "/c", "SET").Run(); -task.Wait(); +var task = new CommandLine("cmd", "/c", "DIR") + .RunAsync() + .EnsureSuccess(); + +var result = new CommandLine("cmd", "/c", "SET") + .Run() + .EnsureSuccess(); + +await task; ``` ### Cancellation of asynchronous run -The cancellation will kill a related process. +Cancellation will destroy the process and its child processes. ``` CSharp // Adds the namespace "HostApi" to use Command Line API using HostApi; var cancellationTokenSource = new CancellationTokenSource(); -var task = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120").RunAsync(default, cancellationTokenSource.Token); +var task = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120") + .RunAsync(default, cancellationTokenSource.Token); cancellationTokenSource.CancelAfter(TimeSpan.FromMilliseconds(100)); task.IsCompleted.ShouldBeFalse(); @@ -345,7 +370,10 @@ If timeout expired a process will be killed. // Adds the namespace "HostApi" to use Command Line API using HostApi; -int? exitCode = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120").Run(default, TimeSpan.FromMilliseconds(1)).ExitCode; +int? exitCode = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120") + .Run(default, TimeSpan.FromMilliseconds(1)) + .EnsureSuccess() + .ExitCode; exitCode.HasValue.ShouldBeFalse(); ``` @@ -361,18 +389,26 @@ exitCode.HasValue.ShouldBeFalse(); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("xunit", "-n", "MyLib", "--force").Build(); -result.ExitCode.ShouldBe(0); +new DotNetNew("xunit", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); // Builds the library project, running a command like: "dotnet build" from the directory "MyLib" -result = new DotNetBuild().WithWorkingDirectory("MyLib").Build(); +var result = new DotNetBuild() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(); result.ExitCode.ShouldBe(0); // Runs tests in docker -result = new DotNetTest().WithWorkingDirectory("MyLib").Build(); +result = new DotNetTest() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); result.Summary.Tests.ShouldBe(1); result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1); @@ -389,15 +425,25 @@ result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); +var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Builds the library project, running a command like: "dotnet build" from the directory "MyLib" -result = new DotNetBuild().WithWorkingDirectory("MyLib").Build(); +result = new DotNetBuild() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Clean the project, running a command like: "dotnet clean" from the directory "MyLib" -result = new DotNetClean().WithWorkingDirectory("MyLib").Build(); +result = new DotNetClean() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); @@ -415,7 +461,7 @@ using HostApi; // Gets the dotnet version, running a command like: "dotnet --version" NuGetVersion? version = default; -var exitCode = new DotNetCustom("--version") +new DotNetCustom("--version") .Run(message => NuGetVersion.TryParse(message.Line, out version)) .EnsureSuccess(); @@ -433,13 +479,18 @@ version.ShouldNotBeNull(); using HostApi; // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" -var result = new DotNetNew("mstest", "-n", "MyTests", "--force").Build(); +var result = new DotNetNew("mstest", "-n", "MyTests", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs tests via a command like: "dotnet msbuild /t:VSTest" from the directory "MyTests" result = new MSBuild() .WithTarget("VSTest") - .WithWorkingDirectory("MyTests").Build(); + .WithWorkingDirectory("MyTests") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); @@ -458,14 +509,18 @@ result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); +var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Creates a NuGet package of version 1.2.3 for the project, running a command like: "dotnet pack /p:version=1.2.3" from the directory "MyLib" result = new DotNetPack() .WithWorkingDirectory("MyLib") .AddProps(("version", "1.2.3")) - .Build(); + .Build() + .EnsureSuccess(); result.ExitCode.ShouldBe(0); ``` @@ -481,11 +536,19 @@ result.ExitCode.ShouldBe(0); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("classlib", "-n", "MyLib", "--force", "-f", "net8.0").Build(); +var result = new DotNetNew("classlib", "-n", "MyLib", "--force", "-f", "net8.0") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Publish the project, running a command like: "dotnet publish --framework net6.0" from the directory "MyLib" -result = new DotNetPublish().WithWorkingDirectory("MyLib").WithFramework("net8.0").Build(); +result = new DotNetPublish() + .WithWorkingDirectory("MyLib") + .WithFramework("net8.0") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); ``` @@ -500,11 +563,18 @@ result.ExitCode.ShouldBe(0); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); +var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Restore the project, running a command like: "dotnet restore" from the directory "MyLib" -result = new DotNetRestore().WithWorkingDirectory("MyLib").Build(); +result = new DotNetRestore() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); ``` @@ -519,12 +589,18 @@ result.ExitCode.ShouldBe(0); using HostApi; // Creates a new console project, running a command like: "dotnet new console -n MyApp --force" -var result = new DotNetNew("console", "-n", "MyApp", "--force").Build(); +var result = new DotNetNew("console", "-n", "MyApp", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs the console project using a command like: "dotnet run" from the directory "MyApp" var stdOut = new List(); -result = new DotNetRun().WithWorkingDirectory("MyApp").Build(message => stdOut.Add(message.Text)); +result = new DotNetRun().WithWorkingDirectory("MyApp") + .Build(message => stdOut.Add(message.Text)) + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Checks StdOut @@ -542,11 +618,17 @@ stdOut.ShouldBe(new[] {"Hello, World!"}); using HostApi; // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" -var result = new DotNetNew("mstest", "-n", "MyTests", "--force").Build(); +var result = new DotNetNew("mstest", "-n", "MyTests", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs tests via a command like: "dotnet test" from the directory "MyTests" -result = new DotNetTest().WithWorkingDirectory("MyTests").Build(); +result = new DotNetTest() + .WithWorkingDirectory("MyTests") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); @@ -566,18 +648,23 @@ using HostApi; // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" new DotNetNew("mstest", "-n", "MyTests", "--force") - .Run().EnsureSuccess(); + .Run() + .EnsureSuccess(); // Creates the tool manifest and installs the dotCover tool locally // It is better to run the following 2 commands manually // and commit these changes to a source control -new DotNetNew("tool-manifest").Run().EnsureSuccess(); +new DotNetNew("tool-manifest") + .Run() + .EnsureSuccess(); new DotNetCustom("tool", "install", "--local", "JetBrains.dotCover.GlobalTool") - .Run().EnsureSuccess(); + .Run() + .EnsureSuccess(); // Creates a test command -var test = new DotNetTest().WithProject("MyTests"); +var test = new DotNetTest() + .WithProject("MyTests"); var dotCoverSnapshot = Path.Combine("MyTests", "dotCover.dcvr"); var dotCoverReport = Path.Combine("MyTests", "dotCover.html"); @@ -593,7 +680,9 @@ var testUnderDotCover = test.Customize(cmd => + "--dcAttributeFilters=System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage"); // Runs tests under dotCover via a command like: "dotnet dotcover test ..." -var result = testUnderDotCover.Build(); +var result = testUnderDotCover + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); @@ -621,10 +710,16 @@ var projectDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()[..4] Directory.CreateDirectory(projectDir); // Creates a local tool manifest -new DotNetNew("tool-manifest").WithWorkingDirectory(projectDir).Run().EnsureSuccess(); +new DotNetNew("tool-manifest") + .WithWorkingDirectory(projectDir) + .Run() + .EnsureSuccess(); // Restore local tools -new DotNetToolRestore().WithWorkingDirectory(projectDir).Run().EnsureSuccess(); +new DotNetToolRestore() + .WithWorkingDirectory(projectDir) + .Run() + .EnsureSuccess(); ``` @@ -638,18 +733,28 @@ new DotNetToolRestore().WithWorkingDirectory(projectDir).Run().EnsureSuccess(); using HostApi; // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" -var result = new DotNetNew("mstest", "-n", "MyTests", "--force").Build(); +var result = new DotNetNew("mstest", "-n", "MyTests", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Builds the test project, running a command like: "dotnet build -c Release" from the directory "MyTests" -result = new DotNetBuild().WithWorkingDirectory("MyTests").WithConfiguration("Release").WithOutput("MyOutput").Build(); +result = new DotNetBuild() + .WithWorkingDirectory("MyTests") + .WithConfiguration("Release") + .WithOutput("MyOutput") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs tests via a command like: "dotnet vstest" from the directory "MyTests" result = new VSTest() .AddTestFileNames(Path.Combine("MyOutput", "MyTests.dll")) .WithWorkingDirectory("MyTests") - .Build(); + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); @@ -668,7 +773,10 @@ result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); +var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Builds the library project, running a command like: "dotnet msbuild /t:Build -restore /p:configuration=Release -verbosity=detailed" from the directory "MyLib" @@ -678,7 +786,8 @@ result = new MSBuild() .WithRestore(true) .AddProps(("configuration", "Release")) .WithVerbosity(DotNetVerbosity.Detailed) - .Build(); + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(); @@ -696,7 +805,9 @@ result.ExitCode.ShouldBe(0); using HostApi; // Shuts down all build servers that are started from dotnet. -new DotNetBuildServerShutdown().Run().EnsureSuccess(); +new DotNetBuildServerShutdown() + .Run() + .EnsureSuccess(); ``` @@ -709,7 +820,8 @@ new DotNetBuildServerShutdown().Run().EnsureSuccess(); // Adds the namespace "HostApi" to use INuGet using HostApi; -IEnumerable packages = GetService().Restore(new NuGetRestoreSettings("IoC.Container").WithVersionRange(VersionRange.All)); +IEnumerable packages = GetService() + .Restore(new NuGetRestoreSettings("IoC.Container").WithVersionRange(VersionRange.All)); ``` @@ -757,12 +869,14 @@ var dockerRun = new DockerRun() // Creates a new library project in a docker container dockerRun .WithCommandLine(new DotNetCustom("new", "classlib", "-n", "MyLib", "--force")) - .Run().EnsureSuccess(); + .Run() + .EnsureSuccess(); // Builds the library project in a docker container var result = dockerRun .WithCommandLine(new DotNetBuild().WithProject("MyLib/MyLib.csproj")) - .Build(); + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(); diff --git a/CSharpInteractive.Tests/UsageScenarios/BaseScenario.cs b/CSharpInteractive.Tests/UsageScenarios/BaseScenario.cs index e935f92a..85435c18 100644 --- a/CSharpInteractive.Tests/UsageScenarios/BaseScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/BaseScenario.cs @@ -15,6 +15,7 @@ public class BaseScenario : IHost, IDisposable public BaseScenario() { + Composition.Shared.Root.TestEnvironment.ExitCode = default; _tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()[..4]); Directory.CreateDirectory(_tempDir); _prevCurDir = Environment.CurrentDirectory; @@ -81,5 +82,6 @@ void IDisposable.Dispose() } Environment.CurrentDirectory = _prevCurDir; + Composition.Shared.Root.TestEnvironment.ExitCode.ShouldBe(0); } } \ No newline at end of file diff --git a/CSharpInteractive.Tests/UsageScenarios/CommandLineAsyncCancellation.cs b/CSharpInteractive.Tests/UsageScenarios/CommandLineAsyncCancellation.cs index 4a653666..b831f942 100644 --- a/CSharpInteractive.Tests/UsageScenarios/CommandLineAsyncCancellation.cs +++ b/CSharpInteractive.Tests/UsageScenarios/CommandLineAsyncCancellation.cs @@ -19,13 +19,14 @@ public void Run() // $tag=10 Command Line API // $priority=06 // $description=Cancellation of asynchronous run - // $header=The cancellation will kill a related process. + // $header=Cancellation will destroy the process and its child processes. // { // Adds the namespace "HostApi" to use Command Line API // ## using HostApi; var cancellationTokenSource = new CancellationTokenSource(); - var task = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120").RunAsync(default, cancellationTokenSource.Token); + var task = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120") + .RunAsync(default, cancellationTokenSource.Token); cancellationTokenSource.CancelAfter(TimeSpan.FromMilliseconds(100)); task.IsCompleted.ShouldBeFalse(); diff --git a/CSharpInteractive.Tests/UsageScenarios/CommandLineAsyncScenario.cs b/CSharpInteractive.Tests/UsageScenarios/CommandLineAsyncScenario.cs index 1f03c60a..254b9a4f 100644 --- a/CSharpInteractive.Tests/UsageScenarios/CommandLineAsyncScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/CommandLineAsyncScenario.cs @@ -24,12 +24,16 @@ public async Task Run() // Adds the namespace "HostApi" to use Command Line API // ## using HostApi; - var task = await GetService().RunAsync(new CommandLine("cmd", "/C", "DIR")); + await GetService() + .RunAsync(new CommandLine("cmd", "/C", "DIR")) + .EnsureSuccess(); // or the same thing using the extension method - task = await new CommandLine("cmd", "/c", "DIR").RunAsync(); + var result = await new CommandLine("cmd", "/c", "DIR") + .RunAsync() + .EnsureSuccess(); // } - - task.ExitCode.HasValue.ShouldBeTrue(); + + result.ExitCode.HasValue.ShouldBeTrue(); } } \ No newline at end of file diff --git a/CSharpInteractive.Tests/UsageScenarios/CommandLineInParallelScenario.cs b/CSharpInteractive.Tests/UsageScenarios/CommandLineInParallelScenario.cs index 2c2370bf..15f77f9a 100644 --- a/CSharpInteractive.Tests/UsageScenarios/CommandLineInParallelScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/CommandLineInParallelScenario.cs @@ -11,7 +11,7 @@ namespace CSharpInteractive.Tests.UsageScenarios; public class CommandLineInParallelScenario : BaseScenario { [SkippableFact] - public void Run() + public async Task Run() { Skip.IfNot(Environment.OSVersion.Platform == PlatformID.Win32NT); Skip.IfNot(string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TEAMCITY_VERSION"))); @@ -24,9 +24,15 @@ public void Run() // Adds the namespace "HostApi" to use Command Line API // ## using HostApi; - var task = new CommandLine("cmd", "/c", "DIR").RunAsync(); - var result = new CommandLine("cmd", "/c", "SET").Run(); - task.Wait(); + var task = new CommandLine("cmd", "/c", "DIR") + .RunAsync() + .EnsureSuccess(); + + var result = new CommandLine("cmd", "/c", "SET") + .Run() + .EnsureSuccess(); + + await task; // } task.Result.ExitCode.HasValue.ShouldBeTrue(); diff --git a/CSharpInteractive.Tests/UsageScenarios/CommandLineOutputScenario.cs b/CSharpInteractive.Tests/UsageScenarios/CommandLineOutputScenario.cs index f119f797..97e67bad 100644 --- a/CSharpInteractive.Tests/UsageScenarios/CommandLineOutputScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/CommandLineOutputScenario.cs @@ -24,13 +24,14 @@ public void Run() // ## using HostApi; var lines = new List(); - int? exitCode = new CommandLine("cmd", "/c", "SET") + var result = new CommandLine("cmd", "/c", "SET") .AddVars(("MyEnv", "MyVal")) - .Run(output => lines.Add(output.Line)).ExitCode; + .Run(output => lines.Add(output.Line)) + .EnsureSuccess(); lines.ShouldContain("MyEnv=MyVal"); // } - exitCode.HasValue.ShouldBeTrue(); + result.ExitCode.HasValue.ShouldBeTrue(); } } \ No newline at end of file diff --git a/CSharpInteractive.Tests/UsageScenarios/CommandLineScenario.cs b/CSharpInteractive.Tests/UsageScenarios/CommandLineScenario.cs index 1c7360f4..e2ffd7f6 100644 --- a/CSharpInteractive.Tests/UsageScenarios/CommandLineScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/CommandLineScenario.cs @@ -23,10 +23,14 @@ public void Run() // Adds the namespace "HostApi" to use Command Line API // ## using HostApi; - GetService().Run(new CommandLine("cmd", "/c", "DIR")).EnsureSuccess(); + GetService() + .Run(new CommandLine("cmd", "/c", "DIR")) + .EnsureSuccess(); // or the same thing using the extension method - new CommandLine("cmd", "/c", "DIR").Run().EnsureSuccess(); + new CommandLine("cmd", "/c", "DIR") + .Run() + .EnsureSuccess(); // using operator '+' var cmd = new CommandLine("cmd") + "/c" + "DIR"; diff --git a/CSharpInteractive.Tests/UsageScenarios/CommandLineWithTimeoutScenario.cs b/CSharpInteractive.Tests/UsageScenarios/CommandLineWithTimeoutScenario.cs index a0fc702c..b30317a1 100644 --- a/CSharpInteractive.Tests/UsageScenarios/CommandLineWithTimeoutScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/CommandLineWithTimeoutScenario.cs @@ -24,7 +24,10 @@ public void Run() // Adds the namespace "HostApi" to use Command Line API // ## using HostApi; - int? exitCode = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120").Run(default, TimeSpan.FromMilliseconds(1)).ExitCode; + int? exitCode = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120") + .Run(default, TimeSpan.FromMilliseconds(1)) + .EnsureSuccess() + .ExitCode; exitCode.HasValue.ShouldBeFalse(); // } diff --git a/CSharpInteractive.Tests/UsageScenarios/CommandLinesScenario.cs b/CSharpInteractive.Tests/UsageScenarios/CommandLinesScenario.cs index 820886c5..234e8e6a 100644 --- a/CSharpInteractive.Tests/UsageScenarios/CommandLinesScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/CommandLinesScenario.cs @@ -26,10 +26,10 @@ public void Run() // ## using HostApi; // Creates and run a simple command line - "whoami".AsCommandLine().Run(); + "whoami".AsCommandLine().Run().EnsureSuccess(); // Creates and run a simple command line - new CommandLine("whoami").Run(); + new CommandLine("whoami").Run().EnsureSuccess(); // Creates and run a command line with arguments new CommandLine("cmd", "/c", "echo", "Hello").Run(); @@ -37,13 +37,20 @@ public void Run() // Same as previous statement new CommandLine("cmd", "/c") .AddArgs("echo", "Hello") - .Run(); + .Run() + .EnsureSuccess(); - (new CommandLine("cmd") + "/c" + "echo" + "Hello").Run(); + (new CommandLine("cmd") + "/c" + "echo" + "Hello") + .Run() + .EnsureSuccess(); - "cmd".AsCommandLine("/c", "echo", "Hello").Run(); + "cmd".AsCommandLine("/c", "echo", "Hello") + .Run() + .EnsureSuccess(); - ("cmd".AsCommandLine() + "/c" + "echo" + "Hello").Run(); + ("cmd".AsCommandLine() + "/c" + "echo" + "Hello") + .Run() + .EnsureSuccess(); // Just builds a command line with multiple environment variables var cmd = new CommandLine("cmd", "/c", "echo", "Hello") diff --git a/CSharpInteractive.Tests/UsageScenarios/DockerDotNetBuildScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DockerDotNetBuildScenario.cs index 0ee18bc1..1f5836f4 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DockerDotNetBuildScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DockerDotNetBuildScenario.cs @@ -39,12 +39,14 @@ public void Run() // Creates a new library project in a docker container dockerRun .WithCommandLine(new DotNetCustom("new", "classlib", "-n", "MyLib", "--force")) - .Run().EnsureSuccess(); + .Run() + .EnsureSuccess(); // Builds the library project in a docker container var result = dockerRun .WithCommandLine(new DotNetBuild().WithProject("MyLib/MyLib.csproj")) - .Build(); + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(); diff --git a/CSharpInteractive.Tests/UsageScenarios/DockerRunScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DockerRunScenario.cs index b0f0d41e..d5a59b02 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DockerRunScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DockerRunScenario.cs @@ -30,5 +30,7 @@ public void Run() .Run() .EnsureSuccess(); // } + + result.ExitCode.ShouldBe(0); } } \ No newline at end of file diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetBuildScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetBuildScenario.cs index f77d5401..7626865c 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetBuildScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetBuildScenario.cs @@ -22,18 +22,26 @@ public void Run() // ## using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" - var result = new DotNetNew("xunit", "-n", "MyLib", "--force").Build(); - result.ExitCode.ShouldBe(0); + new DotNetNew("xunit", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); // Builds the library project, running a command like: "dotnet build" from the directory "MyLib" - result = new DotNetBuild().WithWorkingDirectory("MyLib").Build(); + var result = new DotNetBuild() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(); result.ExitCode.ShouldBe(0); // Runs tests in docker - result = new DotNetTest().WithWorkingDirectory("MyLib").Build(); + result = new DotNetTest() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); result.Summary.Tests.ShouldBe(1); result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1); diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetBuildServerShutdownScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetBuildServerShutdownScenario.cs index e8b8ba68..3dd2a5ca 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetBuildServerShutdownScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetBuildServerShutdownScenario.cs @@ -21,7 +21,9 @@ public void Run() // ## using HostApi; // Shuts down all build servers that are started from dotnet. - new DotNetBuildServerShutdown().Run().EnsureSuccess(); + new DotNetBuildServerShutdown() + .Run() + .EnsureSuccess(); // } } } \ No newline at end of file diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetCleanScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetCleanScenario.cs index 7079fc0a..152d08a5 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetCleanScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetCleanScenario.cs @@ -22,15 +22,25 @@ public void Run() // ## using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" - var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); + var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Builds the library project, running a command like: "dotnet build" from the directory "MyLib" - result = new DotNetBuild().WithWorkingDirectory("MyLib").Build(); + result = new DotNetBuild() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Clean the project, running a command like: "dotnet clean" from the directory "MyLib" - result = new DotNetClean().WithWorkingDirectory("MyLib").Build(); + result = new DotNetClean() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetCustomScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetCustomScenario.cs index 083e41e6..1d4873ac 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetCustomScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetCustomScenario.cs @@ -25,7 +25,7 @@ public void Run() // Gets the dotnet version, running a command like: "dotnet --version" NuGetVersion? version = default; - var exitCode = new DotNetCustom("--version") + new DotNetCustom("--version") .Run(message => NuGetVersion.TryParse(message.Line, out version)) .EnsureSuccess(); diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetMSBuildVSTestScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetMSBuildVSTestScenario.cs index 14413c0e..992a9e7e 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetMSBuildVSTestScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetMSBuildVSTestScenario.cs @@ -22,13 +22,18 @@ public void Run() // ## using HostApi; // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" - var result = new DotNetNew("mstest", "-n", "MyTests", "--force").Build(); + var result = new DotNetNew("mstest", "-n", "MyTests", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs tests via a command like: "dotnet msbuild /t:VSTest" from the directory "MyTests" result = new MSBuild() .WithTarget("VSTest") - .WithWorkingDirectory("MyTests").Build(); + .WithWorkingDirectory("MyTests") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetPackScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetPackScenario.cs index 942b52ec..a37e7c53 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetPackScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetPackScenario.cs @@ -22,14 +22,18 @@ public void Run() // ## using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" - var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); + var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Creates a NuGet package of version 1.2.3 for the project, running a command like: "dotnet pack /p:version=1.2.3" from the directory "MyLib" result = new DotNetPack() .WithWorkingDirectory("MyLib") .AddProps(("version", "1.2.3")) - .Build(); + .Build() + .EnsureSuccess(); result.ExitCode.ShouldBe(0); // } diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetPublishScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetPublishScenario.cs index 3e8dbf86..6f196fd7 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetPublishScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetPublishScenario.cs @@ -22,11 +22,19 @@ public void Run() // ## using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" - var result = new DotNetNew("classlib", "-n", "MyLib", "--force", "-f", "net8.0").Build(); + var result = new DotNetNew("classlib", "-n", "MyLib", "--force", "-f", "net8.0") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Publish the project, running a command like: "dotnet publish --framework net6.0" from the directory "MyLib" - result = new DotNetPublish().WithWorkingDirectory("MyLib").WithFramework("net8.0").Build(); + result = new DotNetPublish() + .WithWorkingDirectory("MyLib") + .WithFramework("net8.0") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // } } diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetRestoreScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetRestoreScenario.cs index 4b6d1a5c..008d5245 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetRestoreScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetRestoreScenario.cs @@ -22,11 +22,18 @@ public void Run() // ## using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" - var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); + var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Restore the project, running a command like: "dotnet restore" from the directory "MyLib" - result = new DotNetRestore().WithWorkingDirectory("MyLib").Build(); + result = new DotNetRestore() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // } } diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetRunScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetRunScenario.cs index 110e4962..639937bd 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetRunScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetRunScenario.cs @@ -23,12 +23,18 @@ public void Run() // ## using HostApi; // Creates a new console project, running a command like: "dotnet new console -n MyApp --force" - var result = new DotNetNew("console", "-n", "MyApp", "--force").Build(); + var result = new DotNetNew("console", "-n", "MyApp", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs the console project using a command like: "dotnet run" from the directory "MyApp" var stdOut = new List(); - result = new DotNetRun().WithWorkingDirectory("MyApp").Build(message => stdOut.Add(message.Text)); + result = new DotNetRun().WithWorkingDirectory("MyApp") + .Build(message => stdOut.Add(message.Text)) + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Checks StdOut diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetTestScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetTestScenario.cs index 74a9d894..baf93b1e 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetTestScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetTestScenario.cs @@ -21,11 +21,17 @@ public void Run() // ## using HostApi; // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" - var result = new DotNetNew("mstest", "-n", "MyTests", "--force").Build(); + var result = new DotNetNew("mstest", "-n", "MyTests", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs tests via a command like: "dotnet test" from the directory "MyTests" - result = new DotNetTest().WithWorkingDirectory("MyTests").Build(); + result = new DotNetTest() + .WithWorkingDirectory("MyTests") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetTestWithDotCoverScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetTestWithDotCoverScenario.cs index 6e978bef..304b095a 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetTestWithDotCoverScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetTestWithDotCoverScenario.cs @@ -22,18 +22,23 @@ public void Run() // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" new DotNetNew("mstest", "-n", "MyTests", "--force") - .Run().EnsureSuccess(); + .Run() + .EnsureSuccess(); // Creates the tool manifest and installs the dotCover tool locally // It is better to run the following 2 commands manually // and commit these changes to a source control - new DotNetNew("tool-manifest").Run().EnsureSuccess(); + new DotNetNew("tool-manifest") + .Run() + .EnsureSuccess(); new DotNetCustom("tool", "install", "--local", "JetBrains.dotCover.GlobalTool") - .Run().EnsureSuccess(); + .Run() + .EnsureSuccess(); // Creates a test command - var test = new DotNetTest().WithProject("MyTests"); + var test = new DotNetTest() + .WithProject("MyTests"); var dotCoverSnapshot = Path.Combine("MyTests", "dotCover.dcvr"); var dotCoverReport = Path.Combine("MyTests", "dotCover.html"); @@ -49,7 +54,9 @@ public void Run() + "--dcAttributeFilters=System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage"); // Runs tests under dotCover via a command like: "dotnet dotcover test ..." - var result = testUnderDotCover.Build(); + var result = testUnderDotCover + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetToolRestoreScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetToolRestoreScenario.cs index 1c475d1e..1eb2aa53 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetToolRestoreScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetToolRestoreScenario.cs @@ -25,10 +25,16 @@ public void Run() Directory.CreateDirectory(projectDir); // Creates a local tool manifest - new DotNetNew("tool-manifest").WithWorkingDirectory(projectDir).Run().EnsureSuccess(); + new DotNetNew("tool-manifest") + .WithWorkingDirectory(projectDir) + .Run() + .EnsureSuccess(); // Restore local tools - new DotNetToolRestore().WithWorkingDirectory(projectDir).Run().EnsureSuccess(); + new DotNetToolRestore() + .WithWorkingDirectory(projectDir) + .Run() + .EnsureSuccess(); // } Directory.Delete(projectDir, true); diff --git a/CSharpInteractive.Tests/UsageScenarios/DotNetVSTestScenario.cs b/CSharpInteractive.Tests/UsageScenarios/DotNetVSTestScenario.cs index 5b177fe0..ecd086de 100644 --- a/CSharpInteractive.Tests/UsageScenarios/DotNetVSTestScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/DotNetVSTestScenario.cs @@ -22,18 +22,28 @@ public void Run() // ## using HostApi; // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" - var result = new DotNetNew("mstest", "-n", "MyTests", "--force").Build(); + var result = new DotNetNew("mstest", "-n", "MyTests", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Builds the test project, running a command like: "dotnet build -c Release" from the directory "MyTests" - result = new DotNetBuild().WithWorkingDirectory("MyTests").WithConfiguration("Release").WithOutput("MyOutput").Build(); + result = new DotNetBuild() + .WithWorkingDirectory("MyTests") + .WithConfiguration("Release") + .WithOutput("MyOutput") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs tests via a command like: "dotnet vstest" from the directory "MyTests" result = new VSTest() .AddTestFileNames(Path.Combine("MyOutput", "MyTests.dll")) .WithWorkingDirectory("MyTests") - .Build(); + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); @@ -46,11 +56,20 @@ public void Run() public void RunAsCommandLine() { // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" - var result = new DotNetNew("mstest", "-n", "MyTests", "--force").Build(); + var result = new DotNetNew("mstest", "-n", "MyTests", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Builds the test project, running a command like: "dotnet build -c Release" from the directory "MyTests" - result = new DotNetBuild().WithWorkingDirectory("MyTests").WithConfiguration("Release").WithOutput("MyOutput").Build(); + result = new DotNetBuild() + .WithWorkingDirectory("MyTests") + .WithConfiguration("Release") + .WithOutput("MyOutput") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs tests via a command like: "dotnet vstest" from the directory "MyTests" @@ -59,6 +78,7 @@ public void RunAsCommandLine() .AddTestFileNames(Path.Combine("MyOutput", "MyTests.dll")) .WithWorkingDirectory("MyTests") .Run(i => lines.Add(i.Line)) + .EnsureSuccess() .ExitCode; lines.Count(i => i.Contains("##teamcity[")).ShouldBe(0); diff --git a/CSharpInteractive.Tests/UsageScenarios/MSBuildScenario.cs b/CSharpInteractive.Tests/UsageScenarios/MSBuildScenario.cs index bb495716..5e27145a 100644 --- a/CSharpInteractive.Tests/UsageScenarios/MSBuildScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/MSBuildScenario.cs @@ -23,7 +23,10 @@ public void Run() // ## using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" - var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); + var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Builds the library project, running a command like: "dotnet msbuild /t:Build -restore /p:configuration=Release -verbosity=detailed" from the directory "MyLib" @@ -33,7 +36,8 @@ public void Run() .WithRestore(true) .AddProps(("configuration", "Release")) .WithVerbosity(DotNetVerbosity.Detailed) - .Build(); + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(); diff --git a/CSharpInteractive.Tests/UsageScenarios/NuGetRestoreScenario.cs b/CSharpInteractive.Tests/UsageScenarios/NuGetRestoreScenario.cs index d3810260..0b788645 100644 --- a/CSharpInteractive.Tests/UsageScenarios/NuGetRestoreScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/NuGetRestoreScenario.cs @@ -20,7 +20,8 @@ public void Run() // Adds the namespace "HostApi" to use INuGet // ## using HostApi; - IEnumerable packages = GetService().Restore(new NuGetRestoreSettings("IoC.Container").WithVersionRange(VersionRange.All)); + IEnumerable packages = GetService() + .Restore(new NuGetRestoreSettings("IoC.Container").WithVersionRange(VersionRange.All)); // } packages.ShouldNotBeEmpty(); diff --git a/CSharpInteractive.Tests/UsageScenarios/ServiceCollectionScenario.cs b/CSharpInteractive.Tests/UsageScenarios/ServiceCollectionScenario.cs index 7cf7f2a8..6a75fa7e 100644 --- a/CSharpInteractive.Tests/UsageScenarios/ServiceCollectionScenario.cs +++ b/CSharpInteractive.Tests/UsageScenarios/ServiceCollectionScenario.cs @@ -27,8 +27,10 @@ public void Run() private class MyTask(ICommandLineRunner runner) { - public int? Run() => - runner.Run(new CommandLine("whoami")).ExitCode; + public int? Run() => runner + .Run(new CommandLine("whoami")) + .EnsureSuccess() + .ExitCode; } // } diff --git a/CSharpInteractive/Composition.cs b/CSharpInteractive/Composition.cs index c402717f..a4e49ae3 100644 --- a/CSharpInteractive/Composition.cs +++ b/CSharpInteractive/Composition.cs @@ -86,7 +86,7 @@ private void Setup() }) .Bind().To() .Bind().To() - .Bind().Bind(Tag.Type).To() + .Bind().Bind(Tag.Type).To() .Bind().Bind(Tag.Type).To() .Bind().To() .Bind().To() diff --git a/CSharpInteractive/Core/Environment.cs b/CSharpInteractive/Core/Environment.cs index 332f9716..4024545c 100644 --- a/CSharpInteractive/Core/Environment.cs +++ b/CSharpInteractive/Core/Environment.cs @@ -7,6 +7,7 @@ namespace CSharpInteractive.Core; internal class Environment: IEnvironment, + ITestEnvironment, ITraceSource, IScriptContext, IErrorContext @@ -14,6 +15,10 @@ internal class Environment: private static readonly OSPlatform UnknownOSPlatform = OSPlatform.Create("Unknown"); private readonly LinkedList _sources = []; + public bool IsTesting { get; set; } + + public int? ExitCode { get; set; } + public OSPlatform OperatingSystemPlatform { get @@ -72,6 +77,17 @@ public string GetPath(SpecialFolder specialFolder) }; } + public void Exit(int exitCode) + { + ExitCode = exitCode; + if (IsTesting) + { + return; + } + + System.Environment.Exit(exitCode); + } + public IEnumerable Trace { get diff --git a/CSharpInteractive/Core/ExitTracker.cs b/CSharpInteractive/Core/ExitTracker.cs index 7c3f0012..989c0455 100644 --- a/CSharpInteractive/Core/ExitTracker.cs +++ b/CSharpInteractive/Core/ExitTracker.cs @@ -8,6 +8,7 @@ namespace CSharpInteractive.Core; internal class ExitTracker( ISettings settings, IPresenter summaryPresenter, + IEnvironment environment, CancellationTokenSource cancellationTokenSource) : IExitTracker { @@ -36,7 +37,7 @@ public void Exit(int exitCode) Host.Finish(); #endif ClearEvents(typeof(AppContext)); - System.Environment.Exit(exitCode); + environment.Exit(exitCode); } private static void ClearEvents(Type type) diff --git a/CSharpInteractive/Core/IEnvironment.cs b/CSharpInteractive/Core/IEnvironment.cs index fae95169..0eb5194b 100644 --- a/CSharpInteractive/Core/IEnvironment.cs +++ b/CSharpInteractive/Core/IEnvironment.cs @@ -12,4 +12,6 @@ internal interface IEnvironment IEnumerable GetCommandLineArgs(); string GetPath(SpecialFolder specialFolder); + + void Exit(int exitCode); } \ No newline at end of file diff --git a/CSharpInteractive/Core/ITestEnvironment.cs b/CSharpInteractive/Core/ITestEnvironment.cs new file mode 100644 index 00000000..c78dc7d5 --- /dev/null +++ b/CSharpInteractive/Core/ITestEnvironment.cs @@ -0,0 +1,8 @@ +namespace CSharpInteractive.Core; + +internal interface ITestEnvironment +{ + public bool IsTesting { get; set; } + + public int? ExitCode { get; set; } +} \ No newline at end of file diff --git a/CSharpInteractive/Root.cs b/CSharpInteractive/Root.cs index 4ee26a78..9014e8cd 100644 --- a/CSharpInteractive/Root.cs +++ b/CSharpInteractive/Root.cs @@ -15,6 +15,7 @@ internal record Root( Program Program, #endif IHost Host, + ITestEnvironment TestEnvironment, IStatisticsRegistry StatisticsRegistry, ILog Log, IInfo Info, diff --git a/README.md b/README.md index 4d73e334..029a6854 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![](docs/csharp_cat.png) -Example of usage: +Key features by example: ```c# // Output API @@ -122,9 +122,7 @@ finally { tempDir.Delete(); } class MyTool(INuGet nuGet); ``` -## Usage - -### Script runner tool +## Script runner tool It can be installed as a command-line tool on Windows, Linux, or macOS. The dotnet tool requires [.NET 6+ runtime](https://dotnet.microsoft.com/en-us/download). @@ -174,23 +172,28 @@ dotnet csi [options] [--] [script] [script arguments] Executes a script if specified, otherwise launches an interactive REPL (Read Eval Print Loop). -Supported arguments: +`--` - 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 | |:------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------| -| 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. | | -| -- | Indicates that the remaining arguments should not be treated as options. | | | --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 | Define a key-value pair(s) for the script properties called _Props_, which is accessible in scripts. | `-p`, `/property`, `/p` | | --property: | Define a key-value pair(s) in MSBuild style for the script properties called _Props_, which is accessible in scripts. | `-p:`, `/property:`, `/p:`, `--property:key1=val1;key2=val2` | -| @file | Read the response file for more options. | | -```using HostApi;``` directive in a script allows you to use host API types without specifying the fully qualified namespace of these types. +> [!IMPORTANT] +> `using HostApi;` directive in a script allows you to use host API types without specifying the fully qualified namespace of these types. -### .NET project +## .NET project Install the C# script template [CSharpInteractive.Templates](https://www.nuget.org/packages/CSharpInteractive.Templates) @@ -198,7 +201,7 @@ Install the C# script template [CSharpInteractive.Templates](https://www.nuget.o dotnet new install CSharpInteractive.Templates ``` -Create a console project "Build" containing a script from the template *__build__* +Create a console project *__Build__* containing a script from the template *__build__* ```shell dotnet new build -o ./Build @@ -341,8 +344,10 @@ public void Run() private class MyTask(ICommandLineRunner runner) { - public int? Run() => - runner.Run(new CommandLine("whoami")).ExitCode; + public int? Run() => runner + .Run(new CommandLine("whoami")) + .EnsureSuccess() + .ExitCode; } ``` @@ -428,10 +433,10 @@ Trace("Some trace info"); using HostApi; // Creates and run a simple command line -"whoami".AsCommandLine().Run(); +"whoami".AsCommandLine().Run().EnsureSuccess(); // Creates and run a simple command line -new CommandLine("whoami").Run(); +new CommandLine("whoami").Run().EnsureSuccess(); // Creates and run a command line with arguments new CommandLine("cmd", "/c", "echo", "Hello").Run(); @@ -439,13 +444,20 @@ new CommandLine("cmd", "/c", "echo", "Hello").Run(); // Same as previous statement new CommandLine("cmd", "/c") .AddArgs("echo", "Hello") - .Run(); + .Run() + .EnsureSuccess(); -(new CommandLine("cmd") + "/c" + "echo" + "Hello").Run(); +(new CommandLine("cmd") + "/c" + "echo" + "Hello") + .Run() + .EnsureSuccess(); -"cmd".AsCommandLine("/c", "echo", "Hello").Run(); +"cmd".AsCommandLine("/c", "echo", "Hello") + .Run() + .EnsureSuccess(); -("cmd".AsCommandLine() + "/c" + "echo" + "Hello").Run(); +("cmd".AsCommandLine() + "/c" + "echo" + "Hello") + .Run() + .EnsureSuccess(); // Just builds a command line with multiple environment variables var cmd = new CommandLine("cmd", "/c", "echo", "Hello") @@ -473,10 +485,14 @@ cmd = new CommandLine("cmd", "/c", "echo", "Hello") // Adds the namespace "HostApi" to use Command Line API using HostApi; -GetService().Run(new CommandLine("cmd", "/c", "DIR")).EnsureSuccess(); +GetService() + .Run(new CommandLine("cmd", "/c", "DIR")) + .EnsureSuccess(); // or the same thing using the extension method -new CommandLine("cmd", "/c", "DIR").Run().EnsureSuccess(); +new CommandLine("cmd", "/c", "DIR") + .Run() + .EnsureSuccess(); // using operator '+' var cmd = new CommandLine("cmd") + "/c" + "DIR"; @@ -497,10 +513,14 @@ cmd.Run().EnsureSuccess(); // Adds the namespace "HostApi" to use Command Line API using HostApi; -var task = await GetService().RunAsync(new CommandLine("cmd", "/C", "DIR")); +await GetService() + .RunAsync(new CommandLine("cmd", "/C", "DIR")) + .EnsureSuccess(); // or the same thing using the extension method -task = await new CommandLine("cmd", "/c", "DIR").RunAsync(); +var result = await new CommandLine("cmd", "/c", "DIR") + .RunAsync() + .EnsureSuccess(); ``` @@ -514,9 +534,10 @@ task = await new CommandLine("cmd", "/c", "DIR").RunAsync(); using HostApi; var lines = new List(); -int? exitCode = new CommandLine("cmd", "/c", "SET") +var result = new CommandLine("cmd", "/c", "SET") .AddVars(("MyEnv", "MyVal")) - .Run(output => lines.Add(output.Line)).ExitCode; + .Run(output => lines.Add(output.Line)) + .EnsureSuccess(); lines.ShouldContain("MyEnv=MyVal"); ``` @@ -531,23 +552,30 @@ lines.ShouldContain("MyEnv=MyVal"); // Adds the namespace "HostApi" to use Command Line API using HostApi; -var task = new CommandLine("cmd", "/c", "DIR").RunAsync(); -var result = new CommandLine("cmd", "/c", "SET").Run(); -task.Wait(); +var task = new CommandLine("cmd", "/c", "DIR") + .RunAsync() + .EnsureSuccess(); + +var result = new CommandLine("cmd", "/c", "SET") + .Run() + .EnsureSuccess(); + +await task; ``` ### Cancellation of asynchronous run -The cancellation will kill a related process. +Cancellation will destroy the process and its child processes. ``` CSharp // Adds the namespace "HostApi" to use Command Line API using HostApi; var cancellationTokenSource = new CancellationTokenSource(); -var task = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120").RunAsync(default, cancellationTokenSource.Token); +var task = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120") + .RunAsync(default, cancellationTokenSource.Token); cancellationTokenSource.CancelAfter(TimeSpan.FromMilliseconds(100)); task.IsCompleted.ShouldBeFalse(); @@ -563,7 +591,10 @@ If timeout expired a process will be killed. // Adds the namespace "HostApi" to use Command Line API using HostApi; -int? exitCode = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120").Run(default, TimeSpan.FromMilliseconds(1)).ExitCode; +int? exitCode = new CommandLine("cmd", "/c", "TIMEOUT", "/T", "120") + .Run(default, TimeSpan.FromMilliseconds(1)) + .EnsureSuccess() + .ExitCode; exitCode.HasValue.ShouldBeFalse(); ``` @@ -579,18 +610,26 @@ exitCode.HasValue.ShouldBeFalse(); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("xunit", "-n", "MyLib", "--force").Build(); -result.ExitCode.ShouldBe(0); +new DotNetNew("xunit", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); // Builds the library project, running a command like: "dotnet build" from the directory "MyLib" -result = new DotNetBuild().WithWorkingDirectory("MyLib").Build(); +var result = new DotNetBuild() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(); result.ExitCode.ShouldBe(0); // Runs tests in docker -result = new DotNetTest().WithWorkingDirectory("MyLib").Build(); +result = new DotNetTest() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); result.Summary.Tests.ShouldBe(1); result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1); @@ -607,15 +646,25 @@ result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); +var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Builds the library project, running a command like: "dotnet build" from the directory "MyLib" -result = new DotNetBuild().WithWorkingDirectory("MyLib").Build(); +result = new DotNetBuild() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Clean the project, running a command like: "dotnet clean" from the directory "MyLib" -result = new DotNetClean().WithWorkingDirectory("MyLib").Build(); +result = new DotNetClean() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); @@ -633,7 +682,7 @@ using HostApi; // Gets the dotnet version, running a command like: "dotnet --version" NuGetVersion? version = default; -var exitCode = new DotNetCustom("--version") +new DotNetCustom("--version") .Run(message => NuGetVersion.TryParse(message.Line, out version)) .EnsureSuccess(); @@ -651,13 +700,18 @@ version.ShouldNotBeNull(); using HostApi; // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" -var result = new DotNetNew("mstest", "-n", "MyTests", "--force").Build(); +var result = new DotNetNew("mstest", "-n", "MyTests", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs tests via a command like: "dotnet msbuild /t:VSTest" from the directory "MyTests" result = new MSBuild() .WithTarget("VSTest") - .WithWorkingDirectory("MyTests").Build(); + .WithWorkingDirectory("MyTests") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); @@ -676,14 +730,18 @@ result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); +var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Creates a NuGet package of version 1.2.3 for the project, running a command like: "dotnet pack /p:version=1.2.3" from the directory "MyLib" result = new DotNetPack() .WithWorkingDirectory("MyLib") .AddProps(("version", "1.2.3")) - .Build(); + .Build() + .EnsureSuccess(); result.ExitCode.ShouldBe(0); ``` @@ -699,11 +757,19 @@ result.ExitCode.ShouldBe(0); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("classlib", "-n", "MyLib", "--force", "-f", "net8.0").Build(); +var result = new DotNetNew("classlib", "-n", "MyLib", "--force", "-f", "net8.0") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Publish the project, running a command like: "dotnet publish --framework net6.0" from the directory "MyLib" -result = new DotNetPublish().WithWorkingDirectory("MyLib").WithFramework("net8.0").Build(); +result = new DotNetPublish() + .WithWorkingDirectory("MyLib") + .WithFramework("net8.0") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); ``` @@ -718,11 +784,18 @@ result.ExitCode.ShouldBe(0); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); +var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Restore the project, running a command like: "dotnet restore" from the directory "MyLib" -result = new DotNetRestore().WithWorkingDirectory("MyLib").Build(); +result = new DotNetRestore() + .WithWorkingDirectory("MyLib") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); ``` @@ -737,12 +810,18 @@ result.ExitCode.ShouldBe(0); using HostApi; // Creates a new console project, running a command like: "dotnet new console -n MyApp --force" -var result = new DotNetNew("console", "-n", "MyApp", "--force").Build(); +var result = new DotNetNew("console", "-n", "MyApp", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs the console project using a command like: "dotnet run" from the directory "MyApp" var stdOut = new List(); -result = new DotNetRun().WithWorkingDirectory("MyApp").Build(message => stdOut.Add(message.Text)); +result = new DotNetRun().WithWorkingDirectory("MyApp") + .Build(message => stdOut.Add(message.Text)) + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Checks StdOut @@ -760,11 +839,17 @@ stdOut.ShouldBe(new[] {"Hello, World!"}); using HostApi; // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" -var result = new DotNetNew("mstest", "-n", "MyTests", "--force").Build(); +var result = new DotNetNew("mstest", "-n", "MyTests", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs tests via a command like: "dotnet test" from the directory "MyTests" -result = new DotNetTest().WithWorkingDirectory("MyTests").Build(); +result = new DotNetTest() + .WithWorkingDirectory("MyTests") + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); @@ -784,18 +869,23 @@ using HostApi; // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" new DotNetNew("mstest", "-n", "MyTests", "--force") - .Run().EnsureSuccess(); + .Run() + .EnsureSuccess(); // Creates the tool manifest and installs the dotCover tool locally // It is better to run the following 2 commands manually // and commit these changes to a source control -new DotNetNew("tool-manifest").Run().EnsureSuccess(); +new DotNetNew("tool-manifest") + .Run() + .EnsureSuccess(); new DotNetCustom("tool", "install", "--local", "JetBrains.dotCover.GlobalTool") - .Run().EnsureSuccess(); + .Run() + .EnsureSuccess(); // Creates a test command -var test = new DotNetTest().WithProject("MyTests"); +var test = new DotNetTest() + .WithProject("MyTests"); var dotCoverSnapshot = Path.Combine("MyTests", "dotCover.dcvr"); var dotCoverReport = Path.Combine("MyTests", "dotCover.html"); @@ -811,7 +901,9 @@ var testUnderDotCover = test.Customize(cmd => + "--dcAttributeFilters=System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage"); // Runs tests under dotCover via a command like: "dotnet dotcover test ..." -var result = testUnderDotCover.Build(); +var result = testUnderDotCover + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); @@ -839,10 +931,16 @@ var projectDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()[..4] Directory.CreateDirectory(projectDir); // Creates a local tool manifest -new DotNetNew("tool-manifest").WithWorkingDirectory(projectDir).Run().EnsureSuccess(); +new DotNetNew("tool-manifest") + .WithWorkingDirectory(projectDir) + .Run() + .EnsureSuccess(); // Restore local tools -new DotNetToolRestore().WithWorkingDirectory(projectDir).Run().EnsureSuccess(); +new DotNetToolRestore() + .WithWorkingDirectory(projectDir) + .Run() + .EnsureSuccess(); ``` @@ -856,18 +954,28 @@ new DotNetToolRestore().WithWorkingDirectory(projectDir).Run().EnsureSuccess(); using HostApi; // Creates a new test project, running a command like: "dotnet new mstest -n MyTests --force" -var result = new DotNetNew("mstest", "-n", "MyTests", "--force").Build(); +var result = new DotNetNew("mstest", "-n", "MyTests", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Builds the test project, running a command like: "dotnet build -c Release" from the directory "MyTests" -result = new DotNetBuild().WithWorkingDirectory("MyTests").WithConfiguration("Release").WithOutput("MyOutput").Build(); +result = new DotNetBuild() + .WithWorkingDirectory("MyTests") + .WithConfiguration("Release") + .WithOutput("MyOutput") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Runs tests via a command like: "dotnet vstest" from the directory "MyTests" result = new VSTest() .AddTestFileNames(Path.Combine("MyOutput", "MyTests.dll")) .WithWorkingDirectory("MyTests") - .Build(); + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.ExitCode.ShouldBe(0); @@ -886,7 +994,10 @@ result.Tests.Count(test => test.State == TestState.Finished).ShouldBe(1); using HostApi; // Creates a new library project, running a command like: "dotnet new classlib -n MyLib --force" -var result = new DotNetNew("classlib", "-n", "MyLib", "--force").Build(); +var result = new DotNetNew("classlib", "-n", "MyLib", "--force") + .Build() + .EnsureSuccess(); + result.ExitCode.ShouldBe(0); // Builds the library project, running a command like: "dotnet msbuild /t:Build -restore /p:configuration=Release -verbosity=detailed" from the directory "MyLib" @@ -896,7 +1007,8 @@ result = new MSBuild() .WithRestore(true) .AddProps(("configuration", "Release")) .WithVerbosity(DotNetVerbosity.Detailed) - .Build(); + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(); @@ -914,7 +1026,9 @@ result.ExitCode.ShouldBe(0); using HostApi; // Shuts down all build servers that are started from dotnet. -new DotNetBuildServerShutdown().Run().EnsureSuccess(); +new DotNetBuildServerShutdown() + .Run() + .EnsureSuccess(); ``` @@ -927,7 +1041,8 @@ new DotNetBuildServerShutdown().Run().EnsureSuccess(); // Adds the namespace "HostApi" to use INuGet using HostApi; -IEnumerable packages = GetService().Restore(new NuGetRestoreSettings("IoC.Container").WithVersionRange(VersionRange.All)); +IEnumerable packages = GetService() + .Restore(new NuGetRestoreSettings("IoC.Container").WithVersionRange(VersionRange.All)); ``` @@ -975,12 +1090,14 @@ var dockerRun = new DockerRun() // Creates a new library project in a docker container dockerRun .WithCommandLine(new DotNetCustom("new", "classlib", "-n", "MyLib", "--force")) - .Run().EnsureSuccess(); + .Run() + .EnsureSuccess(); // Builds the library project in a docker container var result = dockerRun .WithCommandLine(new DotNetBuild().WithProject("MyLib/MyLib.csproj")) - .Build(); + .Build() + .EnsureSuccess(); // The "result" variable provides details about a build result.Errors.Any(message => message.State == BuildMessageState.StdError).ShouldBeFalse(); diff --git a/README_BODY.md b/README_BODY.md index e52f1871..c9f0195f 100644 --- a/README_BODY.md +++ b/README_BODY.md @@ -4,7 +4,7 @@ ![](docs/csharp_cat.png) -Example of usage: +Key features by example: ```c# // Output API @@ -122,9 +122,7 @@ finally { tempDir.Delete(); } class MyTool(INuGet nuGet); ``` -## Usage - -### Script runner tool +## Script runner tool It can be installed as a command-line tool on Windows, Linux, or macOS. The dotnet tool requires [.NET 6+ runtime](https://dotnet.microsoft.com/en-us/download). @@ -174,23 +172,28 @@ dotnet csi [options] [--] [script] [script arguments] Executes a script if specified, otherwise launches an interactive REPL (Read Eval Print Loop). -Supported arguments: +`--` - 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 | |:------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------| -| 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. | | -| -- | Indicates that the remaining arguments should not be treated as options. | | | --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 | Define a key-value pair(s) for the script properties called _Props_, which is accessible in scripts. | `-p`, `/property`, `/p` | | --property: | Define a key-value pair(s) in MSBuild style for the script properties called _Props_, which is accessible in scripts. | `-p:`, `/property:`, `/p:`, `--property:key1=val1;key2=val2` | -| @file | Read the response file for more options. | | -```using HostApi;``` directive in a script allows you to use host API types without specifying the fully qualified namespace of these types. +> [!IMPORTANT] +> `using HostApi;` directive in a script allows you to use host API types without specifying the fully qualified namespace of these types. -### .NET project +## .NET project Install the C# script template [CSharpInteractive.Templates](https://www.nuget.org/packages/CSharpInteractive.Templates) @@ -198,7 +201,7 @@ Install the C# script template [CSharpInteractive.Templates](https://www.nuget.o dotnet new install CSharpInteractive.Templates ``` -Create a console project "Build" containing a script from the template *__build__* +Create a console project *__Build__* containing a script from the template *__build__* ```shell dotnet new build -o ./Build