From cbe7adba44e3798c8fcfa6aee78bf55eed66e646 Mon Sep 17 00:00:00 2001 From: Roman Marusyk Date: Tue, 5 Apr 2022 20:50:35 +0300 Subject: [PATCH] Add alias for dotnet workload install command --- .../Install/DotNetWorkloadInstallerFixture.cs | 20 +++ .../Install/DotNetWorkloadInstallTests.cs | 131 ++++++++++++++++++ src/Cake.Common/Tools/DotNet/DotNetAliases.cs | 98 +++++++++++++ .../Install/DotNetWorkloadInstallSettings.cs | 63 +++++++++ .../Install/DotNetWorkloadInstaller.cs | 128 +++++++++++++++++ 5 files changed, 440 insertions(+) create mode 100644 src/Cake.Common.Tests/Fixtures/Tools/DotNet/Workload/Install/DotNetWorkloadInstallerFixture.cs create mode 100644 src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Install/DotNetWorkloadInstallTests.cs create mode 100644 src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstallSettings.cs create mode 100644 src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstaller.cs diff --git a/src/Cake.Common.Tests/Fixtures/Tools/DotNet/Workload/Install/DotNetWorkloadInstallerFixture.cs b/src/Cake.Common.Tests/Fixtures/Tools/DotNet/Workload/Install/DotNetWorkloadInstallerFixture.cs new file mode 100644 index 0000000000..8a541e9c05 --- /dev/null +++ b/src/Cake.Common.Tests/Fixtures/Tools/DotNet/Workload/Install/DotNetWorkloadInstallerFixture.cs @@ -0,0 +1,20 @@ +// 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.Common.Tools.DotNet.Workload.Install; + +namespace Cake.Common.Tests.Fixtures.Tools.DotNet.Workload.Install +{ + internal sealed class DotNetWorkloadInstallerFixture : DotNetFixture + { + public IEnumerable WorkloadIds { get; set; } + + protected override void RunTool() + { + var tool = new DotNetWorkloadInstaller(FileSystem, Environment, ProcessRunner, Tools); + tool.Install(WorkloadIds, Settings); + } + } +} diff --git a/src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Install/DotNetWorkloadInstallTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Install/DotNetWorkloadInstallTests.cs new file mode 100644 index 0000000000..fe2a1c6061 --- /dev/null +++ b/src/Cake.Common.Tests/Unit/Tools/DotNet/Workload/Install/DotNetWorkloadInstallTests.cs @@ -0,0 +1,131 @@ +// 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.Tests.Fixtures.Tools.DotNet.Workload.Install; +using Cake.Testing; +using Xunit; + +namespace Cake.Common.Tests.Unit.Tools.DotNet.Workload.Install +{ + public sealed class DotNetWorkloadInstallTests + { + public sealed class TheWorkloadInstallMethod + { + [Fact] + public void Should_Throw_If_Process_Was_Not_Started() + { + // Given + var fixture = new DotNetWorkloadInstallerFixture(); + fixture.WorkloadIds = new string[] { "maui" }; + fixture.GivenProcessCannotStart(); + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + AssertEx.IsCakeException(result, ".NET CLI: Process was not started."); + } + + [Fact] + public void Should_Throw_If_Process_Has_A_Non_Zero_Exit_Code() + { + // Given + var fixture = new DotNetWorkloadInstallerFixture(); + fixture.WorkloadIds = new string[] { "maui" }; + fixture.GivenProcessExitsWithCode(1); + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + AssertEx.IsCakeException(result, ".NET CLI: Process returned an error (exit code 1)."); + } + + [Fact] + public void Should_Add_WorkloadIds_Argument() + { + // Given + var fixture = new DotNetWorkloadInstallerFixture(); + fixture.WorkloadIds = new string[] { "maui-android", "maui-ios" }; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("workload install maui-android maui-ios", result.Args); + } + + [Fact] + public void Should_Throw_If_WorkloadIds_Is_Empty() + { + // Given + var fixture = new DotNetWorkloadInstallerFixture(); + fixture.WorkloadIds = new string[] { }; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + AssertEx.IsArgumentNullException(result, "workloadIds"); + } + + [Fact] + public void Should_Throw_If_WorkloadIds_Is_Null() + { + // Given + var fixture = new DotNetWorkloadInstallerFixture(); + fixture.WorkloadIds = null; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + AssertEx.IsArgumentNullException(result, "workloadIds"); + } + + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given + var fixture = new DotNetWorkloadInstallerFixture(); + fixture.WorkloadIds = new string[] { "maui" }; + fixture.Settings = null; + fixture.GivenDefaultToolDoNotExist(); + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + AssertEx.IsArgumentNullException(result, "settings"); + } + + [Fact] + public void Should_Add_Additional_Arguments() + { + // Given + var fixture = new DotNetWorkloadInstallerFixture(); + fixture.WorkloadIds = new string[] { "maui" }; + fixture.Settings.ConfigFile = "./nuget.config"; + fixture.Settings.DisableParallel = true; + fixture.Settings.IgnoreFailedSources = true; + fixture.Settings.IncludePreviews = true; + fixture.Settings.Interactive = true; + fixture.Settings.NoCache = true; + fixture.Settings.SkipManifestUpdate = true; + fixture.Settings.Source.Add("http://www.nuget.org/api/v2/package"); + fixture.Settings.Source.Add("http://www.symbolserver.org/"); + fixture.Settings.TempDir = "./src/project"; + fixture.Settings.Verbosity = Common.Tools.DotNet.DotNetVerbosity.Diagnostic; + + // When + var result = fixture.Run(); + + // Then + var expected = "workload install maui --configfile \"/Working/nuget.config\" --disable-parallel --ignore-failed-sources --include-previews --interactive --no-cache --skip-manifest-update"; + expected += " --source \"http://www.nuget.org/api/v2/package\" --source \"http://www.symbolserver.org/\" --temp-dir \"/Working/src/project\" --verbosity diagnostic"; + Assert.Equal(expected, result.Args); + } + } + } +} diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.cs index a5540defb2..b335c567cf 100644 --- a/src/Cake.Common/Tools/DotNet/DotNetAliases.cs +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.cs @@ -22,6 +22,7 @@ using Cake.Common.Tools.DotNet.Test; using Cake.Common.Tools.DotNet.Tool; using Cake.Common.Tools.DotNet.VSTest; +using Cake.Common.Tools.DotNet.Workload.Install; using Cake.Common.Tools.DotNet.Workload.Search; using Cake.Common.Tools.DotNet.Workload.Uninstall; using Cake.Common.Tools.DotNetCore.Build; @@ -1977,5 +1978,102 @@ public static void DotNetWorkloadUninstall(this ICakeContext context, IEnumerabl var uninstaller = new DotNetWorkloadUninstaller(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools); uninstaller.Uninstall(workloadIds); } + + /// + /// Installs a specified optional workload. + /// + /// The context. + /// The workload ID to install. + /// + /// + /// DotNetWorkloadInstall("maui"); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Workload")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Workload.Install")] + public static void DotNetWorkloadInstall(this ICakeContext context, string workloadId) + { + context.DotNetWorkloadInstall(workloadId, null); + } + + /// + /// Installs a specified optional workload. + /// + /// The context. + /// The workload ID to install. + /// The settings. + /// + /// + /// var settings = new DotNetWorkloadInstallSettings + /// { + /// IncludePreviews = true, + /// NoCache = true + /// }; + /// + /// DotNetWorkloadInstall("maui", settings); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Workload")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Workload.Install")] + public static void DotNetWorkloadInstall(this ICakeContext context, string workloadId, DotNetWorkloadInstallSettings settings) + { + context.DotNetWorkloadInstall(new string[] { workloadId }, settings); + } + + /// + /// Installs one or more optional workloads. + /// + /// The context. + /// The workload ID or multiple IDs to install. + /// + /// + /// DotNetWorkloadInstall(new string[] { "maui", "maui-desktop", "maui-mobile" }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Workload")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Workload.Install")] + public static void DotNetWorkloadInstall(this ICakeContext context, IEnumerable workloadIds) + { + context.DotNetWorkloadInstall(workloadIds, null); + } + + /// + /// Installs one or more optional workloads. + /// + /// The context. + /// The workload ID or multiple IDs to install. + /// The settings. + /// + /// + /// var settings = new DotNetWorkloadInstallSettings + /// { + /// IncludePreviews = true, + /// NoCache = true + /// }; + /// + /// DotNetWorkloadInstall(new string[] { "maui", "maui-desktop", "maui-mobile" }, settings); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Workload")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Workload.Install")] + public static void DotNetWorkloadInstall(this ICakeContext context, IEnumerable workloadIds, DotNetWorkloadInstallSettings settings) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (settings == null) + { + settings = new DotNetWorkloadInstallSettings(); + } + + var installer = new DotNetWorkloadInstaller(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools); + installer.Install(workloadIds, settings); + } } } diff --git a/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstallSettings.cs b/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstallSettings.cs new file mode 100644 index 0000000000..480b30cdbe --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstallSettings.cs @@ -0,0 +1,63 @@ +// 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.Workload.Install +{ + /// + /// Contains settings used by . + /// + public sealed class DotNetWorkloadInstallSettings : DotNetSettings + { + /// + /// Gets or sets the NuGet configuration file (nuget.config) to use. + /// + public FilePath ConfigFile { 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 allow prerelease workload manifests. + /// + public bool IncludePreviews { get; set; } + + /// + /// Gets or sets a value indicating whether to allow the command to stop and wait for user input or action. + /// For example, to complete authentication. + /// + public bool Interactive { get; set; } + + /// + /// Gets or sets a value indicating whether to do not cache packages and http requests. + /// + public bool NoCache { get; set; } + + /// + /// Gets or sets a value indicating whether to skip updating the workload manifests. + /// The workload manifests define what assets and versions need to be installed for each workload. + /// + public bool SkipManifestUpdate { get; set; } + + /// + /// Gets or sets the URI of the NuGet package source to use. + /// This setting overrides all of the sources specified in the nuget.config files. + /// + public ICollection Source { get; set; } = new List(); + + /// + /// Gets or sets the temporary directory used to download and extract NuGet packages (must be secure). + /// + public DirectoryPath TempDir { get; set; } + } +} diff --git a/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstaller.cs b/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstaller.cs new file mode 100644 index 0000000000..682d2f8299 --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/Workload/Install/DotNetWorkloadInstaller.cs @@ -0,0 +1,128 @@ +// 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.Core; +using Cake.Core.IO; +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.DotNet.Workload.Install +{ + /// + /// .NET workloads installer. + /// + public sealed class DotNetWorkloadInstaller : DotNetTool + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The file system. + /// The environment. + /// The process runner. + /// The tool locator. + public DotNetWorkloadInstaller( + IFileSystem fileSystem, + ICakeEnvironment environment, + IProcessRunner processRunner, + IToolLocator tools) : base(fileSystem, environment, processRunner, tools) + { + _environment = environment; + } + + /// + /// Lists the latest available version of the .NET SDK and .NET Runtime, for each feature band. + /// + /// The workload ID or multiple IDs to uninstall. + /// The settings. + public void Install(IEnumerable workloadIds, DotNetWorkloadInstallSettings settings) + { + if (workloadIds == null || !workloadIds.Any()) + { + throw new ArgumentNullException(nameof(workloadIds)); + } + + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + + RunCommand(settings, GetArguments(workloadIds, settings)); + } + + private ProcessArgumentBuilder GetArguments(IEnumerable workloadIds, DotNetWorkloadInstallSettings settings) + { + var builder = CreateArgumentBuilder(settings); + + builder.Append("workload install"); + + if (workloadIds != null && workloadIds.Any()) + { + builder.Append(string.Join(" ", workloadIds)); + } + + // Config File + if (settings.ConfigFile != null) + { + builder.AppendSwitchQuoted("--configfile", settings.ConfigFile.MakeAbsolute(_environment).FullPath); + } + + // Disable Parallel + if (settings.DisableParallel) + { + builder.Append("--disable-parallel"); + } + + // Ignore Failed Sources + if (settings.IgnoreFailedSources) + { + builder.Append("--ignore-failed-sources"); + } + + // Include Previews + if (settings.IncludePreviews) + { + builder.Append("--include-previews"); + } + + // Interactive + if (settings.Interactive) + { + builder.Append("--interactive"); + } + + // No Cache + if (settings.NoCache) + { + builder.Append("--no-cache"); + } + + // Skip Manifest Update + if (settings.SkipManifestUpdate) + { + builder.Append("--skip-manifest-update"); + } + + // Source + if (settings.Source != null && settings.Source.Any()) + { + foreach (var source in settings.Source) + { + builder.AppendSwitchQuoted("--source", source); + } + } + + // Temp Dir + if (settings.TempDir != null) + { + builder.AppendSwitchQuoted("--temp-dir", settings.TempDir.MakeAbsolute(_environment).FullPath); + } + + return builder; + } + } +}