winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 077cf644438980e6eccfe1742abca65595aeb7b6
parent 9fb9458dcfc3899a3fb2138584f73d11b11708ba
Author: Ryan <69221034+ryfu-msft@users.noreply.github.com>
Date:   Wed, 13 Sep 2023 16:02:01 -0700

make windows feature experimental (#3620)


Diffstat:
Mdoc/Settings.md | 11+++++++++++
Mschemas/JSON/settings/settings.schema.0.2.json | 5+++++
Msrc/AppInstallerCLICore/Workflows/DependenciesFlow.cpp | 5+++++
Msrc/AppInstallerCLIE2ETests/FeaturesCommand.cs | 1+
Msrc/AppInstallerCLIE2ETests/InstallCommand.cs | 9+++++++++
Msrc/AppInstallerCLITests/WindowsFeature.cpp | 15+++++++++++++++
Msrc/AppInstallerCommonCore/ExperimentalFeature.cpp | 4++++
Msrc/AppInstallerCommonCore/Public/winget/ExperimentalFeature.h | 1+
Msrc/AppInstallerCommonCore/Public/winget/UserSettings.h | 2++
Msrc/AppInstallerCommonCore/UserSettings.cpp | 1+
10 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/doc/Settings.md b/doc/Settings.md @@ -272,4 +272,15 @@ You can enable the feature as shown below. "experimentalFeatures": { "configuration": true }, +``` + +### windowsFeature + +This feature enables the ability to enable Windows Feature dependencies during installation. +You can enable the feature as shown below. + +```json + "experimentalFeatures": { + "windowsFeature": true + }, ``` \ No newline at end of file diff --git a/schemas/JSON/settings/settings.schema.0.2.json b/schemas/JSON/settings/settings.schema.0.2.json @@ -241,6 +241,11 @@ "description": "Enable support for configuration", "type": "boolean", "default": false + }, + "windowsFeature": { + "description": "Enable support for enabling Windows Feature(s)", + "type": "boolean", + "default": false } } } diff --git a/src/AppInstallerCLICore/Workflows/DependenciesFlow.cpp b/src/AppInstallerCLICore/Workflows/DependenciesFlow.cpp @@ -129,6 +129,11 @@ namespace AppInstaller::CLI::Workflow void EnableWindowsFeaturesDependencies(Execution::Context& context) { + if (!Settings::ExperimentalFeature::IsEnabled(Settings::ExperimentalFeature::Feature::WindowsFeature)) + { + return; + } + const auto& rootDependencies = context.Get<Execution::Data::Installer>()->Dependencies; if (rootDependencies.Empty()) diff --git a/src/AppInstallerCLIE2ETests/FeaturesCommand.cs b/src/AppInstallerCLIE2ETests/FeaturesCommand.cs @@ -53,6 +53,7 @@ namespace AppInstallerCLIE2ETests WinGetSettingsHelper.ConfigureFeature("experimentalArg", true); WinGetSettingsHelper.ConfigureFeature("experimentalCmd", true); WinGetSettingsHelper.ConfigureFeature("directMSI", true); + WinGetSettingsHelper.ConfigureFeature("windowsFeature", true); var result = TestCommon.RunAICLICommand("features", string.Empty); Assert.True(result.StdOut.Contains("Enabled")); } diff --git a/src/AppInstallerCLIE2ETests/InstallCommand.cs b/src/AppInstallerCLIE2ETests/InstallCommand.cs @@ -17,6 +17,15 @@ namespace AppInstallerCLIE2ETests public class InstallCommand : BaseCommand { /// <summary> + /// One time setup. + /// </summary> + [OneTimeSetUp] + public void OneTimeSetup() + { + WinGetSettingsHelper.ConfigureFeature("windowsFeature", true); + } + + /// <summary> /// Set up. /// </summary> [SetUp] diff --git a/src/AppInstallerCLITests/WindowsFeature.cpp b/src/AppInstallerCLITests/WindowsFeature.cpp @@ -24,6 +24,9 @@ TEST_CASE("InstallFlow_WindowsFeatureDoesNotExist", "[windowsFeature]") TestCommon::TempFile installResultPath("TestExeInstalled.txt"); + TestCommon::TestUserSettings testSettings; + testSettings.Set<Setting::EFWindowsFeature>(true); + std::ostringstream installOutput; TestContext context{ installOutput, std::cin }; auto previousThreadGlobals = context.SetForCurrentThread(); @@ -57,6 +60,9 @@ TEST_CASE("InstallFlow_FailedToEnableWindowsFeature", "[windowsFeature]") TestCommon::TempFile installResultPath("TestExeInstalled.txt"); + TestCommon::TestUserSettings testSettings; + testSettings.Set<Setting::EFWindowsFeature>(true); + std::ostringstream installOutput; TestContext context{ installOutput, std::cin }; auto previousThreadGlobals = context.SetForCurrentThread(); @@ -92,6 +98,9 @@ TEST_CASE("InstallFlow_FailedToEnableWindowsFeature_Force", "[windowsFeature]") TestCommon::TempFile installResultPath("TestExeInstalled.txt"); + TestCommon::TestUserSettings testSettings; + testSettings.Set<Setting::EFWindowsFeature>(true); + // Override with arbitrary DISM api error (DISMAPI_E_DISMAPI_NOT_INITIALIZED) and make windows feature discoverable. HRESULT dismErrorResult = 0xc0040001; LocIndString testFeatureDisplayName = LocIndString{ "Test Windows Feature"_liv }; @@ -139,6 +148,9 @@ TEST_CASE("InstallFlow_RebootRequired", "[windowsFeature]") TestCommon::TempFile installResultPath("TestExeInstalled.txt"); + TestCommon::TestUserSettings testSettings; + testSettings.Set<Setting::EFWindowsFeature>(true); + // Override with reboot required HRESULT. auto mockDismHelperOverride = TestHook::MockDismHelper_Override(); auto setEnableFeatureOverride = TestHook::SetEnableWindowsFeatureResult_Override(ERROR_SUCCESS_REBOOT_REQUIRED); @@ -173,6 +185,9 @@ TEST_CASE("InstallFlow_RebootRequired_Force", "[windowsFeature]") TestCommon::TempFile installResultPath("TestExeInstalled.txt"); + TestCommon::TestUserSettings testSettings; + testSettings.Set<Setting::EFWindowsFeature>(true); + // Override with reboot required HRESULT. auto mockDismHelperOverride = TestHook::MockDismHelper_Override(); auto setEnableFeatureOverride = TestHook::SetEnableWindowsFeatureResult_Override(ERROR_SUCCESS_REBOOT_REQUIRED); diff --git a/src/AppInstallerCommonCore/ExperimentalFeature.cpp b/src/AppInstallerCommonCore/ExperimentalFeature.cpp @@ -40,6 +40,8 @@ namespace AppInstaller::Settings return userSettings.Get<Setting::EFExperimentalArg>(); case ExperimentalFeature::Feature::DirectMSI: return userSettings.Get<Setting::EFDirectMSI>(); + case ExperimentalFeature::Feature::WindowsFeature: + return userSettings.Get<Setting::EFWindowsFeature>(); default: THROW_HR(E_UNEXPECTED); } @@ -69,6 +71,8 @@ namespace AppInstaller::Settings return ExperimentalFeature{ "Argument Sample", "experimentalArg", "https://aka.ms/winget-settings", Feature::ExperimentalArg }; case Feature::DirectMSI: return ExperimentalFeature{ "Direct MSI Installation", "directMSI", "https://aka.ms/winget-settings", Feature::DirectMSI }; + case Feature::WindowsFeature: + return ExperimentalFeature{ "Windows Feature Dependencies", "windowsFeature", "https://aka.ms/winget-settings", Feature::WindowsFeature }; default: THROW_HR(E_UNEXPECTED); } diff --git a/src/AppInstallerCommonCore/Public/winget/ExperimentalFeature.h b/src/AppInstallerCommonCore/Public/winget/ExperimentalFeature.h @@ -23,6 +23,7 @@ namespace AppInstaller::Settings None = 0x0, // Before making DirectMSI non-experimental, it should be part of manifest validation. DirectMSI = 0x1, + WindowsFeature = 0x2, Max, // This MUST always be after all experimental features // Features listed after Max will not be shown with the features command diff --git a/src/AppInstallerCommonCore/Public/winget/UserSettings.h b/src/AppInstallerCommonCore/Public/winget/UserSettings.h @@ -70,6 +70,7 @@ namespace AppInstaller::Settings EFExperimentalCmd, EFExperimentalArg, EFDirectMSI, + EFWindowsFeature, // Telemetry TelemetryDisable, // Install behavior @@ -145,6 +146,7 @@ namespace AppInstaller::Settings SETTINGMAPPING_SPECIALIZATION(Setting::EFExperimentalCmd, bool, bool, false, ".experimentalFeatures.experimentalCmd"sv); SETTINGMAPPING_SPECIALIZATION(Setting::EFExperimentalArg, bool, bool, false, ".experimentalFeatures.experimentalArg"sv); SETTINGMAPPING_SPECIALIZATION(Setting::EFDirectMSI, bool, bool, false, ".experimentalFeatures.directMSI"sv); + SETTINGMAPPING_SPECIALIZATION(Setting::EFWindowsFeature, bool, bool, false, ".experimentalFeatures.windowsFeature"sv); // Telemetry SETTINGMAPPING_SPECIALIZATION(Setting::TelemetryDisable, bool, bool, false, ".telemetry.disable"sv); // Install behavior diff --git a/src/AppInstallerCommonCore/UserSettings.cpp b/src/AppInstallerCommonCore/UserSettings.cpp @@ -259,6 +259,7 @@ namespace AppInstaller::Settings WINGET_VALIDATE_PASS_THROUGH(EFExperimentalCmd) WINGET_VALIDATE_PASS_THROUGH(EFExperimentalArg) WINGET_VALIDATE_PASS_THROUGH(EFDirectMSI) + WINGET_VALIDATE_PASS_THROUGH(EFWindowsFeature) WINGET_VALIDATE_PASS_THROUGH(AnonymizePathForDisplay) WINGET_VALIDATE_PASS_THROUGH(TelemetryDisable) WINGET_VALIDATE_PASS_THROUGH(InteractivityDisable)