diff --git a/build.cake b/build.cake index 557c60f121..06505947d6 100644 --- a/build.cake +++ b/build.cake @@ -379,13 +379,14 @@ Task("Frosting-Integration-Tests") }, (parameters, test, context) => { + string defaultVerbosity = EnvironmentVariable("RUNNER_DEBUG", "0") == "1" ? "diagnostic" : "quiet"; try { Information("Testing: {0}", test.Framework); DotNetRun(test.Project.FullPath, new ProcessArgumentBuilder() - .AppendSwitchQuoted("--verbosity", "=", Argument("integration-tests-verbosity", "quiet")) + .AppendSwitchQuoted("--verbosity", "=", Argument("integration-tests-verbosity", defaultVerbosity)) .AppendSwitchQuoted("--name", "=", "World") .AppendSwitchQuoted("--IntegrationTest_Argument", "=", bool.TrueString), new DotNetRunSettings @@ -414,16 +415,21 @@ Task("Run-Integration-Tests") .IsDependentOn("Prepare-Integration-Tests") .IsDependentOn("Frosting-Integration-Tests") .DeferOnError() - .DoesForEach( - parameters => new[] { - GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net8.0/**/Cake.dll").Single(), - GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net9.0/**/Cake.dll").Single(), - GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net10.0/**/Cake.dll").Single() + .DoesForEach( + parameters => { + string defaultVerbosity = EnvironmentVariable("RUNNER_DEBUG", "0") == "1" ? "diagnostic" : "quiet"; + return [ + (GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net8.0/**/Cake.dll").Single(), defaultVerbosity), + (GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net9.0/**/Cake.dll").Single(), defaultVerbosity), + (GetFiles($"{parameters.Paths.Directories.IntegrationTestsBinTool.FullPath}/**/net10.0/**/Cake.dll").Single(), defaultVerbosity) + ]; }, - (parameters, cakeAssembly, context) => + (parameters, test, context) => { + var (cakeAssembly, verbosity) = test; try { + Information("Testing: {0}", cakeAssembly); CakeExecuteScript("./tests/integration/build.cake", new CakeSettings { @@ -434,7 +440,7 @@ Task("Run-Integration-Tests") }, ArgumentCustomization = args => args .AppendSwitchQuoted("--target", " ", Argument("integration-tests-target", "Run-All-Tests")) - .AppendSwitchQuoted("--verbosity", " ", Argument("integration-tests-verbosity", "quiet")) + .AppendSwitchQuoted("--verbosity", " ", Argument("integration-tests-verbosity", verbosity)) .AppendSwitchQuoted("--platform", " ", parameters.IsRunningOnWindows ? "windows" : "posix") .AppendSwitchQuoted("--customarg", " ", "hello") .AppendSwitchQuoted("--multipleargs", "=", "a") diff --git a/build/paths.cake b/build/paths.cake index 7661a26066..6073aa1c9c 100644 --- a/build/paths.cake +++ b/build/paths.cake @@ -40,7 +40,7 @@ public record BuildPaths( integrationTestsBinTool); FilePath signClientPath = null; - if (context.IsRunningOnWindows()) + if (context.IsRunningOnWindows() && context.GitHubActions().IsRunningOnGitHubActions) { signClientPath = context.Tools.Resolve("sign.exe"); diff --git a/src/Cake.Common.Tests/Unit/Tools/DotNet/Tool/DotNetToolCommandTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotNet/Tool/DotNetToolCommandTests.cs new file mode 100644 index 0000000000..5bb976fe43 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Tools/DotNet/Tool/DotNetToolCommandTests.cs @@ -0,0 +1,677 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Cake.Common.Tests.Fixtures.Tools.DotNet; +using Cake.Common.Tools.DotNet; +using Cake.Common.Tools.DotNet.Tool; +using Cake.Core; +using Cake.Core.IO; +using Cake.Testing; +using NSubstitute; +using Xunit; + +namespace Cake.Common.Tests.Unit.Tools.DotNet.Tool +{ + public sealed class DotNetToolCommandTests + { + public sealed class TheToolCommandAliases + { + public static IEnumerable DotNetToolExecuteOverloadCases() + { + yield return new object[] { nameof(DotNetToolCommandInvocation.ExecutePackageOnly), "\"tool\" exec dotnetsay@1.2.3" }; + yield return new object[] { nameof(DotNetToolCommandInvocation.ExecutePackageWithArguments), "\"tool\" exec dotnetsay@1.2.3 -- --tool-option tool-value" }; + yield return new object[] { nameof(DotNetToolCommandInvocation.ExecutePackageWithSettings), "\"tool\" exec dotnetsay@1.2.3 --verbosity minimal" }; + yield return new object[] { nameof(DotNetToolCommandInvocation.ExecutePackageWithArgumentsAndSettings), "\"tool\" exec dotnetsay@1.2.3 --verbosity minimal -- --tool-option tool-value" }; + } + + public static IEnumerable DotNetToolCommandCases() + { + yield return new object[] { nameof(DotNetToolCommandInvocation.ExecutePackageWithArgumentsAndSettings), "dotnetsay@1.2.3", "\"tool\" exec dotnetsay@1.2.3 --verbosity minimal -- --tool-option tool-value", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.InstallFull), "dotnetsay", "\"tool\" install dotnetsay --global --verbosity minimal", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.ListFull), "dotnetsay", "\"tool\" list dotnetsay --global", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.ListSettings), null, "\"tool\" list --global", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.ListPackageSettings), "dotnetsay", "\"tool\" list dotnetsay --global", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.RestoreFull), null, "\"tool\" restore --disable-parallel --verbosity minimal", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.RestoreSettings), null, "\"tool\" restore --disable-parallel --verbosity minimal", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.RunFull), "dotnetsay", "\"tool\" run dotnetsay -- Hello --name World", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.RunCommandArguments), "dotnetsay", "\"tool\" run dotnetsay -- Hello --name World", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.RunCommandArgumentsAndSettings), "dotnetsay", "\"tool\" run dotnetsay -- Hello --name World", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.RunCommandSettings), "dotnetsay", "\"tool\" run dotnetsay", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.SearchFull), "cake", "\"tool\" search cake --detail", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.UninstallFull), "dotnetsay", "\"tool\" uninstall dotnetsay --global", false }; + yield return new object[] { nameof(DotNetToolCommandInvocation.UpdateFull), "dotnetsay", "\"tool\" update dotnetsay --global --verbosity minimal", false }; + } + + public static IEnumerable RequiredCommandArgumentCases() + { + var commandArgumentCases = new[] + { + new { InvocationName = nameof(DotNetToolCommandInvocation.ExecutePackageWithSettings), ParameterName = "packageId" }, + new { InvocationName = nameof(DotNetToolCommandInvocation.InstallFull), ParameterName = "packageId" }, + new { InvocationName = nameof(DotNetToolCommandInvocation.RunFull), ParameterName = "commandName" }, + new { InvocationName = nameof(DotNetToolCommandInvocation.SearchFull), ParameterName = "searchTerm" }, + new { InvocationName = nameof(DotNetToolCommandInvocation.UninstallFull), ParameterName = "packageId" } + }; + + var invalidArguments = new[] { null, string.Empty, " " }; + foreach (var commandArgumentCase in commandArgumentCases) + { + foreach (var invalidArgument in invalidArguments) + { + yield return new object[] { commandArgumentCase.InvocationName, commandArgumentCase.ParameterName, invalidArgument }; + } + } + } + + [Fact] + public void DotNetToolInstall_WithDefaultSettings_RendersCakeToolsPath() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.InstallFull, + CommandArgument = "dotnetsay" + }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"tool\" install dotnetsay --tool-path \"/Working/tools\"", result.Args); + } + + [Fact] + public void DotNetToolInstall_WithToolPathScopeAndWorkingDirectory_RendersToolsPathRelativeToWorkingDirectory() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.InstallFull, + CommandArgument = "dotnetsay" + }; + fixture.InstallSettings.WorkingDirectory = "./temp"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"tool\" install dotnetsay --tool-path \"/Working/temp/tools\"", result.Args); + } + + [Theory] + [InlineData(DotNetToolInstallationScope.Global, "--global")] + [InlineData(DotNetToolInstallationScope.Local, "--local")] + [InlineData(DotNetToolInstallationScope.ToolPath, "--tool-path \"/Working/tools\"")] + public void DotNetToolInstall_WithInstallationScope_RendersSingleScopeFlag(DotNetToolInstallationScope scope, string expectedScopeArgument) + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.InstallFull, + CommandArgument = "dotnetsay" + }; + fixture.InstallSettings.InstallationScope = scope; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal($"\"tool\" install dotnetsay {expectedScopeArgument}", result.Args); + } + + [Fact] + public void DotNetToolExecute_WithDefaultSettings_RendersExpectedCommand() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.ExecutePackageWithSettings, + CommandArgument = "dotnetsay" + }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"tool\" exec dotnetsay", result.Args); + } + + [Theory] + [MemberData(nameof(RequiredCommandArgumentCases))] + public void DotNetToolCommand_WithInvalidRequiredArgument_ThrowsArgumentNullException(string invocationName, string parameterName, string commandArgument) + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = Enum.Parse(invocationName), + CommandArgument = commandArgument + }; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + AssertEx.IsArgumentNullException(result, parameterName); + } + + [Fact] + public void DotNetToolExecute_WithNullSettings_UsesDefaultSettings() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.ExecutePackageWithSettings, + CommandArgument = "dotnetsay", + ExecuteSettings = null + }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"tool\" exec dotnetsay", result.Args); + } + + [Fact] + public void DotNetToolExecute_WhenProcessCannotStart_ThrowsCakeException() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.ExecutePackageWithSettings, + CommandArgument = "dotnetsay" + }; + fixture.GivenProcessCannotStart(); + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + AssertEx.IsCakeException(result, ".NET CLI: Process was not started."); + } + + [Fact] + public void DotNetToolExecute_WhenProcessHasNonZeroExitCode_ThrowsCakeException() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.ExecutePackageWithSettings, + CommandArgument = "dotnetsay" + }; + fixture.GivenProcessExitsWithCode(1); + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + AssertEx.IsCakeException(result, ".NET CLI: Process returned an error (exit code 1)."); + } + + [Theory] + [MemberData(nameof(DotNetToolExecuteOverloadCases))] + public void DotNetToolExecute_AllOverloads_RenderDotNetToolExecCommand(string invocationName, string expectedArguments) + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = Enum.Parse(invocationName), + CommandArgument = "dotnetsay@1.2.3" + }; + fixture.ConfigureCommonSettings(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(expectedArguments, result.Args); + } + + [Theory] + [MemberData(nameof(DotNetToolCommandCases))] + public void DotNetToolCommands_RenderExpectedArguments(string invocationName, string commandArgument, string expectedArguments, bool usesProjectPath) + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = Enum.Parse(invocationName), + ProjectPath = "./src/project.csproj", + CommandArgument = commandArgument + }; + fixture.ConfigureCommonSettings(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal(expectedArguments, result.Args); + if (usesProjectPath) + { + Assert.Equal(fixture.ProjectPath.GetDirectory().FullPath, result.Process.WorkingDirectory.FullPath); + } + } + + [Fact] + public void DotNetToolCommands_RenderCommandSpecificSettings() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.InstallFull, + CommandArgument = "dotnetsay" + }; + fixture.InstallSettings.InstallationScope = DotNetToolInstallationScope.ToolPath; + fixture.InstallSettings.ToolInstallationPath = "./tools"; + fixture.InstallSettings.Version = "1.2.3"; + fixture.InstallSettings.ConfigFile = "./nuget.config"; + fixture.InstallSettings.ToolManifest = "./.config/dotnet-tools.json"; + fixture.InstallSettings.AddSource.Add("https://example.com/add-source"); + fixture.InstallSettings.Source.Add("https://example.com/source"); + fixture.InstallSettings.Framework = "net10.0"; + fixture.InstallSettings.Prerelease = true; + fixture.InstallSettings.DisableParallel = true; + fixture.InstallSettings.IgnoreFailedSources = true; + fixture.InstallSettings.NoHttpCache = true; + fixture.InstallSettings.Interactive = true; + fixture.InstallSettings.AllowDowngrade = true; + fixture.InstallSettings.Architecture = "x64"; + fixture.InstallSettings.CreateManifestIfNeeded = true; + fixture.InstallSettings.AllowRollForward = true; + + // When + 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"; + Assert.Equal(expected, result.Args); + } + + [Fact] + public void DotNetToolExecute_RenderCommandSpecificSettings() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.ExecutePackageWithSettings, + CommandArgument = "dotnetsay" + }; + fixture.ExecuteSettings.Version = "1.2.3"; + fixture.ExecuteSettings.ConfigFile = "./nuget.config"; + fixture.ExecuteSettings.Source.Add("https://example.com/source"); + fixture.ExecuteSettings.AddSource.Add("https://example.com/add-source"); + fixture.ExecuteSettings.Prerelease = true; + fixture.ExecuteSettings.AllowRollForward = true; + fixture.ExecuteSettings.DisableParallel = true; + fixture.ExecuteSettings.IgnoreFailedSources = true; + fixture.ExecuteSettings.NoHttpCache = true; + fixture.ExecuteSettings.Interactive = true; + + // When + var result = fixture.Run(); + + // Then + var expected = "\"tool\" exec dotnetsay --version \"1.2.3\" --configfile \"/Working/nuget.config\" --source \"https://example.com/source\" --add-source \"https://example.com/add-source\" --prerelease --allow-roll-forward --disable-parallel --ignore-failed-sources --no-http-cache --interactive"; + Assert.Equal(expected, result.Args); + } + + [Fact] + public void DotNetToolList_RenderCommandSpecificSettings() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.ListFull, + CommandArgument = "dotnetsay" + }; + fixture.ListSettings.InstallationScope = DotNetToolInstallationScope.Local; + fixture.ListSettings.Format = DotNetToolListFormat.Json; + + // When + var result = fixture.Run(); + + // Then + var expected = "\"tool\" list dotnetsay --local --format json"; + Assert.Equal(expected, result.Args); + } + + [Fact] + public void DotNetToolRestore_RenderCommandSpecificSettings() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.RestoreFull + }; + fixture.RestoreSettings.ConfigFile = "./nuget.config"; + fixture.RestoreSettings.AddSource.Add("https://example.com/add-source"); + fixture.RestoreSettings.ToolManifest = "./.config/dotnet-tools.json"; + fixture.RestoreSettings.DisableParallel = true; + fixture.RestoreSettings.IgnoreFailedSources = true; + fixture.RestoreSettings.NoHttpCache = true; + fixture.RestoreSettings.Interactive = true; + + // When + var result = fixture.Run(); + + // Then + var expected = "\"tool\" restore --configfile \"/Working/nuget.config\" --add-source \"https://example.com/add-source\" --tool-manifest \"/Working/.config/dotnet-tools.json\" --disable-parallel --ignore-failed-sources --no-http-cache --interactive"; + Assert.Equal(expected, result.Args); + } + + [Fact] + public void DotNetToolRun_RenderCommandSpecificSettings() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.RunFull, + CommandArgument = "dotnetsay" + }; + fixture.RunSettings.AllowRollForward = true; + + // When + var result = fixture.Run(); + + // Then + var expected = "\"tool\" run dotnetsay --allow-roll-forward"; + Assert.Equal(expected, result.Args); + } + + [Fact] + public void DotNetToolRun_WithArgumentCustomization_RestoresOriginalCustomization() + { + // Given + Func addInteractive = arguments => arguments.Append("--interactive"); + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.RunCommandArgumentsAndSettings, + CommandArgument = "dotnetsay" + }; + fixture.RunArguments = Arguments("--tool-option"); + fixture.RunSettings.ArgumentCustomization = addInteractive; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"tool\" run dotnetsay --interactive -- --tool-option", result.Args); + Assert.Same(addInteractive, fixture.RunSettings.ArgumentCustomization); + } + + [Fact] + public void DotNetToolSearch_RenderCommandSpecificSettings() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.SearchFull, + CommandArgument = "cake" + }; + fixture.SearchSettings.Detail = true; + fixture.SearchSettings.Skip = 10; + fixture.SearchSettings.Take = 20; + fixture.SearchSettings.Prerelease = true; + + // When + var result = fixture.Run(); + + // Then + var expected = "\"tool\" search cake --detail --skip 10 --take 20 --prerelease"; + Assert.Equal(expected, result.Args); + } + + [Fact] + public void DotNetToolUninstall_RenderCommandSpecificSettings() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.UninstallFull, + CommandArgument = "dotnetsay" + }; + fixture.UninstallSettings.InstallationScope = DotNetToolInstallationScope.Local; + fixture.UninstallSettings.ToolManifest = "./.config/dotnet-tools.json"; + + // When + var result = fixture.Run(); + + // Then + var expected = "\"tool\" uninstall dotnetsay --local --tool-manifest \"/Working/.config/dotnet-tools.json\""; + Assert.Equal(expected, result.Args); + } + + [Fact] + public void DotNetToolUpdate_RenderCommandSpecificSettings() + { + // Given + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.UpdateFull, + CommandArgument = null + }; + fixture.UpdateSettings.InstallationScope = DotNetToolInstallationScope.Global; + fixture.UpdateSettings.Version = "1.2.3"; + fixture.UpdateSettings.ConfigFile = "./nuget.config"; + fixture.UpdateSettings.Source.Add("https://example.com/source"); + fixture.UpdateSettings.AddSource.Add("https://example.com/add-source"); + fixture.UpdateSettings.Prerelease = true; + fixture.UpdateSettings.ToolManifest = "./.config/dotnet-tools.json"; + fixture.UpdateSettings.Framework = "net10.0"; + fixture.UpdateSettings.DisableParallel = true; + fixture.UpdateSettings.IgnoreFailedSources = true; + fixture.UpdateSettings.NoHttpCache = true; + fixture.UpdateSettings.Interactive = true; + fixture.UpdateSettings.AllowDowngrade = true; + fixture.UpdateSettings.All = true; + + // When + var result = fixture.Run(); + + // Then + var expected = "\"tool\" update --global --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 --all"; + Assert.Equal(expected, result.Args); + } + + [Fact] + public void DotNetToolExecute_WithArgumentCustomization_RestoresOriginalCustomization() + { + // Given + Func addInteractive = arguments => arguments.Append("--interactive"); + var fixture = new DotNetToolCommandFixture + { + Invocation = DotNetToolCommandInvocation.ExecutePackageWithArgumentsAndSettings, + CommandArgument = "dotnetsay" + }; + fixture.ExecuteArguments = Arguments("--tool-option"); + fixture.ExecuteSettings.ArgumentCustomization = addInteractive; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("\"tool\" exec dotnetsay --interactive -- --tool-option", result.Args); + Assert.Same(addInteractive, fixture.ExecuteSettings.ArgumentCustomization); + } + + private static ProcessArgumentBuilder Arguments(params string[] arguments) + { + var builder = new ProcessArgumentBuilder(); + foreach (var argument in arguments) + { + builder.Append(argument); + } + + return builder; + } + } + + private enum DotNetToolCommandInvocation + { + ExecutePackageWithSettings, + ExecutePackageOnly, + ExecutePackageWithArguments, + ExecutePackageWithArgumentsAndSettings, + InstallFull, + ListFull, + ListSettings, + ListPackageSettings, + RestoreFull, + RestoreSettings, + RunFull, + RunCommandArguments, + RunCommandArgumentsAndSettings, + RunCommandSettings, + SearchFull, + UninstallFull, + UpdateFull + } + + private sealed class DotNetToolCommandFixture : DotNetFixture + { + public FilePath ProjectPath { get; set; } + + public string CommandArgument { get; set; } + + public DotNetToolCommandInvocation Invocation { get; set; } + + public DotNetToolExecuteSettings ExecuteSettings { get; set; } = new DotNetToolExecuteSettings(); + + public ProcessArgumentBuilder ExecuteArguments { get; set; } = new ProcessArgumentBuilder(); + + public DotNetToolInstallSettings InstallSettings { get; set; } = new DotNetToolInstallSettings(); + + public DotNetToolListSettings ListSettings { get; set; } = new DotNetToolListSettings(); + + public DotNetToolRestoreSettings RestoreSettings { get; set; } = new DotNetToolRestoreSettings(); + + public DotNetToolRunSettings RunSettings { get; set; } = new DotNetToolRunSettings(); + + public ProcessArgumentBuilder RunArguments { get; set; } = new ProcessArgumentBuilder(); + + public DotNetToolSearchSettings SearchSettings { get; set; } = new DotNetToolSearchSettings(); + + public DotNetToolUninstallSettings UninstallSettings { get; set; } = new DotNetToolUninstallSettings(); + + public DotNetToolUpdateSettings UpdateSettings { get; set; } = new DotNetToolUpdateSettings(); + + public void ConfigureCommonSettings() + { + ExecuteSettings.Verbosity = DotNetVerbosity.Minimal; + ExecuteArguments = Arguments("--tool-option", "tool-value"); + + InstallSettings.Verbosity = DotNetVerbosity.Minimal; + InstallSettings.InstallationScope = DotNetToolInstallationScope.Global; + + ListSettings.Verbosity = DotNetVerbosity.Minimal; + ListSettings.InstallationScope = DotNetToolInstallationScope.Global; + + RestoreSettings.Verbosity = DotNetVerbosity.Minimal; + RestoreSettings.DisableParallel = true; + + RunSettings.Verbosity = DotNetVerbosity.Minimal; + RunArguments = Arguments("Hello", "--name", "World"); + + SearchSettings.Verbosity = DotNetVerbosity.Minimal; + SearchSettings.Detail = true; + + UninstallSettings.Verbosity = DotNetVerbosity.Minimal; + UninstallSettings.InstallationScope = DotNetToolInstallationScope.Global; + + UpdateSettings.Verbosity = DotNetVerbosity.Minimal; + UpdateSettings.InstallationScope = DotNetToolInstallationScope.Global; + } + + protected override void RunTool() + { + var context = CreateContext(); + + switch (Invocation) + { + case DotNetToolCommandInvocation.ExecutePackageOnly: + context.DotNetToolExecute(CommandArgument); + break; + case DotNetToolCommandInvocation.ExecutePackageWithArguments: + context.DotNetToolExecute(CommandArgument, ExecuteArguments); + break; + case DotNetToolCommandInvocation.ExecutePackageWithArgumentsAndSettings: + context.DotNetToolExecute(CommandArgument, ExecuteArguments, ExecuteSettings); + break; + case DotNetToolCommandInvocation.ExecutePackageWithSettings: + context.DotNetToolExecute(CommandArgument, ExecuteSettings); + break; + case DotNetToolCommandInvocation.InstallFull: + context.DotNetToolInstall(CommandArgument, InstallSettings); + break; + case DotNetToolCommandInvocation.ListFull: + context.DotNetToolList(CommandArgument, ListSettings); + break; + case DotNetToolCommandInvocation.ListSettings: + context.DotNetToolList(ListSettings); + break; + case DotNetToolCommandInvocation.ListPackageSettings: + context.DotNetToolList(CommandArgument, ListSettings); + break; + case DotNetToolCommandInvocation.RestoreFull: + context.DotNetToolRestore(RestoreSettings); + break; + case DotNetToolCommandInvocation.RestoreSettings: + context.DotNetToolRestore(RestoreSettings); + break; + case DotNetToolCommandInvocation.RunFull: + context.DotNetToolRun(CommandArgument, RunArguments, RunSettings); + break; + case DotNetToolCommandInvocation.RunCommandArguments: + context.DotNetToolRun(CommandArgument, RunArguments); + break; + case DotNetToolCommandInvocation.RunCommandArgumentsAndSettings: + context.DotNetToolRun(CommandArgument, RunArguments, RunSettings); + break; + case DotNetToolCommandInvocation.RunCommandSettings: + context.DotNetToolRun(CommandArgument, RunSettings); + break; + case DotNetToolCommandInvocation.SearchFull: + context.DotNetToolSearch(CommandArgument, SearchSettings); + break; + case DotNetToolCommandInvocation.UninstallFull: + context.DotNetToolUninstall(CommandArgument, UninstallSettings); + break; + case DotNetToolCommandInvocation.UpdateFull: + context.DotNetToolUpdate(CommandArgument, UpdateSettings); + break; + } + } + + private static ProcessArgumentBuilder Arguments(params string[] arguments) + { + var builder = new ProcessArgumentBuilder(); + foreach (var argument in arguments) + { + builder.Append(argument); + } + + return builder; + } + + private ICakeContext CreateContext() + { + var arguments = new CakeArguments(Enumerable.Empty().ToLookup(argument => argument, StringComparer.Ordinal)); + + return new CakeContext( + FileSystem, + Environment, + Globber, + new FakeLog(), + arguments, + ProcessRunner, + Substitute.For(), + Tools, + Substitute.For(), + Configuration); + } + } + } +} diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Common.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Common.cs new file mode 100644 index 0000000000..94fc158a72 --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Common.cs @@ -0,0 +1,308 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Cake.Common.Tools.DotNet.Tool; +using Cake.Core; +using Cake.Core.Configuration; +using Cake.Core.IO; + +namespace Cake.Common.Tools.DotNet +{ + /// + /// Contains functionality related to .NET CLI. + /// + /// In order to use the commands for this alias, the .NET CLI tools will need to be installed on the machine where + /// the Cake script is being executed. See this page for information + /// on how to install. + /// + /// + public static partial class DotNetAliases + { + private static void RunDotNetToolCommand( + ICakeContext context, + FilePath projectPath, + ProcessArgumentBuilder arguments, + DotNetToolSettings settings) + { + ArgumentNullException.ThrowIfNull(context); + ArgumentNullException.ThrowIfNull(arguments); + ArgumentNullException.ThrowIfNull(settings); + + context.DotNetTool(projectPath, "tool", arguments, settings); + } + + private static void RunDotNetToolCommandWithoutVerbosity( + ICakeContext context, + FilePath projectPath, + ProcessArgumentBuilder arguments, + DotNetToolSettings settings) + { + ArgumentNullException.ThrowIfNull(context); + ArgumentNullException.ThrowIfNull(arguments); + ArgumentNullException.ThrowIfNull(settings); + + var verbosity = settings.Verbosity; + settings.Verbosity = null; + + try + { + context.DotNetTool(projectPath, "tool", arguments, settings); + } + finally + { + settings.Verbosity = verbosity; + } + } + + private static void RunDotNetToolCommandWithForwardedArguments( + ICakeContext context, + FilePath projectPath, + ProcessArgumentBuilder arguments, + ProcessArgumentBuilder forwardedArguments, + DotNetToolSettings settings) + { + ArgumentNullException.ThrowIfNull(context); + ArgumentNullException.ThrowIfNull(arguments); + ArgumentNullException.ThrowIfNull(settings); + + if (forwardedArguments.IsNullOrEmpty()) + { + context.DotNetTool(projectPath, "tool", arguments, settings); + return; + } + + var argumentCustomization = settings.ArgumentCustomization; + settings.ArgumentCustomization = dotnetArguments => + { + var customizedArguments = argumentCustomization?.Invoke(dotnetArguments) ?? dotnetArguments; + customizedArguments.Append("--"); + forwardedArguments.CopyTo(customizedArguments); + return customizedArguments; + }; + + try + { + context.DotNetTool(projectPath, "tool", arguments, settings); + } + finally + { + settings.ArgumentCustomization = argumentCustomization; + } + } + + private static void RunDotNetToolCommandWithForwardedArgumentsWithoutVerbosity( + ICakeContext context, + FilePath projectPath, + ProcessArgumentBuilder arguments, + ProcessArgumentBuilder forwardedArguments, + DotNetToolSettings settings) + { + ArgumentNullException.ThrowIfNull(context); + ArgumentNullException.ThrowIfNull(arguments); + ArgumentNullException.ThrowIfNull(settings); + + var verbosity = settings.Verbosity; + settings.Verbosity = null; + + try + { + RunDotNetToolCommandWithForwardedArguments(context, projectPath, arguments, forwardedArguments, settings); + } + finally + { + settings.Verbosity = verbosity; + } + } + + private static void AppendToolExecuteSettings(ProcessArgumentBuilder builder, DotNetToolExecuteSettings settings, ICakeEnvironment environment) + { + AppendPackageResolutionSettings(builder, settings.Version, settings.ConfigFile, settings.Source, settings.AddSource, settings.Prerelease, environment); + AppendSwitch(builder, "--allow-roll-forward", settings.AllowRollForward); + AppendRestoreSettings(builder, settings.DisableParallel, settings.IgnoreFailedSources, settings.NoHttpCache, settings.Interactive); + } + + private static void AppendToolInstallSettings(ProcessArgumentBuilder builder, DotNetToolInstallSettings settings, ICakeConfiguration configuration, ICakeEnvironment environment) + { + AppendInstallationScope(builder, settings.InstallationScope, settings.ToolInstallationPath, settings.WorkingDirectory, configuration, environment); + AppendPackageResolutionSettings(builder, settings.Version, settings.ConfigFile, settings.Source, settings.AddSource, settings.Prerelease, environment); + AppendFilePath(builder, "--tool-manifest", settings.ToolManifest, environment); + AppendString(builder, "--framework", settings.Framework); + 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); + AppendSwitch(builder, "--allow-roll-forward", settings.AllowRollForward); + } + + private static void AppendToolListSettings(ProcessArgumentBuilder builder, DotNetToolListSettings settings, ICakeConfiguration configuration, ICakeEnvironment environment) + { + AppendInstallationScope(builder, settings.InstallationScope, settings.ToolInstallationPath, settings.WorkingDirectory, configuration, environment); + + if (settings.Format.HasValue) + { + builder.AppendSwitch("--format", settings.Format.Value == DotNetToolListFormat.Json ? "json" : "table"); + } + } + + private static void AppendToolRestoreSettings(ProcessArgumentBuilder builder, DotNetToolRestoreSettings settings, ICakeEnvironment environment) + { + AppendFilePath(builder, "--configfile", settings.ConfigFile, environment); + AppendSources(builder, "--add-source", settings.AddSource); + AppendFilePath(builder, "--tool-manifest", settings.ToolManifest, environment); + AppendRestoreSettings(builder, settings.DisableParallel, settings.IgnoreFailedSources, settings.NoHttpCache, settings.Interactive); + } + + private static void AppendToolRunSettings(ProcessArgumentBuilder builder, DotNetToolRunSettings settings) + { + AppendSwitch(builder, "--allow-roll-forward", settings.AllowRollForward); + } + + private static void AppendToolSearchSettings(ProcessArgumentBuilder builder, DotNetToolSearchSettings settings) + { + AppendSwitch(builder, "--detail", settings.Detail); + + if (settings.Skip.HasValue) + { + builder.AppendSwitch("--skip", settings.Skip.Value.ToString()); + } + + if (settings.Take.HasValue) + { + builder.AppendSwitch("--take", settings.Take.Value.ToString()); + } + + AppendSwitch(builder, "--prerelease", settings.Prerelease); + } + + private static void AppendToolUninstallSettings(ProcessArgumentBuilder builder, DotNetToolUninstallSettings settings, ICakeConfiguration configuration, ICakeEnvironment environment) + { + AppendInstallationScope(builder, settings.InstallationScope, settings.ToolInstallationPath, settings.WorkingDirectory, configuration, environment); + AppendFilePath(builder, "--tool-manifest", settings.ToolManifest, environment); + } + + private static void AppendToolUpdateSettings(ProcessArgumentBuilder builder, DotNetToolUpdateSettings settings, ICakeConfiguration configuration, ICakeEnvironment environment) + { + AppendInstallationScope(builder, settings.InstallationScope, settings.ToolInstallationPath, settings.WorkingDirectory, configuration, environment); + AppendPackageResolutionSettings(builder, settings.Version, settings.ConfigFile, settings.Source, settings.AddSource, settings.Prerelease, environment); + AppendFilePath(builder, "--tool-manifest", settings.ToolManifest, environment); + AppendString(builder, "--framework", settings.Framework); + AppendRestoreSettings(builder, settings.DisableParallel, settings.IgnoreFailedSources, settings.NoHttpCache, settings.Interactive); + AppendSwitch(builder, "--allow-downgrade", settings.AllowDowngrade); + AppendSwitch(builder, "--all", settings.All); + } + + private static void AppendInstallationScope( + ProcessArgumentBuilder builder, + DotNetToolInstallationScope scope, + DirectoryPath toolInstallationPath, + DirectoryPath settingsWorkingDirectory, + ICakeConfiguration configuration, + ICakeEnvironment environment) + { + switch (scope) + { + case DotNetToolInstallationScope.Global: + builder.Append("--global"); + break; + case DotNetToolInstallationScope.Local: + builder.Append("--local"); + break; + case DotNetToolInstallationScope.ToolPath: + var root = settingsWorkingDirectory ?? environment.WorkingDirectory; + var path = toolInstallationPath ?? configuration.GetToolPath(root, environment); + AppendDirectoryPath(builder, "--tool-path", path, environment); + break; + } + } + + private static void AppendPackageResolutionSettings( + ProcessArgumentBuilder builder, + string version, + FilePath configFile, + ICollection source, + ICollection addSource, + bool prerelease, + ICakeEnvironment environment) + { + AppendString(builder, "--version", version); + AppendFilePath(builder, "--configfile", configFile, environment); + AppendSources(builder, "--source", source); + AppendSources(builder, "--add-source", addSource); + AppendSwitch(builder, "--prerelease", prerelease); + } + + private static void AppendRestoreSettings(ProcessArgumentBuilder builder, bool disableParallel, bool ignoreFailedSources, bool noHttpCache, bool interactive) + { + AppendSwitch(builder, "--disable-parallel", disableParallel); + AppendSwitch(builder, "--ignore-failed-sources", ignoreFailedSources); + AppendSwitch(builder, "--no-http-cache", noHttpCache); + AppendSwitch(builder, "--interactive", interactive); + } + + private static void AppendRequiredArgument(ProcessArgumentBuilder builder, string argument, string parameterName) + { + if (string.IsNullOrWhiteSpace(argument)) + { + throw new ArgumentNullException(parameterName); + } + + builder.Append(argument); + } + + private static void AppendOptionalArgument(ProcessArgumentBuilder builder, string argument) + { + if (!string.IsNullOrWhiteSpace(argument)) + { + builder.Append(argument); + } + } + + private static void AppendSwitch(ProcessArgumentBuilder builder, string switchName, bool value) + { + if (value) + { + builder.Append(switchName); + } + } + + private static void AppendString(ProcessArgumentBuilder builder, string switchName, string value) + { + if (!string.IsNullOrWhiteSpace(value)) + { + builder.AppendSwitchQuoted(switchName, value); + } + } + + private static void AppendFilePath(ProcessArgumentBuilder builder, string switchName, FilePath value, ICakeEnvironment environment) + { + if (value != null) + { + builder.AppendSwitchQuoted(switchName, value.MakeAbsolute(environment).FullPath); + } + } + + private static void AppendDirectoryPath(ProcessArgumentBuilder builder, string switchName, DirectoryPath value, ICakeEnvironment environment) + { + if (value != null) + { + builder.AppendSwitchQuoted(switchName, value.MakeAbsolute(environment).FullPath); + } + } + + private static void AppendSources(ProcessArgumentBuilder builder, string switchName, ICollection sources) + { + if (sources == null) + { + return; + } + + foreach (var source in sources) + { + AppendString(builder, switchName, source); + } + } + } +} diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Execute.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Execute.cs new file mode 100644 index 0000000000..85789d8e5f --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Execute.cs @@ -0,0 +1,109 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tools.DotNet.Tool; +using Cake.Core; +using Cake.Core.Annotations; +using Cake.Core.IO; + +namespace Cake.Common.Tools.DotNet +{ + /// + /// Contains functionality related to .NET CLI. + /// + /// In order to use the commands for this alias, the .NET CLI tools will need to be installed on the machine where + /// the Cake script is being executed. See this page for information + /// on how to install. + /// + /// + public static partial class DotNetAliases + { + /// + /// Executes a .NET tool package with dotnet tool exec. + /// + /// For more information, see dotnet tool exec. + /// The context. + /// The package ID to execute. Use the package@version syntax to request a specific version. + /// + /// + /// DotNetToolExecute("DPI"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolExecute(this ICakeContext context, string packageId) + { + context.DotNetToolExecute(packageId, (ProcessArgumentBuilder)null, null); + } + + /// + /// For more information, see dotnet tool exec. + /// The context. + /// The package ID to execute. Use the package@version syntax to request a specific version. + /// The arguments forwarded to the tool. + /// + /// + /// var arguments = new ProcessArgumentBuilder().Append("--version"); + /// DotNetToolExecute("DPI", arguments); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolExecute(this ICakeContext context, string packageId, ProcessArgumentBuilder arguments) + { + context.DotNetToolExecute(packageId, arguments, null); + } + + /// + /// For more information, see dotnet tool exec. + /// The context. + /// The package ID to execute. Use the package@version syntax to request a specific version. + /// The arguments forwarded to the tool. + /// The settings. + /// + /// + /// var arguments = new ProcessArgumentBuilder().Append("--version"); + /// DotNetToolExecute("DPI", arguments, new DotNetToolExecuteSettings + /// { + /// WorkingDirectory = "./src" + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolExecute(this ICakeContext context, string packageId, ProcessArgumentBuilder arguments, DotNetToolExecuteSettings settings) + { + settings ??= new DotNetToolExecuteSettings(); + + var dotnetArguments = new ProcessArgumentBuilder().Append("exec"); + AppendRequiredArgument(dotnetArguments, packageId, nameof(packageId)); + AppendToolExecuteSettings(dotnetArguments, settings, context.Environment); + RunDotNetToolCommandWithForwardedArguments(context, null, dotnetArguments, arguments, settings); + } + + /// + /// For more information, see dotnet tool exec. + /// The context. + /// The package ID to execute. Use the package@version syntax to request a specific version. + /// The settings. + /// + /// + /// DotNetToolExecute("DPI", new DotNetToolExecuteSettings + /// { + /// WorkingDirectory = "./src" + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolExecute(this ICakeContext context, string packageId, DotNetToolExecuteSettings settings) + { + context.DotNetToolExecute(packageId, (ProcessArgumentBuilder)null, settings); + } + } +} diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Install.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Install.cs new file mode 100644 index 0000000000..a26aee579a --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Install.cs @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tools.DotNet.Tool; +using Cake.Core; +using Cake.Core.Annotations; +using Cake.Core.IO; + +namespace Cake.Common.Tools.DotNet +{ + /// + /// Contains functionality related to .NET CLI. + /// + /// In order to use the commands for this alias, the .NET CLI tools will need to be installed on the machine where + /// the Cake script is being executed. See this page for information + /// on how to install. + /// + /// + public static partial class DotNetAliases + { + /// + /// Installs a .NET tool package with dotnet tool install. + /// + /// For more information, see dotnet tool install. + /// The context. + /// The package ID to install. + /// + /// + /// DotNetToolInstall("dotnetsay"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolInstall(this ICakeContext context, string packageId) + { + context.DotNetToolInstall(packageId, null); + } + + /// + /// For more information, see dotnet tool install. + /// The context. + /// The package ID to install. + /// The settings. + /// + /// + /// DotNetToolInstall("DPI", new DotNetToolInstallSettings + /// { + /// WorkingDirectory = "./src" + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolInstall(this ICakeContext context, string packageId, DotNetToolInstallSettings settings) + { + settings ??= new DotNetToolInstallSettings(); + + var arguments = new ProcessArgumentBuilder().Append("install"); + AppendRequiredArgument(arguments, packageId, nameof(packageId)); + AppendToolInstallSettings(arguments, settings, context.Configuration, context.Environment); + RunDotNetToolCommand(context, null, arguments, settings); + } + } +} diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.List.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.List.cs new file mode 100644 index 0000000000..0eb741fa6d --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.List.cs @@ -0,0 +1,107 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tools.DotNet.Tool; +using Cake.Core; +using Cake.Core.Annotations; +using Cake.Core.IO; + +namespace Cake.Common.Tools.DotNet +{ + /// + /// Contains functionality related to .NET CLI. + /// + /// In order to use the commands for this alias, the .NET CLI tools will need to be installed on the machine where + /// the Cake script is being executed. See this page for information + /// on how to install. + /// + /// + public static partial class DotNetAliases + { + /// + /// Lists .NET tools with dotnet tool list. + /// + /// For more information, see dotnet tool list. + /// The context. + /// + /// + /// DotNetToolList(); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolList(this ICakeContext context) + { + context.DotNetToolList(null, null); + } + + /// + /// For more information, see dotnet tool list. + /// The context. + /// The settings. + /// + /// + /// DotNetToolList(new DotNetToolListSettings + /// { + /// InstallationScope = DotNetToolInstallationScope.Local, + /// WorkingDirectory = "./src" + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolList(this ICakeContext context, DotNetToolListSettings settings) + { + context.DotNetToolList(null, settings); + } + + /// + /// Lists a .NET tool package with dotnet tool list. + /// + /// For more information, see dotnet tool list. + /// The context. + /// The package ID to list. + /// + /// + /// DotNetToolList("dotnetsay"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolList(this ICakeContext context, string packageId) + { + context.DotNetToolList(packageId, null); + } + + /// + /// For more information, see dotnet tool list. + /// The context. + /// The package ID to list. + /// The settings. + /// + /// + /// DotNetToolList("DPI", new DotNetToolListSettings + /// { + /// InstallationScope = DotNetToolInstallationScope.Local, + /// WorkingDirectory = "./src" + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolList(this ICakeContext context, string packageId, DotNetToolListSettings settings) + { + settings ??= new DotNetToolListSettings(); + + var arguments = new ProcessArgumentBuilder().Append("list"); + AppendOptionalArgument(arguments, packageId); + AppendToolListSettings(arguments, settings, context.Configuration, context.Environment); + RunDotNetToolCommandWithoutVerbosity(context, null, arguments, settings); + } + } +} diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Restore.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Restore.cs new file mode 100644 index 0000000000..3c84289a83 --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Restore.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tools.DotNet.Tool; +using Cake.Core; +using Cake.Core.Annotations; +using Cake.Core.IO; + +namespace Cake.Common.Tools.DotNet +{ + /// + /// Contains functionality related to .NET CLI. + /// + /// In order to use the commands for this alias, the .NET CLI tools will need to be installed on the machine where + /// the Cake script is being executed. See this page for information + /// on how to install. + /// + /// + public static partial class DotNetAliases + { + /// + /// Restores .NET tools with dotnet tool restore. + /// + /// For more information, see dotnet tool restore. + /// The context. + /// + /// + /// DotNetToolRestore(); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolRestore(this ICakeContext context) + { + context.DotNetToolRestore(null); + } + + /// + /// For more information, see dotnet tool restore. + /// The context. + /// The settings. + /// + /// + /// DotNetToolRestore(new DotNetToolRestoreSettings + /// { + /// WorkingDirectory = "./src" + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolRestore(this ICakeContext context, DotNetToolRestoreSettings settings) + { + settings ??= new DotNetToolRestoreSettings(); + + var arguments = new ProcessArgumentBuilder().Append("restore"); + AppendToolRestoreSettings(arguments, settings, context.Environment); + RunDotNetToolCommand(context, null, arguments, settings); + } + } +} diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Run.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Run.cs new file mode 100644 index 0000000000..f304760c00 --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Run.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tools.DotNet.Tool; +using Cake.Core; +using Cake.Core.Annotations; +using Cake.Core.IO; + +namespace Cake.Common.Tools.DotNet +{ + /// + /// Contains functionality related to .NET CLI. + /// + /// In order to use the commands for this alias, the .NET CLI tools will need to be installed on the machine where + /// the Cake script is being executed. See this page for information + /// on how to install. + /// + /// + public static partial class DotNetAliases + { + /// + /// Runs a local .NET tool with dotnet tool run. + /// + /// For more information, see dotnet tool run. + /// The context. + /// The tool command name to run. + /// + /// + /// DotNetToolRun("dotnetsay"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolRun(this ICakeContext context, string commandName) + { + context.DotNetToolRun(commandName, null, null); + } + + /// + /// For more information, see dotnet tool run. + /// The context. + /// The tool command name to run. + /// The arguments forwarded to the tool. + /// + /// + /// var arguments = new ProcessArgumentBuilder().Append("--version"); + /// DotNetToolRun("DPI", arguments); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolRun(this ICakeContext context, string commandName, ProcessArgumentBuilder arguments) + { + context.DotNetToolRun(commandName, arguments, null); + } + + /// + /// For more information, see dotnet tool run. + /// The context. + /// The tool command name to run. + /// The arguments forwarded to the tool. + /// The settings. + /// + /// + /// DotNetToolRun("DPI", "--version", new DotNetToolRunSettings + /// { + /// WorkingDirectory = "./src" + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolRun(this ICakeContext context, string commandName, ProcessArgumentBuilder arguments, DotNetToolRunSettings settings) + { + settings ??= new DotNetToolRunSettings(); + + var dotnetArguments = new ProcessArgumentBuilder().Append("run"); + AppendRequiredArgument(dotnetArguments, commandName, nameof(commandName)); + AppendToolRunSettings(dotnetArguments, settings); + RunDotNetToolCommandWithForwardedArgumentsWithoutVerbosity(context, null, dotnetArguments, arguments, settings); + } + + /// + /// For more information, see dotnet tool run. + /// The context. + /// The tool command name to run. + /// The settings. + /// + /// + /// DotNetToolRun("DPI", new DotNetToolRunSettings + /// { + /// WorkingDirectory = "./src" + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolRun(this ICakeContext context, string commandName, DotNetToolRunSettings settings) + { + context.DotNetToolRun(commandName, null, settings); + } + } +} diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Search.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Search.cs new file mode 100644 index 0000000000..d75730eabd --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Search.cs @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tools.DotNet.Tool; +using Cake.Core; +using Cake.Core.Annotations; +using Cake.Core.IO; + +namespace Cake.Common.Tools.DotNet +{ + /// + /// Contains functionality related to .NET CLI. + /// + /// In order to use the commands for this alias, the .NET CLI tools will need to be installed on the machine where + /// the Cake script is being executed. See this page for information + /// on how to install. + /// + /// + public static partial class DotNetAliases + { + /// + /// Searches for .NET tool packages with dotnet tool search. + /// + /// For more information, see dotnet tool search. + /// The context. + /// The search term. + /// + /// + /// DotNetToolSearch("cake"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolSearch(this ICakeContext context, string searchTerm) + { + context.DotNetToolSearch(searchTerm, null); + } + + /// + /// For more information, see dotnet tool search. + /// The context. + /// The search term. + /// The settings. + /// + /// + /// DotNetToolSearch("DPI", new DotNetToolSearchSettings + /// { + /// WorkingDirectory = "./src" + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolSearch(this ICakeContext context, string searchTerm, DotNetToolSearchSettings settings) + { + settings ??= new DotNetToolSearchSettings(); + + var arguments = new ProcessArgumentBuilder().Append("search"); + AppendRequiredArgument(arguments, searchTerm, nameof(searchTerm)); + AppendToolSearchSettings(arguments, settings); + RunDotNetToolCommandWithoutVerbosity(context, null, arguments, settings); + } + } +} diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Uninstall.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Uninstall.cs new file mode 100644 index 0000000000..a9b3766fb8 --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Uninstall.cs @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tools.DotNet.Tool; +using Cake.Core; +using Cake.Core.Annotations; +using Cake.Core.IO; + +namespace Cake.Common.Tools.DotNet +{ + /// + /// Contains functionality related to .NET CLI. + /// + /// In order to use the commands for this alias, the .NET CLI tools will need to be installed on the machine where + /// the Cake script is being executed. See this page for information + /// on how to install. + /// + /// + public static partial class DotNetAliases + { + /// + /// Uninstalls a .NET tool package with dotnet tool uninstall. + /// + /// For more information, see dotnet tool uninstall. + /// The context. + /// The package ID to uninstall. + /// + /// + /// DotNetToolUninstall("dotnetsay"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolUninstall(this ICakeContext context, string packageId) + { + context.DotNetToolUninstall(packageId, null); + } + + /// + /// For more information, see dotnet tool uninstall. + /// The context. + /// The package ID to uninstall. + /// The settings. + /// + /// + /// DotNetToolUninstall("DPI", new DotNetToolUninstallSettings + /// { + /// WorkingDirectory = "./src" + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolUninstall(this ICakeContext context, string packageId, DotNetToolUninstallSettings settings) + { + settings ??= new DotNetToolUninstallSettings(); + + var arguments = new ProcessArgumentBuilder().Append("uninstall"); + AppendRequiredArgument(arguments, packageId, nameof(packageId)); + AppendToolUninstallSettings(arguments, settings, context.Configuration, context.Environment); + RunDotNetToolCommandWithoutVerbosity(context, null, arguments, settings); + } + } +} diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Update.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Update.cs new file mode 100644 index 0000000000..902a938d38 --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.Tool.Update.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Cake.Common.Tools.DotNet.Tool; +using Cake.Core; +using Cake.Core.Annotations; +using Cake.Core.IO; + +namespace Cake.Common.Tools.DotNet +{ + /// + /// Contains functionality related to .NET CLI. + /// + /// In order to use the commands for this alias, the .NET CLI tools will need to be installed on the machine where + /// the Cake script is being executed. See this page for information + /// on how to install. + /// + /// + public static partial class DotNetAliases + { + /// + /// Updates .NET tool packages with dotnet tool update. + /// + /// For more information, see dotnet tool update. + /// The context. + /// + /// + /// DotNetToolUpdate(); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolUpdate(this ICakeContext context) + { + context.DotNetToolUpdate(null, null); + } + + /// + /// For more information, see dotnet tool update. + /// The context. + /// The settings. + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolUpdate(this ICakeContext context, DotNetToolUpdateSettings settings) + { + context.DotNetToolUpdate(null, settings); + } + + /// + /// Updates a .NET tool package with dotnet tool update. + /// + /// For more information, see dotnet tool update. + /// The context. + /// The package ID to update. + /// + /// + /// DotNetToolUpdate("dotnetsay"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolUpdate(this ICakeContext context, string packageId) + { + context.DotNetToolUpdate(packageId, null); + } + + /// + /// For more information, see dotnet tool update. + /// The context. + /// The package ID to update. + /// The settings. + /// + /// + /// DotNetToolUpdate("DPI", new DotNetToolUpdateSettings + /// { + /// WorkingDirectory = "./src" + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Tool")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Tool")] + public static void DotNetToolUpdate(this ICakeContext context, string packageId, DotNetToolUpdateSettings settings) + { + settings ??= new DotNetToolUpdateSettings(); + + var arguments = new ProcessArgumentBuilder().Append("update"); + AppendOptionalArgument(arguments, packageId); + AppendToolUpdateSettings(arguments, settings, context.Configuration, context.Environment); + RunDotNetToolCommand(context, null, arguments, settings); + } + } +} diff --git a/src/Cake.Common/Tools/DotNet/Tool/DotNetToolCommandSettings.cs b/src/Cake.Common/Tools/DotNet/Tool/DotNetToolCommandSettings.cs new file mode 100644 index 0000000000..a9070fb2de --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/Tool/DotNetToolCommandSettings.cs @@ -0,0 +1,399 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Cake.Core.IO; + +namespace Cake.Common.Tools.DotNet.Tool +{ + /// + /// The installation scope for dotnet tool commands that support global, local, or tool-path installation. + /// + public enum DotNetToolInstallationScope + { + /// + /// Maps to --tool-path. Uses when set; + /// otherwise falls back to the Cake tools directory (same as the #tool directive). + /// + ToolPath, + + /// + /// Maps to --global. + /// + Global, + + /// + /// Maps to --local. Use to target a specific manifest. + /// + Local, + } + + /// + /// The output format for dotnet tool list. + /// + public enum DotNetToolListFormat + { + /// + /// Outputs the result as a table. + /// + Table, + + /// + /// Outputs the result as JSON. + /// + Json + } + + /// + /// Contains settings used by dotnet tool exec. + /// + public sealed class DotNetToolExecuteSettings : DotNetToolSettings + { + /// + /// Gets or sets the tool package version to execute. + /// + public string Version { get; set; } + + /// + /// Gets or sets a value indicating whether to allow a .NET tool to roll forward to newer versions of the .NET runtime. + /// + public bool AllowRollForward { get; set; } + + /// + /// Gets or sets a value indicating whether to include prerelease packages. + /// + public bool Prerelease { get; set; } + + /// + /// Gets or sets the NuGet configuration file to use. + /// + public FilePath ConfigFile { get; set; } + + /// + /// Gets or sets the package sources to use instead of configured NuGet package sources. + /// + public ICollection Source { get; set; } = new List(); + + /// + /// Gets or sets additional package sources to use during installation. + /// + public ICollection AddSource { get; set; } = new List(); + + /// + /// Gets or sets a value indicating whether to prevent restoring multiple projects in parallel. + /// + public bool DisableParallel { get; set; } + + /// + /// Gets or sets a value indicating whether to treat package source failures as warnings. + /// + public bool IgnoreFailedSources { get; set; } + + /// + /// Gets or sets a value indicating whether to not cache packages and HTTP requests. + /// + public bool NoHttpCache { get; set; } + + /// + /// Gets or sets a value indicating whether to allow the command to stop and wait for user input or action. + /// + public bool Interactive { get; set; } + } + + /// + /// Contains settings used by dotnet tool install. + /// + public sealed class DotNetToolInstallSettings : DotNetToolSettings + { + /// + /// Gets or sets the installation scope for the tool. + /// + public DotNetToolInstallationScope InstallationScope { get; set; } + + /// + /// Gets or sets the directory where the tool will be installed when is . + /// When not set, the Cake tools directory is used. + /// + public DirectoryPath ToolInstallationPath { get; set; } + + /// + /// Gets or sets the tool package version to install. + /// + public string Version { get; set; } + + /// + /// Gets or sets the NuGet configuration file to use. + /// + public FilePath ConfigFile { get; set; } + + /// + /// Gets or sets the path to the local tool manifest file. + /// + public FilePath ToolManifest { get; set; } + + /// + /// Gets or sets additional package sources to use during installation. + /// + public ICollection AddSource { get; set; } = new List(); + + /// + /// Gets or sets the package sources to use instead of configured NuGet package sources. + /// + public ICollection Source { get; set; } = new List(); + + /// + /// Gets or sets the target framework to install the tool for. + /// + public string Framework { get; set; } + + /// + /// Gets or sets a value indicating whether to include prerelease packages. + /// + public bool Prerelease { get; set; } + + /// + /// Gets or sets a value indicating whether to prevent restoring multiple projects in parallel. + /// + public bool DisableParallel { get; set; } + + /// + /// Gets or sets a value indicating whether to treat package source failures as warnings. + /// + public bool IgnoreFailedSources { get; set; } + + /// + /// Gets or sets a value indicating whether to not cache packages and HTTP requests. + /// + public bool NoHttpCache { get; set; } + + /// + /// Gets or sets a value indicating whether to allow the command to stop and wait for user input or action. + /// + public bool Interactive { get; set; } + + /// + /// Gets or sets a value indicating whether to allow package downgrade when installing a .NET tool package. + /// + public bool AllowDowngrade { get; set; } + + /// + /// Gets or sets the target architecture. + /// + public string Architecture { get; set; } + + /// + /// Gets or sets a value indicating whether to create a tool manifest if one is not found. + /// + 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. + /// + public bool AllowRollForward { get; set; } + } + + /// + /// Contains settings used by dotnet tool list. + /// + public sealed class DotNetToolListSettings : DotNetToolSettings + { + /// + /// Gets or sets the installation scope for listing tools. + /// + public DotNetToolInstallationScope InstallationScope { get; set; } + + /// + /// Gets or sets the directory containing the tools to list when is . + /// When not set, the Cake tools directory is used. + /// + public DirectoryPath ToolInstallationPath { get; set; } + + /// + /// Gets or sets the output format. + /// + public DotNetToolListFormat? Format { get; set; } + } + + /// + /// Contains settings used by dotnet tool restore. + /// + public sealed class DotNetToolRestoreSettings : DotNetToolSettings + { + /// + /// Gets or sets the NuGet configuration file to use. + /// + public FilePath ConfigFile { get; set; } + + /// + /// Gets or sets additional package sources to use during installation. + /// + public ICollection AddSource { get; set; } = new List(); + + /// + /// Gets or sets the path to the local tool manifest file. + /// + public FilePath ToolManifest { get; set; } + + /// + /// Gets or sets a value indicating whether to prevent restoring multiple projects in parallel. + /// + public bool DisableParallel { get; set; } + + /// + /// Gets or sets a value indicating whether to treat package source failures as warnings. + /// + public bool IgnoreFailedSources { get; set; } + + /// + /// Gets or sets a value indicating whether to not cache packages and HTTP requests. + /// + public bool NoHttpCache { get; set; } + + /// + /// Gets or sets a value indicating whether to allow the command to stop and wait for user input or action. + /// + public bool Interactive { get; set; } + } + + /// + /// Contains settings used by dotnet tool run. + /// + public sealed class DotNetToolRunSettings : DotNetToolSettings + { + /// + /// Gets or sets a value indicating whether to allow a .NET tool to roll forward to newer versions of the .NET runtime. + /// + public bool AllowRollForward { get; set; } + } + + /// + /// Contains settings used by dotnet tool search. + /// + public sealed class DotNetToolSearchSettings : DotNetToolSettings + { + /// + /// Gets or sets a value indicating whether to show detailed query results. + /// + public bool Detail { get; set; } + + /// + /// Gets or sets the number of results to skip for pagination. + /// + public int? Skip { get; set; } + + /// + /// Gets or sets the number of results to return for pagination. + /// + public int? Take { get; set; } + + /// + /// Gets or sets a value indicating whether to include prerelease packages. + /// + public bool Prerelease { get; set; } + } + + /// + /// Contains settings used by dotnet tool uninstall. + /// + public sealed class DotNetToolUninstallSettings : DotNetToolSettings + { + /// + /// Gets or sets the installation scope for uninstalling the tool. + /// + public DotNetToolInstallationScope InstallationScope { get; set; } + + /// + /// Gets or sets the directory containing the tool to uninstall when is . + /// When not set, the Cake tools directory is used. + /// + public DirectoryPath ToolInstallationPath { get; set; } + + /// + /// Gets or sets the path to the local tool manifest file. + /// + public FilePath ToolManifest { get; set; } + } + + /// + /// Contains settings used by dotnet tool update. + /// + public sealed class DotNetToolUpdateSettings : DotNetToolSettings + { + /// + /// Gets or sets the installation scope for updating the tool. + /// + public DotNetToolInstallationScope InstallationScope { get; set; } + + /// + /// Gets or sets the directory where the tool is installed when is . + /// When not set, the Cake tools directory is used. + /// + public DirectoryPath ToolInstallationPath { get; set; } + + /// + /// Gets or sets the tool package version to update to. + /// + public string Version { get; set; } + + /// + /// Gets or sets the NuGet configuration file to use. + /// + public FilePath ConfigFile { get; set; } + + /// + /// Gets or sets the path to the local tool manifest file. + /// + public FilePath ToolManifest { get; set; } + + /// + /// Gets or sets additional package sources to use during installation. + /// + public ICollection AddSource { get; set; } = new List(); + + /// + /// Gets or sets the package sources to use instead of configured NuGet package sources. + /// + public ICollection Source { get; set; } = new List(); + + /// + /// Gets or sets the target framework to install the tool for. + /// + public string Framework { get; set; } + + /// + /// Gets or sets a value indicating whether to include prerelease packages. + /// + public bool Prerelease { get; set; } + + /// + /// Gets or sets a value indicating whether to prevent restoring multiple projects in parallel. + /// + public bool DisableParallel { get; set; } + + /// + /// Gets or sets a value indicating whether to treat package source failures as warnings. + /// + public bool IgnoreFailedSources { get; set; } + + /// + /// Gets or sets a value indicating whether to not cache packages and HTTP requests. + /// + public bool NoHttpCache { get; set; } + + /// + /// Gets or sets a value indicating whether to allow the command to stop and wait for user input or action. + /// + public bool Interactive { get; set; } + + /// + /// Gets or sets a value indicating whether to allow package downgrade when updating a .NET tool package. + /// + public bool AllowDowngrade { get; set; } + + /// + /// Gets or sets a value indicating whether to update all tools. + /// + public bool All { get; set; } + } +} diff --git a/tests/integration/Cake.Common/Tools/DotNet/DotNetAliases.cake b/tests/integration/Cake.Common/Tools/DotNet/DotNetAliases.cake index 68edb0f002..20862941df 100644 --- a/tests/integration/Cake.Common/Tools/DotNet/DotNetAliases.cake +++ b/tests/integration/Cake.Common/Tools/DotNet/DotNetAliases.cake @@ -16,211 +16,398 @@ Task("Cake.Common.Tools.DotNet.DotNetAliases.Setup") CopyDirectory(sourcePath, targetPath); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRestore") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSearchPackage") .Does(() => { // Given - var root = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); + var package = "Cake.Tool"; // When - DotNetRestore(root.FullPath, new DotNetRestoreSettings { Verbosity = DotNetVerbosity.Minimal }); + var result = DotNetSearchPackage(package); + + // Then + Assert.NotNull(result); + Assert.Contains(package, result.Select(x => x.Name)); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuild") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRestore") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSearchPackage.ExactMatch") + .Does(() => +{ + // Given: exact-match returns "version" in JSON (not "latestVersion"); see issue #4454 + var package = "Refit.Newtonsoft.Json"; + + // When + var result = DotNetSearchPackage(package, new DotNetPackageSearchSettings { ExactMatch = true }); + + // Then: every item must have non-null Version (fix for dotnet package search --exact-match --format json) + Assert.NotNull(result); + var list = result.ToList(); + Assert.NotEmpty(list); + foreach (var item in list) + { + Assert.NotNull(item.Name); + Assert.NotNull(item.Version); + Assert.Equal(package, item.Name); + } +}); + +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetToolExecute") + .Does(() => +{ + var workingDirectory = Paths.Temp.Combine("./Cake.Common/Tools/DotNet/DotNetToolExecute"); + EnsureDirectoryExist(workingDirectory); + + DotNetToolExecute("DPI", "--version", new DotNetToolExecuteSettings + { + WorkingDirectory = workingDirectory, + }); +}); + +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetToolInstallListRunUninstallLocal") + .Does(() => +{ + var package = "DPI"; + var workingDirectory = Paths.Temp.Combine("./Cake.Common/Tools/DotNet/DotNetToolInstallListRunUninstallLocal"); + var toolManifest = workingDirectory.CombineWithFilePath("dotnet-tools.json"); + EnsureDirectoryExist(workingDirectory); + + // dotnet tool --local walks up the directory tree for an existing manifest. + // The Cake repo has .config/dotnet-tools.json at the root, so create an isolated manifest here first. + System.IO.File.WriteAllText( + toolManifest.FullPath, + """ + { + "version": 1, + "isRoot": true, + "tools": {} + } + """); + + DotNetToolInstall(package, new DotNetToolInstallSettings + { + InstallationScope = DotNetToolInstallationScope.Local, + WorkingDirectory = workingDirectory + }); + + DotNetToolList(package, new DotNetToolListSettings + { + InstallationScope = DotNetToolInstallationScope.Local, + WorkingDirectory = workingDirectory + }); + + DotNetToolRun(package, "--version", new DotNetToolRunSettings + { + WorkingDirectory = workingDirectory, + }); + + DotNetToolUninstall(package, new DotNetToolUninstallSettings + { + InstallationScope = DotNetToolInstallationScope.Local, + WorkingDirectory = workingDirectory, + }); +}); + +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetToolInstallListRunUninstallLocalToolManifest") + .Does(() => +{ + var package = "DPI"; + var workingDirectory = Paths.Temp.Combine("./Cake.Common/Tools/DotNet/DotNetToolInstallListRunUninstallLocalToolManifest"); + var toolManifest = workingDirectory.CombineWithFilePath("dotnet-tools.json"); + EnsureDirectoryExist(workingDirectory); + + // Use an isolated manifest path so local tool commands do not walk up to the Cake repo manifest. + System.IO.File.WriteAllText( + toolManifest.FullPath, + """ + { + "version": 1, + "isRoot": true, + "tools": {} + } + """); + + DotNetToolInstall(package, new DotNetToolInstallSettings + { + InstallationScope = DotNetToolInstallationScope.Local, + ToolManifest = toolManifest, + }); + + DotNetToolList(package, new DotNetToolListSettings + { + InstallationScope = DotNetToolInstallationScope.Local, + WorkingDirectory = workingDirectory + }); + + DotNetToolRun(package, "--version", new DotNetToolRunSettings + { + WorkingDirectory = workingDirectory + }); + + DotNetToolUninstall(package, new DotNetToolUninstallSettings + { + InstallationScope = DotNetToolInstallationScope.Local, + ToolManifest = toolManifest, + }); +}); + +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetToolInstallListRunUninstallToolPath") + .Does(() => +{ + var package = "DPI"; + var workingDirectory = Paths.Temp.Combine("./Cake.Common/Tools/DotNet/DotNetToolInstallListRunUninstallToolPath"); + var toolInstallationPath = workingDirectory.Combine("./tools"); + EnsureDirectoryExist(workingDirectory); + EnsureDirectoryExist(toolInstallationPath); + + DotNetToolInstall(package, new DotNetToolInstallSettings + { + InstallationScope = DotNetToolInstallationScope.ToolPath, + ToolInstallationPath = toolInstallationPath, + WorkingDirectory = workingDirectory, + }); + + DotNetToolList(package, new DotNetToolListSettings + { + InstallationScope = DotNetToolInstallationScope.ToolPath, + ToolInstallationPath = toolInstallationPath, + WorkingDirectory = workingDirectory, + }); + + // dotnet tool run applies to local manifest tools; --tool-path installs are invoked directly. + var toolExecutable = toolInstallationPath.CombineWithFilePath(Context.IsRunningOnUnix() ? "dpi" : "dpi.exe"); + Assert.True(FileExists(toolExecutable)); + StartProcess(toolExecutable, new ProcessSettings + { + Arguments = "--version", + WorkingDirectory = workingDirectory, + }); + + DotNetToolUninstall(package, new DotNetToolUninstallSettings + { + InstallationScope = DotNetToolInstallationScope.ToolPath, + ToolInstallationPath = toolInstallationPath, + WorkingDirectory = workingDirectory, + }); +}); + +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetAddPackage") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); - var assembly = path.CombineWithFilePath("hwapp/bin/Debug/net10.0/hwapp.dll"); + var package = "Cake.Core"; // When - DotNetBuild(project.FullPath); + DotNetAddPackage(package, project.FullPath); + + var value = XmlPeek( + project.FullPath, + $"/Project/ItemGroup/PackageReference[@Include='{package}']/@Include" + ); // Then - Assert.True(System.IO.File.Exists(assembly.FullPath)); + Assert.Equal(package, value); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuild") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetAddReference") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); var project = path.CombineWithFilePath("hwapp.tests/hwapp.tests.csproj"); - + var projectReferencePath = path.CombineWithFilePath("hwapp/hwapp.csproj"); + var projectReference = "..\\hwapp\\hwapp.csproj"; // When - DotNetTest(project.FullPath, new DotNetTestSettings { PathType = DotNetTestPathType.Project }); + DotNetAddReference(project.FullPath, new[] { (FilePath)projectReferencePath.FullPath}); + var value = XmlPeek( + project.FullPath, + $"/Project/ItemGroup/ProjectReference[@Include='{projectReference}']/@Include" + ); + // Then + Assert.Equal(projectReference, value); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetVSTest") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuild") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetFormat") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var assembly = path.CombineWithFilePath("hwapp.tests/bin/Debug/net10.0/hwapp.tests.dll"); + var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); // When - DotNetVSTest(assembly.FullPath); + DotNetFormat(project.FullPath); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTool") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuild") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetListReference") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") .Does(() => { + // Given + var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); + var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); + var projectReference = FilePath.FromString("../hwapp.common/hwapp.common.csproj"); // When - DotNetTool("--info"); + var result = DotNetListReference(project.FullPath); + // Then + Assert.Contains(result, item => FilePath.FromString(item) == projectReference); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRun") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetVSTest") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRemoveReference") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); - + var project = path.CombineWithFilePath("hwapp.tests/hwapp.tests.csproj"); + var projectReferencePath = path.CombineWithFilePath("hwapp/hwapp.csproj"); + var projectReference = "..\\hwapp\\hwapp.csproj"; // When - DotNetRun(project.FullPath); + DotNetRemoveReference(project.FullPath, new[] { (FilePath)projectReferencePath.FullPath}); + var value = XmlPeek( + project.FullPath, + $"/Project/ItemGroup/ProjectReference[@Include='{projectReference}']/@Include" + ); + // Then + Assert.Null(value); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetPack") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRestore") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") .Does(() => { // Given - var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); - var outputPath = path.Combine("DotNetPack"); - var nuget = outputPath.CombineWithFilePath("hwapp.1.0.0.nupkg"); - var nugetSymbols = outputPath.CombineWithFilePath("hwapp.1.0.0.symbols.nupkg"); - EnsureDirectoryExist(outputPath); + var root = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); // When - DotNetPack(project.FullPath, new DotNetPackSettings { OutputDirectory = outputPath, IncludeSymbols = true }); + DotNetRestore(root.FullPath, new DotNetRestoreSettings { Verbosity = DotNetVerbosity.Minimal }); +}); - // Then - Assert.True(System.IO.File.Exists(nuget.FullPath), "Path:" + nuget.FullPath); - Assert.True(System.IO.File.Exists(nugetSymbols.FullPath), "Path:" + nugetSymbols.FullPath); +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSDKCheck") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") + .Does(() => +{ + // When + DotNetSDKCheck(); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetNuGetPush") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetPack") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnAdd") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var outputPath = path.Combine("DotNetPack"); - var nugetServerPath = path.Combine("DotNetPush"); - var nugetSource = outputPath.CombineWithFilePath("hwapp.1.0.0.nupkg"); - var nugetDestination = nugetServerPath.CombineWithFilePath("hwapp.1.0.0.nupkg"); - - EnsureDirectoryExist(outputPath); - EnsureDirectoryExist(nugetServerPath); - Assert.True(System.IO.File.Exists(nugetSource.FullPath), "Path:" + nugetSource.FullPath); - + var solution = path.CombineWithFilePath("hwapp.sln"); + var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); // When - DotNetNuGetPush(nugetSource.FullPath, new DotNetNuGetPushSettings { Source = nugetServerPath.FullPath }); + DotNetSlnAdd(solution.FullPath, new[] { (FilePath)project.FullPath}); +}); +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnList") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") + .Does(() => +{ + // Given + var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); + var solution = path.CombineWithFilePath("hwapp.sln"); + var project = new DirectoryPath("./hwapp.common").CombineWithFilePath("hwapp.common.csproj"); + // When + var result = DotNetSlnList(solution.FullPath); // Then - Assert.True(System.IO.File.Exists(nugetDestination.FullPath), "Path:" + nugetDestination.FullPath); + Assert.Contains(result, item => item == project); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetNuGetDelete") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetNuGetPush") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnRemove") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var nugetServerPath = path.Combine("DotNetPush"); - var nugetDestination = nugetServerPath.CombineWithFilePath("hwapp.1.0.0.nupkg"); - - EnsureDirectoryExist(nugetServerPath); - Assert.True(System.IO.File.Exists(nugetDestination.FullPath), "Path:" + nugetDestination.FullPath); - + var solution = path.CombineWithFilePath("hwapp.sln"); + var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); // When - DotNetNuGetDelete("hwapp", "1.0.0", new DotNetNuGetDeleteSettings { Source = nugetServerPath.FullPath, NonInteractive = true }); + DotNetSlnRemove(solution.FullPath, new[] { (FilePath)project.FullPath}); +}); - // Then - Assert.False(System.IO.File.Exists(nugetDestination.FullPath), "Path:" + nugetDestination.FullPath); +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadRepair") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") + .OnError(exception => { Console.WriteLine(exception); }) + .Does(() => +{ + // When + DotNetWorkloadRepair(); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetPublish") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadRestore") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); - var outputPath = path.Combine("DotNetPublish"); - var publishFiles = new [] { - outputPath.CombineWithFilePath("hwapp.common.dll"), - outputPath.CombineWithFilePath("hwapp.common.pdb"), - outputPath.CombineWithFilePath("hwapp.deps.json"), - outputPath.CombineWithFilePath("hwapp.dll"), - outputPath.CombineWithFilePath("hwapp.pdb"), - outputPath.CombineWithFilePath("hwapp.runtimeconfig.json") - }; - EnsureDirectoryExist(outputPath); + // When + DotNetWorkloadRestore(project.FullPath); +}); + +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadSearch") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") + .Does(() => +{ + // Given + var searchString = "maui"; // When - DotNetPublish(project.FullPath, new DotNetPublishSettings { OutputDirectory = outputPath }); + var workloads = DotNetWorkloadSearch(searchString); // Then - foreach (var file in publishFiles) + foreach (var workload in workloads) { - Assert.True(System.IO.File.Exists(file.FullPath), "Path:" + file.FullPath); + Assert.Contains("maui", workload.Id); + Assert.Contains(".NET MAUI SDK", workload.Description); } }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetExecute") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadUpdate") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") .Does(() => { - // Given - var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var assembly = path.CombineWithFilePath("hwapp/bin/Debug/net10.0/hwapp.dll"); - // When - DotNetExecute(assembly); + DotNetWorkloadUpdate(); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetClean") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuild") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuild") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRestore") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); var assembly = path.CombineWithFilePath("hwapp/bin/Debug/net10.0/hwapp.dll"); - Assert.True(System.IO.File.Exists(assembly.FullPath)); // When - DotNetClean(project.FullPath); + DotNetBuild(project.FullPath); // Then - Assert.False(System.IO.File.Exists(assembly.FullPath)); + Assert.True(System.IO.File.Exists(assembly.FullPath)); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetMSBuild") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetClean") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetListPackage") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRestore") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); - var assembly = path.CombineWithFilePath("hwapp/bin/Debug/net10.0/hwapp.dll"); - - // When (Verbosity.Quiet exercises MSBuild /verbosity, not dotnet --verbosity; see https://github.com/cake-build/cake/issues/4456) - DotNetMSBuild(project.FullPath, new DotNetMSBuildSettings { Verbosity = DotNetVerbosity.Quiet }); - + // When + DotNetRestore(project.FullPath); + var result = DotNetListPackage(project.FullPath); // Then - Assert.True(System.IO.File.Exists(assembly.FullPath)); + Assert.Equal(1, result.Version); + Assert.Contains(result.Projects, item => item.Path == project); }); Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetMSBuild.Results") @@ -251,25 +438,26 @@ Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetMSBuild.Results") Assert.Equal("Success", result.RootElement.GetProperty("TargetResults").GetProperty("Compile").GetProperty("Result").GetString()); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetMSBuildEmptyParametersAllowed") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetClean") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetClean") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuild") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetExecute") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); var assembly = path.CombineWithFilePath("hwapp/bin/Debug/net10.0/hwapp.dll"); + Assert.True(System.IO.File.Exists(assembly.FullPath)); - // When - empty string property value is allowed - DotNetMSBuild(project.FullPath, new DotNetMSBuildSettings() - .WithProperty("APropertyIWantTobeBlank", "")); + // When + DotNetClean(project.FullPath); // Then - Assert.True(System.IO.File.Exists(assembly.FullPath)); + Assert.False(System.IO.File.Exists(assembly.FullPath)); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest.Fail") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuild") .Does(() => { // Given @@ -277,102 +465,122 @@ Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest.Fail") var project = path.CombineWithFilePath("hwapp.tests/hwapp.tests.csproj"); // When - var exception = Record.Exception(()=>DotNetTest(project.FullPath, - new DotNetTestSettings { EnvironmentVariables = new Dictionary {{ "hwapp_fail_test", "true" }} - })); + DotNetTest(project.FullPath, new DotNetTestSettings { PathType = DotNetTestPathType.Project }); +}); - // Then - Assert.NotNull(exception); - Assert.IsType(exception); - Assert.Equal(".NET CLI: Process returned an error (exit code 2).",exception.Message); +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTool") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuild") + .Does(() => +{ + // When + DotNetTool("--info"); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetFormat") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetVSTest") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuild") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); + var assembly = path.CombineWithFilePath("hwapp.tests/bin/Debug/net10.0/hwapp.tests.dll"); // When - DotNetFormat(project.FullPath); + DotNetVSTest(assembly.FullPath); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSDKCheck") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetExecute") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") .Does(() => { + // Given + var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); + var assembly = path.CombineWithFilePath("hwapp/bin/Debug/net10.0/hwapp.dll"); + Assert.True(System.IO.File.Exists(assembly.FullPath)); + // When - DotNetSDKCheck(); + DotNetExecute(assembly); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadSearch") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetMSBuild") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetClean") .Does(() => { // Given - var searchString = "maui"; - - // When - var workloads = DotNetWorkloadSearch(searchString); + var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); + var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); + var assembly = path.CombineWithFilePath("hwapp/bin/Debug/net10.0/hwapp.dll"); - // Then - foreach (var workload in workloads) - { - Assert.Contains("maui", workload.Id); - Assert.Contains(".NET MAUI SDK", workload.Description); - } -}); + // When (Verbosity.Quiet exercises MSBuild /verbosity, not dotnet --verbosity; see https://github.com/cake-build/cake/issues/4456) + DotNetMSBuild(project.FullPath, new DotNetMSBuildSettings { Verbosity = DotNetVerbosity.Quiet }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadRepair") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") - .OnError(exception => { Console.WriteLine(exception); }) - .Does(() => -{ - // When - DotNetWorkloadRepair(); + // Then + Assert.True(System.IO.File.Exists(assembly.FullPath)); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadUpdate") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetMSBuildEmptyParametersAllowed") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetClean") .Does(() => { - // When - DotNetWorkloadUpdate(); + // Given + var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); + var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); + var assembly = path.CombineWithFilePath("hwapp/bin/Debug/net10.0/hwapp.dll"); + + // When - empty string property value is allowed + DotNetMSBuild(project.FullPath, new DotNetMSBuildSettings() + .WithProperty("APropertyIWantTobeBlank", "")); + + // Then + Assert.True(System.IO.File.Exists(assembly.FullPath)); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadRestore") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetPack") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); + var outputPath = path.Combine("DotNetPack"); + var nuget = outputPath.CombineWithFilePath("hwapp.1.0.0.nupkg"); + var nugetSymbols = outputPath.CombineWithFilePath("hwapp.1.0.0.symbols.nupkg"); + EnsureDirectoryExist(outputPath); // When - DotNetWorkloadRestore(project.FullPath); + DotNetPack(project.FullPath, new DotNetPackSettings { OutputDirectory = outputPath, IncludeSymbols = true }); + + // Then + Assert.True(System.IO.File.Exists(nuget.FullPath), "Path:" + nuget.FullPath); + Assert.True(System.IO.File.Exists(nugetSymbols.FullPath), "Path:" + nugetSymbols.FullPath); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetAddPackage") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetPublish") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); - var package = "Cake.Core"; + var outputPath = path.Combine("DotNetPublish"); + var publishFiles = new [] { + outputPath.CombineWithFilePath("hwapp.common.dll"), + outputPath.CombineWithFilePath("hwapp.common.pdb"), + outputPath.CombineWithFilePath("hwapp.deps.json"), + outputPath.CombineWithFilePath("hwapp.dll"), + outputPath.CombineWithFilePath("hwapp.pdb"), + outputPath.CombineWithFilePath("hwapp.runtimeconfig.json") + }; - // When - DotNetAddPackage(package, project.FullPath); + EnsureDirectoryExist(outputPath); - var value = XmlPeek( - project.FullPath, - $"/Project/ItemGroup/PackageReference[@Include='{package}']/@Include" - ); + // When + DotNetPublish(project.FullPath, new DotNetPublishSettings { OutputDirectory = outputPath }); // Then - Assert.Equal(package, value); + foreach (var file in publishFiles) + { + Assert.True(System.IO.File.Exists(file.FullPath), "Path:" + file.FullPath); + } }); Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRemovePackage") @@ -407,184 +615,121 @@ Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRemovePackage") Assert.Null(value); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetAddReference") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest.Fail") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); var project = path.CombineWithFilePath("hwapp.tests/hwapp.tests.csproj"); - var projectReferencePath = path.CombineWithFilePath("hwapp/hwapp.csproj"); - var projectReference = "..\\hwapp\\hwapp.csproj"; - // When - DotNetAddReference(project.FullPath, new[] { (FilePath)projectReferencePath.FullPath}); - var value = XmlPeek( - project.FullPath, - $"/Project/ItemGroup/ProjectReference[@Include='{projectReference}']/@Include" - ); - // Then - Assert.Equal(projectReference, value); -}); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetListReference") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") - .Does(() => -{ - // Given - var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); - var projectReference = FilePath.FromString("../hwapp.common/hwapp.common.csproj"); // When - var result = DotNetListReference(project.FullPath); + var exception = Record.Exception(()=>DotNetTest(project.FullPath, + new DotNetTestSettings { EnvironmentVariables = new Dictionary {{ "hwapp_fail_test", "true" }} + })); + // Then - Assert.Contains(result, item => FilePath.FromString(item) == projectReference); + Assert.NotNull(exception); + Assert.IsType(exception); + Assert.Equal(".NET CLI: Process returned an error (exit code 2).",exception.Message); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRemoveReference") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetNuGetPush") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetPack") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var project = path.CombineWithFilePath("hwapp.tests/hwapp.tests.csproj"); - var projectReferencePath = path.CombineWithFilePath("hwapp/hwapp.csproj"); - var projectReference = "..\\hwapp\\hwapp.csproj"; - // When - DotNetRemoveReference(project.FullPath, new[] { (FilePath)projectReferencePath.FullPath}); - var value = XmlPeek( - project.FullPath, - $"/Project/ItemGroup/ProjectReference[@Include='{projectReference}']/@Include" - ); - // Then - Assert.Null(value); -}); + var outputPath = path.Combine("DotNetPack"); + var nugetServerPath = path.Combine("DotNetPush"); + var nugetSource = outputPath.CombineWithFilePath("hwapp.1.0.0.nupkg"); + var nugetDestination = nugetServerPath.CombineWithFilePath("hwapp.1.0.0.nupkg"); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSearchPackage") - .Does(() => -{ - // Given - var package = "Cake.Tool"; + EnsureDirectoryExist(outputPath); + EnsureDirectoryExist(nugetServerPath); + Assert.True(System.IO.File.Exists(nugetSource.FullPath), "Path:" + nugetSource.FullPath); // When - var result = DotNetSearchPackage(package); + DotNetNuGetPush(nugetSource.FullPath, new DotNetNuGetPushSettings { Source = nugetServerPath.FullPath }); // Then - Assert.NotNull(result); - Assert.Contains(package, result.Select(x => x.Name)); -}); - -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSearchPackage.ExactMatch") - .Does(() => -{ - // Given: exact-match returns "version" in JSON (not "latestVersion"); see issue #4454 - var package = "Refit.Newtonsoft.Json"; - - // When - var result = DotNetSearchPackage(package, new DotNetPackageSearchSettings { ExactMatch = true }); - - // Then: every item must have non-null Version (fix for dotnet package search --exact-match --format json) - Assert.NotNull(result); - var list = result.ToList(); - Assert.NotEmpty(list); - foreach (var item in list) - { - Assert.NotNull(item.Name); - Assert.NotNull(item.Version); - Assert.Equal(package, item.Name); - } + Assert.True(System.IO.File.Exists(nugetDestination.FullPath), "Path:" + nugetDestination.FullPath); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetListPackage") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRestore") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRun") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetVSTest") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); - // When - DotNetRestore(project.FullPath); - var result = DotNetListPackage(project.FullPath); - // Then - Assert.Equal(1, result.Version); - Assert.Contains(result.Projects, item => item.Path == project); -}); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnList") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") - .Does(() => -{ - // Given - var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var solution = path.CombineWithFilePath("hwapp.sln"); - var project = new DirectoryPath("./hwapp.common").CombineWithFilePath("hwapp.common.csproj"); // When - var result = DotNetSlnList(solution.FullPath); - // Then - Assert.Contains(result, item => item == project); + DotNetRun(project.FullPath); }); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnAdd") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") +Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetNuGetDelete") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetNuGetPush") .Does(() => { // Given var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var solution = path.CombineWithFilePath("hwapp.sln"); - var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); - // When - DotNetSlnAdd(solution.FullPath, new[] { (FilePath)project.FullPath}); -}); + var nugetServerPath = path.Combine("DotNetPush"); + var nugetDestination = nugetServerPath.CombineWithFilePath("hwapp.1.0.0.nupkg"); + + EnsureDirectoryExist(nugetServerPath); + Assert.True(System.IO.File.Exists(nugetDestination.FullPath), "Path:" + nugetDestination.FullPath); -Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnRemove") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.Setup") - .Does(() => -{ - // Given - var path = Paths.Temp.Combine("./Cake.Common/Tools/DotNet"); - var solution = path.CombineWithFilePath("hwapp.sln"); - var project = path.CombineWithFilePath("hwapp/hwapp.csproj"); // When - DotNetSlnRemove(solution.FullPath, new[] { (FilePath)project.FullPath}); + DotNetNuGetDelete("hwapp", "1.0.0", new DotNetNuGetDeleteSettings { Source = nugetServerPath.FullPath, NonInteractive = true }); + + // Then + Assert.False(System.IO.File.Exists(nugetDestination.FullPath), "Path:" + nugetDestination.FullPath); }); Task("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuildServerShutdown") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSearchPackage") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSearchPackage.ExactMatch") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetToolExecute") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetToolInstallListRunUninstallLocal") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetToolInstallListRunUninstallLocalToolManifest") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetToolInstallListRunUninstallToolPath") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetAddPackage") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetAddReference") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetFormat") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetListReference") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRemoveReference") .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRestore") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSDKCheck") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnAdd") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnList") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnRemove") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadRepair") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadRestore") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadSearch") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadUpdate") .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuild") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetListPackage") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetMSBuild.Results") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetClean") .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetVSTest") .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTool") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRun") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetPack") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetNuGetPush") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetNuGetDelete") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetPublish") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetVSTest") .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetExecute") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetClean") .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetMSBuild") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetMSBuild.Results") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest.Fail") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetFormat") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSDKCheck") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadSearch") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadRepair") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadUpdate") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetWorkloadRestore") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetAddPackage") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetPack") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetPublish") .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRemovePackage") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSearchPackage") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSearchPackage.ExactMatch") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetListPackage") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetAddReference") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRemoveReference") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetListReference") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnList") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnAdd") - .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetSlnRemove") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetTest.Fail") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetNuGetPush") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetRun") + .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetNuGetDelete") .Does(() => { // When DotNetBuildServerShutdown(); -});; +}); Task("Cake.Common.Tools.DotNet.DotNetAliases") .IsDependentOn("Cake.Common.Tools.DotNet.DotNetAliases.DotNetBuildServerShutdown");