diff --git a/src/Cake.Common.Tests/Unit/Tools/DotNet/Project/Convert/DotNetProjectConverterTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotNet/Project/Convert/DotNetProjectConverterTests.cs index 428b2041c0..8ce216c6c2 100644 --- a/src/Cake.Common.Tests/Unit/Tools/DotNet/Project/Convert/DotNetProjectConverterTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/DotNet/Project/Convert/DotNetProjectConverterTests.cs @@ -100,7 +100,22 @@ public void Should_Add_Additional_Arguments() var result = fixture.Run(); // Then - Assert.Equal("project convert \"/Working/cake.cs\" --delete-source --dry-run --force --interactive --output \"/Working/cake\" --verbosity diagnostic", result.Args); + Assert.Equal("project convert \"/Working/cake.cs\" --delete-source --dry-run --force --interactive true --output \"/Working/cake\" --verbosity diagnostic", result.Args); + } + + [Fact] + public void Should_Add_Interactive_False() + { + // Given + var fixture = new DotNetProjectConverterFixture(); + fixture.File = "cake.cs"; + fixture.Settings.Interactive = false; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("project convert \"/Working/cake.cs\" --interactive false", result.Args); } } } diff --git a/src/Cake.Common.Tests/Unit/Tools/DotNet/Reference/Add/DotNetReferenceAdderTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotNet/Reference/Add/DotNetReferenceAdderTests.cs index cdb7ffe250..0ce8588e07 100644 --- a/src/Cake.Common.Tests/Unit/Tools/DotNet/Reference/Add/DotNetReferenceAdderTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/DotNet/Reference/Add/DotNetReferenceAdderTests.cs @@ -149,8 +149,24 @@ public void Should_Add_Additional_Arguments() var result = fixture.Run(); // Then - var expected = "add \"ToDo.csproj\" reference \"/Working/lib1.csproj\" --framework net10.0 --interactive --verbosity diagnostic"; + var expected = "add \"ToDo.csproj\" reference \"/Working/lib1.csproj\" --framework net10.0 --interactive true --verbosity diagnostic"; Assert.Equal(expected, result.Args); } + + [Fact] + public void Should_Add_Interactive_False() + { + // Given + var fixture = new DotNetReferenceAdderFixture(); + fixture.ProjectReferences = new[] { (FilePath)"./lib1.csproj" }; + fixture.Project = "ToDo.csproj"; + fixture.Settings.Interactive = false; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("add \"ToDo.csproj\" reference \"/Working/lib1.csproj\" --interactive false", result.Args); + } } } diff --git a/src/Cake.Common.Tests/Unit/Tools/DotNet/Restore/DotNetRestorerTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotNet/Restore/DotNetRestorerTests.cs index e34ccdaccb..f709524c18 100644 --- a/src/Cake.Common.Tests/Unit/Tools/DotNet/Restore/DotNetRestorerTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/DotNet/Restore/DotNetRestorerTests.cs @@ -144,18 +144,21 @@ public void Should_Add_Host_Arguments() Assert.Equal("--diagnostics restore", result.Args); } - [Fact] - public void Should_Add_Interactive() + [Theory] + [InlineData(true, "restore --interactive true")] + [InlineData(false, "restore --interactive false")] + [InlineData(null, "restore")] + public void Should_Add_Interactive(bool? interactive, string expected) { // Given var fixture = new DotNetRestorerFixture(); - fixture.Settings.Interactive = true; + fixture.Settings.Interactive = interactive; // When var result = fixture.Run(); // Then - Assert.Equal($@"restore --interactive", result.Args); + Assert.Equal(expected, result.Args); } [Fact] diff --git a/src/Cake.Common.Tests/Unit/Tools/DotNet/Tool/DotNetToolCommandTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotNet/Tool/DotNetToolCommandTests.cs index f9316c1a75..0b881bb44a 100644 --- a/src/Cake.Common.Tests/Unit/Tools/DotNet/Tool/DotNetToolCommandTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/DotNet/Tool/DotNetToolCommandTests.cs @@ -120,6 +120,28 @@ public void DotNetToolInstall_WithInstallationScope_RendersSingleScopeFlag(DotNe Assert.Equal($"\"tool\" install dotnetsay {expectedScopeArgument}", result.Args); } + [Theory] + [InlineData(true, "\"tool\" install dotnetsay --global --create-manifest-if-needed true")] + [InlineData(false, "\"tool\" install dotnetsay --global --create-manifest-if-needed false")] + [InlineData(null, "\"tool\" install dotnetsay --global")] + public void DotNetToolInstall_WithCreateManifestIfNeeded_RendersExplicitValue(bool? createManifestIfNeeded, string expected) + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.InstallFull, + CommandArgument = "dotnetsay" + }; + fixture.InstallSettings.InstallationScope = DotNetToolInstallationScope.Global; + fixture.InstallSettings.CreateManifestIfNeeded = createManifestIfNeeded; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(expected, result.Args); + } + [Fact] public void DotNetToolExecute_WithDefaultSettings_RendersExpectedCommand() { @@ -283,7 +305,7 @@ public void DotNetToolCommands_RenderCommandSpecificSettings() var result = fixture.Run(); // Then - var expected = "\"tool\" install dotnetsay --tool-path \"/Working/tools\" --version \"1.2.3\" --configfile \"/Working/nuget.config\" --source \"https://example.com/source\" --add-source \"https://example.com/add-source\" --prerelease --tool-manifest \"/Working/.config/dotnet-tools.json\" --framework \"net10.0\" --disable-parallel --ignore-failed-sources --no-http-cache --interactive --allow-downgrade --arch \"x64\" --create-manifest-if-needed --allow-roll-forward"; + var expected = "\"tool\" install dotnetsay --tool-path \"/Working/tools\" --version \"1.2.3\" --configfile \"/Working/nuget.config\" --source \"https://example.com/source\" --add-source \"https://example.com/add-source\" --prerelease --tool-manifest \"/Working/.config/dotnet-tools.json\" --framework \"net10.0\" --disable-parallel --ignore-failed-sources --no-http-cache --interactive --allow-downgrade --arch \"x64\" --create-manifest-if-needed true --allow-roll-forward"; Assert.Equal(expected, result.Args); } diff --git a/src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Install/DotNetWorkloadInstallTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Install/DotNetWorkloadInstallTests.cs index d20baf0e2b..e48b337267 100644 --- a/src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Install/DotNetWorkloadInstallTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Install/DotNetWorkloadInstallTests.cs @@ -121,9 +121,24 @@ public void Should_Add_Additional_Arguments() var result = fixture.Run(); // Then - var expected = "workload install maui --configfile \"/Working/nuget.config\" --disable-parallel --ignore-failed-sources --include-previews --interactive --no-cache --skip-manifest-update"; + var expected = "workload install maui --configfile \"/Working/nuget.config\" --disable-parallel --ignore-failed-sources --include-previews --interactive true --no-cache --skip-manifest-update"; expected += " --source \"http://www.nuget.org/api/v2/package\" --source \"http://www.symbolserver.org/\" --temp-dir \"/Working/src/project\" --verbosity diagnostic"; Assert.Equal(expected, result.Args); } + + [Fact] + public void Should_Add_Interactive_False() + { + // Given + var fixture = new DotNetWorkloadInstallerFixture(); + fixture.WorkloadIds = new string[] { "maui" }; + fixture.Settings.Interactive = false; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("workload install maui --interactive false", result.Args); + } } } diff --git a/src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Restore/DotNetWorkloadRestoreTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Restore/DotNetWorkloadRestoreTests.cs index a96bedcb89..aa2f4bbde9 100644 --- a/src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Restore/DotNetWorkloadRestoreTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Restore/DotNetWorkloadRestoreTests.cs @@ -110,10 +110,25 @@ public void Should_Add_Additional_Arguments() var result = fixture.Run(); // Then - var expected = "workload restore \"./src/*\" --configfile \"/Working/nuget.config\" --disable-parallel --ignore-failed-sources --include-previews --interactive --no-cache --skip-manifest-update --source \"http://www.nuget.org/api/v2/package\" --source \"http://www.symbolserver.org/\" --temp-dir \"/Working/src/project\" --verbosity diagnostic"; + var expected = "workload restore \"./src/*\" --configfile \"/Working/nuget.config\" --disable-parallel --ignore-failed-sources --include-previews --interactive true --no-cache --skip-manifest-update --source \"http://www.nuget.org/api/v2/package\" --source \"http://www.symbolserver.org/\" --temp-dir \"/Working/src/project\" --verbosity diagnostic"; Assert.Equal(expected, result.Args); } + [Fact] + public void Should_Add_Interactive_False() + { + // Given + var fixture = new DotNetWorkloadRestorerFixture(); + fixture.Project = "./src/*"; + fixture.Settings.Interactive = false; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("workload restore \"./src/*\" --interactive false", result.Args); + } + [Theory] [InlineData("./src/*", "workload restore \"./src/*\"")] [InlineData("./src/cake build/", "workload restore \"./src/cake build/\"")] diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Common.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Common.cs index 848126d9a4..2a92e39e43 100644 --- a/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Common.cs +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Common.cs @@ -133,7 +133,7 @@ private static void AppendToolInstallSettings(ProcessArgumentBuilder builder, Do AppendRestoreSettings(builder, settings.DisableParallel, settings.IgnoreFailedSources, settings.NoHttpCache, settings.Interactive); AppendSwitch(builder, "--allow-downgrade", settings.AllowDowngrade); AppendString(builder, "--arch", settings.Architecture); - AppendSwitch(builder, "--create-manifest-if-needed", settings.CreateManifestIfNeeded); + builder.AppendSwitch("--create-manifest-if-needed", settings.CreateManifestIfNeeded); AppendSwitch(builder, "--allow-roll-forward", settings.AllowRollForward); } diff --git a/src/Cake.Common/Tools/DotNet/Project/Convert/DotNetProjectConvertSettings.cs b/src/Cake.Common/Tools/DotNet/Project/Convert/DotNetProjectConvertSettings.cs index 98eb6d43dc..20acc4bab2 100644 --- a/src/Cake.Common/Tools/DotNet/Project/Convert/DotNetProjectConvertSettings.cs +++ b/src/Cake.Common/Tools/DotNet/Project/Convert/DotNetProjectConvertSettings.cs @@ -29,8 +29,9 @@ public sealed class DotNetProjectConvertSettings : DotNetSettings /// /// Gets or sets a value indicating whether to allow the command to stop and wait for user input or action. /// For example, to complete authentication. + /// When null, the .NET CLI default is used. /// - public bool Interactive { get; set; } + public bool? Interactive { get; set; } /// /// Gets or sets the output directory for the converted project. diff --git a/src/Cake.Common/Tools/DotNet/Project/Convert/DotNetProjectConverter.cs b/src/Cake.Common/Tools/DotNet/Project/Convert/DotNetProjectConverter.cs index 788a2e2cde..04737436af 100644 --- a/src/Cake.Common/Tools/DotNet/Project/Convert/DotNetProjectConverter.cs +++ b/src/Cake.Common/Tools/DotNet/Project/Convert/DotNetProjectConverter.cs @@ -68,10 +68,7 @@ private ProcessArgumentBuilder GetArguments(FilePath file, DotNetProjectConvertS builder.Append("--force"); } - if (settings.Interactive) - { - builder.Append("--interactive"); - } + builder.AppendSwitch("--interactive", settings.Interactive); if (settings.Output != null) { diff --git a/src/Cake.Common/Tools/DotNet/Reference/Add/DotNetReferenceAddSettings.cs b/src/Cake.Common/Tools/DotNet/Reference/Add/DotNetReferenceAddSettings.cs index 37400c76ca..9d68ab73d0 100644 --- a/src/Cake.Common/Tools/DotNet/Reference/Add/DotNetReferenceAddSettings.cs +++ b/src/Cake.Common/Tools/DotNet/Reference/Add/DotNetReferenceAddSettings.cs @@ -17,6 +17,7 @@ public sealed class DotNetReferenceAddSettings : DotNetSettings /// /// Gets or sets a value indicating whether to allow the command to stop and wait for user input or action. /// For example, to complete authentication. Available since .NET Core 3.0 SDK. + /// When null, the .NET CLI default is used. /// - public bool Interactive { get; set; } + public bool? Interactive { get; set; } } diff --git a/src/Cake.Common/Tools/DotNet/Reference/Add/DotNetReferenceAdder.cs b/src/Cake.Common/Tools/DotNet/Reference/Add/DotNetReferenceAdder.cs index ea06b9bc1c..e5f78180ee 100644 --- a/src/Cake.Common/Tools/DotNet/Reference/Add/DotNetReferenceAdder.cs +++ b/src/Cake.Common/Tools/DotNet/Reference/Add/DotNetReferenceAdder.cs @@ -77,10 +77,7 @@ private ProcessArgumentBuilder GetArguments(string project, IEnumerable /// Gets or sets a value indicating whether to stop and wait for user input or action (for example to complete authentication). + /// When null, the .NET CLI default is used. /// /// /// Supported by .NET SDK version 2.1.400 and above. /// - public bool Interactive { get; set; } + public bool? Interactive { get; set; } /// /// Gets or sets a value indicating whether to enable project lock file to be generated and used with restore. diff --git a/src/Cake.Common/Tools/DotNet/Restore/DotNetRestorer.cs b/src/Cake.Common/Tools/DotNet/Restore/DotNetRestorer.cs index d9a19f995a..db6ef92608 100644 --- a/src/Cake.Common/Tools/DotNet/Restore/DotNetRestorer.cs +++ b/src/Cake.Common/Tools/DotNet/Restore/DotNetRestorer.cs @@ -122,10 +122,7 @@ private ProcessArgumentBuilder GetArguments(string root, DotNetRestoreSettings s } // Interactive - if (settings.Interactive) - { - builder.Append("--interactive"); - } + builder.AppendSwitch("--interactive", settings.Interactive); // Use lock file if (settings.UseLockFile) diff --git a/src/Cake.Common/Tools/DotNet/Tool/DotNetToolCommandSettings.cs b/src/Cake.Common/Tools/DotNet/Tool/DotNetToolCommandSettings.cs index 3909dee993..3188a4baed 100644 --- a/src/Cake.Common/Tools/DotNet/Tool/DotNetToolCommandSettings.cs +++ b/src/Cake.Common/Tools/DotNet/Tool/DotNetToolCommandSettings.cs @@ -184,8 +184,9 @@ public sealed class DotNetToolInstallSettings : DotNetToolSettings /// /// Gets or sets a value indicating whether to create a tool manifest if one is not found. + /// When null, the .NET CLI default is used. /// - public bool CreateManifestIfNeeded { get; set; } + public bool? CreateManifestIfNeeded { get; set; } /// /// Gets or sets a value indicating whether to allow a .NET tool to roll forward to newer versions of the .NET runtime. diff --git a/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstallSettings.cs b/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstallSettings.cs index d9be47cf32..9c7de239e0 100644 --- a/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstallSettings.cs +++ b/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstallSettings.cs @@ -35,8 +35,9 @@ public sealed class DotNetWorkloadInstallSettings : DotNetSettings /// /// Gets or sets a value indicating whether to allow the command to stop and wait for user input or action. /// For example, to complete authentication. + /// When null, the .NET CLI default is used. /// - public bool Interactive { get; set; } + public bool? Interactive { get; set; } /// /// Gets or sets a value indicating whether to do not cache packages and http requests. diff --git a/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstaller.cs b/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstaller.cs index 92687b1579..1765c609c0 100644 --- a/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstaller.cs +++ b/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstaller.cs @@ -87,10 +87,7 @@ private ProcessArgumentBuilder GetArguments(IEnumerable workloadIds, Dot } // Interactive - if (settings.Interactive) - { - builder.Append("--interactive"); - } + builder.AppendSwitch("--interactive", settings.Interactive); // No Cache if (settings.NoCache) diff --git a/src/Cake.Common/Tools/DotNet/Workload/Restore/DotNetWorkloadRestoreSettings.cs b/src/Cake.Common/Tools/DotNet/Workload/Restore/DotNetWorkloadRestoreSettings.cs index b482eee157..0844406ece 100644 --- a/src/Cake.Common/Tools/DotNet/Workload/Restore/DotNetWorkloadRestoreSettings.cs +++ b/src/Cake.Common/Tools/DotNet/Workload/Restore/DotNetWorkloadRestoreSettings.cs @@ -35,8 +35,9 @@ public sealed class DotNetWorkloadRestoreSettings : DotNetSettings /// /// Gets or sets a value indicating whether to allow the command to stop and wait for user input or action. /// For example, to complete authentication. + /// When null, the .NET CLI default is used. /// - public bool Interactive { get; set; } + public bool? Interactive { get; set; } /// /// Gets or sets a value indicating whether to do not cache packages and http requests. diff --git a/src/Cake.Common/Tools/DotNet/Workload/Restore/DotNetWorkloadRestorer.cs b/src/Cake.Common/Tools/DotNet/Workload/Restore/DotNetWorkloadRestorer.cs index 08c9fa4898..90a08f60f6 100644 --- a/src/Cake.Common/Tools/DotNet/Workload/Restore/DotNetWorkloadRestorer.cs +++ b/src/Cake.Common/Tools/DotNet/Workload/Restore/DotNetWorkloadRestorer.cs @@ -83,10 +83,7 @@ private ProcessArgumentBuilder GetArguments(string project, DotNetWorkloadRestor } // Interactive - if (settings.Interactive) - { - builder.Append("--interactive"); - } + builder.AppendSwitch("--interactive", settings.Interactive); // No Cache if (settings.NoCache) diff --git a/src/Cake.Core.Tests/Unit/Extensions/ProcessArgumentListExtensionsTests.cs b/src/Cake.Core.Tests/Unit/Extensions/ProcessArgumentListExtensionsTests.cs index 775d15a7c8..e86e579c99 100644 --- a/src/Cake.Core.Tests/Unit/Extensions/ProcessArgumentListExtensionsTests.cs +++ b/src/Cake.Core.Tests/Unit/Extensions/ProcessArgumentListExtensionsTests.cs @@ -407,6 +407,37 @@ public void ShouldInsertFormattedTextArgument() } } + public class TheAppendSwitchBooleanMethods + { + [Theory] + [InlineData(true, "restore --interactive true")] + [InlineData(false, "restore --interactive false")] + [InlineData(null, "restore")] + public void ShouldAppendSwitchWithExplicitValue(bool? value, string expected) + { + var result = new ProcessArgumentBuilder() + .Append("restore") + .AppendSwitch("--interactive", value) + .RenderSafe(); + + Assert.Equal(expected, result); + } + + [Theory] + [InlineData(true, "restore --interactive=true")] + [InlineData(false, "restore --interactive=false")] + [InlineData(null, "restore")] + public void ShouldAppendSwitchWithExplicitValueAndSeparator(bool? value, string expected) + { + var result = new ProcessArgumentBuilder() + .Append("restore") + .AppendSwitch("--interactive", "=", value) + .RenderSafe(); + + Assert.Equal(expected, result); + } + } + public class TheInsertSwitchMethods { [Fact] diff --git a/src/Cake.Core/Extensions/ProcessArgumentListExtensions.cs b/src/Cake.Core/Extensions/ProcessArgumentListExtensions.cs index 529872788c..f0c14ed5a8 100644 --- a/src/Cake.Core/Extensions/ProcessArgumentListExtensions.cs +++ b/src/Cake.Core/Extensions/ProcessArgumentListExtensions.cs @@ -621,6 +621,45 @@ public static ProcessArgumentBuilder AppendSwitch(this ProcessArgumentBuilder bu return builder; } + /// + /// Appends the specified switch with an explicit true or false value to the argument builder. + /// Nothing is appended when is null. + /// + /// The builder. + /// The switch preceding the value. + /// The value to be appended. + /// The same instance so that multiple calls can be chained. + /// + /// + /// var args = new ProcessArgumentBuilder() + /// .Append("restore") + /// .AppendSwitch("--interactive", false); + /// + /// + public static ProcessArgumentBuilder AppendSwitch(this ProcessArgumentBuilder builder, string @switch, bool? value) + { + return AppendSwitch(builder, @switch, " ", value); + } + + /// + /// Appends the specified switch with an explicit true or false value to the argument builder. + /// Nothing is appended when is null. + /// + /// The builder. + /// The switch preceding the value. + /// The separator between the switch and value. + /// The value to be appended. + /// The same instance so that multiple calls can be chained. + public static ProcessArgumentBuilder AppendSwitch(this ProcessArgumentBuilder builder, string @switch, string separator, bool? value) + { + if (value.HasValue) + { + AppendSwitch(builder, @switch, separator, value.Value ? "true" : "false"); + } + + return builder; + } + /// /// Prepend the specified switch to the argument builder. ///