winget-cli

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

commit 43af2815d3ea1ac1b8234199fb00ad6d36ad0149
parent c1a122e377e713b567f55d3864d1f1cf96f08aa8
Author: Ryan Fu <69221034+ryfu-msft@users.noreply.github.com>
Date:   Thu,  2 Jun 2022 14:26:07 -0700

Display InstallationNotes after a successful install (#2211)


Diffstat:
Mschemas/JSON/settings/settings.schema.0.2.json | 5+++++
Msrc/AppInstallerCLICore/ExecutionArgs.h | 2+-
Msrc/AppInstallerCLICore/Resources.h | 2++
Msrc/AppInstallerCLICore/Workflows/InstallFlow.cpp | 25++++++++++++++++++++-----
Msrc/AppInstallerCLICore/Workflows/InstallFlow.h | 6++++++
Msrc/AppInstallerCLICore/Workflows/ShowFlow.cpp | 5+++++
Msrc/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw | 6++++++
Msrc/AppInstallerCLITests/AppInstallerCLITests.vcxproj | 3+++
Msrc/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters | 3+++
Asrc/AppInstallerCLITests/TestData/InstallFlowTest_InstallationNotes.yaml | 16++++++++++++++++
Msrc/AppInstallerCLITests/WorkFlow.cpp | 20++++++++++++++++++++
Msrc/AppInstallerCommonCore/Public/winget/UserSettings.h | 2++
Msrc/AppInstallerCommonCore/UserSettings.cpp | 1+
13 files changed, 90 insertions(+), 6 deletions(-)

diff --git a/schemas/JSON/settings/settings.schema.0.2.json b/schemas/JSON/settings/settings.schema.0.2.json @@ -102,6 +102,11 @@ "type": "boolean", "default": false }, + "disableInstallNotes": { + "description": "Controls whether installation notes are shown after a successful install", + "type": "boolean", + "default": false + }, "PortablePackageUserRoot": { "description": "The default root directory where packages are installed to under User scope. Applies to the portable installer type.", "type": "string", diff --git a/src/AppInstallerCLICore/ExecutionArgs.h b/src/AppInstallerCLICore/ExecutionArgs.h @@ -92,7 +92,7 @@ namespace AppInstaller::CLI::Execution CustomHeader, // Optional Rest source header AcceptSourceAgreements, // Accept all source agreements IncludeUnknown, // Used in Upgrade command to allow upgrades of packages with unknown versions - Wait, // Prompts the user to press any key before exiting. + Wait, // Prompts the user to press any key before exiting // Used for demonstration purposes ExperimentalArg, diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h @@ -194,6 +194,7 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(NoPackageFound); WINGET_DEFINE_RESOURCE_STRINGID(NoPackageSelectionArgumentProvided); WINGET_DEFINE_RESOURCE_STRINGID(NoPackagesFoundInImportFile); + WINGET_DEFINE_RESOURCE_STRINGID(Notes); WINGET_DEFINE_RESOURCE_STRINGID(NoUninstallInfoFound); WINGET_DEFINE_RESOURCE_STRINGID(NoVTArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(OpenSourceFailedNoMatch); @@ -261,6 +262,7 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(ShowLabelDependencies); WINGET_DEFINE_RESOURCE_STRINGID(ShowLabelDescription); WINGET_DEFINE_RESOURCE_STRINGID(ShowLabelExternalDependencies); + WINGET_DEFINE_RESOURCE_STRINGID(ShowLabelInstallationNotes); WINGET_DEFINE_RESOURCE_STRINGID(ShowLabelInstaller); WINGET_DEFINE_RESOURCE_STRINGID(ShowLabelInstallerLocale); WINGET_DEFINE_RESOURCE_STRINGID(ShowLabelInstallerProductId); diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -24,7 +24,6 @@ using namespace AppInstaller::Manifest; using namespace AppInstaller::Repository; using namespace AppInstaller::Settings; using namespace AppInstaller::Utility; -using namespace AppInstaller::Utility::literals; namespace AppInstaller::CLI::Workflow { @@ -145,6 +144,20 @@ namespace AppInstaller::CLI::Workflow } } + void DisplayInstallationNotes(Execution::Context& context) + { + if (!Settings::User().Get<Settings::Setting::DisableInstallNotes>()) + { + const auto& manifest = context.Get<Execution::Data::Manifest>(); + auto installationNotes = manifest.CurrentLocalization.Get<AppInstaller::Manifest::Localization::InstallationNotes>(); + + if (!installationNotes.empty()) + { + context.Reporter.Info() << Resource::String::Notes << ' ' << installationNotes << std::endl; + } + } + } + void ShowPackageAgreements::operator()(Execution::Context& context) const { const auto& manifest = context.Get<Execution::Data::Manifest>(); @@ -381,7 +394,7 @@ namespace AppInstaller::CLI::Workflow auto returnResponseUrl = expectedReturnCodeItr->second.ReturnResponseUrl; if (!returnResponseUrl.empty()) { - context.Reporter.Error() << Resource::String::RelatedLink << ": "_liv << returnResponseUrl << std::endl; + context.Reporter.Error() << Resource::String::RelatedLink << ' ' << returnResponseUrl << std::endl; } AICLI_TERMINATE_CONTEXT(returnCode.HResult); @@ -412,7 +425,8 @@ namespace AppInstaller::CLI::Workflow Workflow::ReportExecutionStage(ExecutionStage::PostExecution) << Workflow::ReportARPChanges << Workflow::RecordInstall << - Workflow::RemoveInstaller; + Workflow::RemoveInstaller << + Workflow::DisplayInstallationNotes; } void DownloadSinglePackage(Execution::Context& context) @@ -487,8 +501,9 @@ namespace AppInstaller::CLI::Workflow { installContext << Workflow::ManagePackageDependencies(m_dependenciesReportMessage); } - installContext << Workflow::DownloadInstaller; - installContext << Workflow::InstallPackageInstaller; + installContext << + Workflow::DownloadInstaller << + Workflow::InstallPackageInstaller; } catch (...) { diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.h b/src/AppInstallerCLICore/Workflows/InstallFlow.h @@ -23,6 +23,12 @@ namespace AppInstaller::CLI::Workflow // Outputs: None void ShowInstallationDisclaimer(Execution::Context& context); + // Displays the installations notes after a successful install. + // Required Args: None + // Inputs: InstallationNotes + // Outputs: None + void DisplayInstallationNotes(Execution::Context& context); + // Shows the license agreements if the application has them. // Required Args: None // Inputs: Manifest diff --git a/src/AppInstallerCLICore/Workflows/ShowFlow.cpp b/src/AppInstallerCLICore/Workflows/ShowFlow.cpp @@ -90,6 +90,11 @@ namespace AppInstaller::CLI::Workflow { info << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelReleaseNotesUrl << ' ' << releaseNotesUrl << std::endl; } + auto installationNotes = manifest.CurrentLocalization.Get<Manifest::Localization::InstallationNotes>(); + if (!installationNotes.empty()) + { + info << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstallationNotes << ' ' << installationNotes << std::endl; + } auto agreements = manifest.CurrentLocalization.Get<Manifest::Localization::Agreements>(); if (!agreements.empty()) { diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -1340,4 +1340,10 @@ Please specify one of them using the `--source` option to proceed.</value> <data name="RelatedLink" xml:space="preserve"> <value>Related Link</value> </data> + <data name="Notes" xml:space="preserve"> + <value>Notes:</value> + </data> + <data name="ShowLabelInstallationNotes" xml:space="preserve"> + <value>InstallationNotes:</value> + </data> </root> \ No newline at end of file diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -267,6 +267,9 @@ <CopyFileToFolders Include="TestData\InstallFlowTest_ExpectedReturnCodes.yaml"> <DeploymentContent>true</DeploymentContent> </CopyFileToFolders> + <CopyFileToFolders Include="TestData\InstallFlowTest_InstallationNotes.yaml"> + <DeploymentContent>true</DeploymentContent> + </CopyFileToFolders> <CopyFileToFolders Include="TestData\InstallFlowTest_Portable.yaml"> <DeploymentContent>true</DeploymentContent> </CopyFileToFolders> diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -444,6 +444,9 @@ <CopyFileToFolders Include="TestData\InstallFlowTest_ExpectedReturnCodes.yaml"> <Filter>TestData</Filter> </CopyFileToFolders> + <CopyFileToFolders Include="TestData\InstallFlowTest_InstallationNotes.yaml"> + <Filter>TestData</Filter> + </CopyFileToFolders> <CopyFileToFolders Include="TestData\InstallFlowTest_Portable.yaml"> <Filter>TestData</Filter> </CopyFileToFolders> diff --git a/src/AppInstallerCLITests/TestData/InstallFlowTest_InstallationNotes.yaml b/src/AppInstallerCLITests/TestData/InstallFlowTest_InstallationNotes.yaml @@ -0,0 +1,16 @@ +PackageIdentifier: AppInstallerCliTest.TestInstaller +PackageVersion: 1.0.0.0 +PackageLocale: en-US +PackageName: AppInstaller Test Installer +ShortDescription: AppInstaller Test Installer +Publisher: Microsoft Corporation +Moniker: AICLITestExe +License: Test +InstallationNotes: testInstallationNotes +Installers: + - Architecture: x86 + InstallerUrl: https://ThisIsNotUsed + InstallerType: exe + InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B +ManifestType: singleton +ManifestVersion: 1.2.0 diff --git a/src/AppInstallerCLITests/WorkFlow.cpp b/src/AppInstallerCLITests/WorkFlow.cpp @@ -795,6 +795,26 @@ TEST_CASE("InstallFlowNonZeroExitCode", "[InstallFlow][workflow]") REQUIRE(installResultStr.find("/silentwithprogress") != std::string::npos); } +TEST_CASE("InstallFlow_InstallationNotes", "[InstallFlow][workflow]") +{ + TestCommon::TempFile installResultPath("TestExeInstalled.txt"); + + std::ostringstream installOutput; + TestContext context{ installOutput, std::cin }; + auto previousThreadGlobals = context.SetForCurrentThread(); + OverrideForShellExecute(context); + context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_InstallationNotes.yaml").GetPath().u8string()); + + InstallCommand install({}); + install.Execute(context); + INFO(installOutput.str()); + + // Verify installation notes are displayed + REQUIRE(context.GetTerminationHR() == S_OK); + REQUIRE(std::filesystem::exists(installResultPath.GetPath())); + REQUIRE(installOutput.str().find("testInstallationNotes") != std::string::npos); +} + TEST_CASE("InstallFlow_ExpectedReturnCodes", "[InstallFlow][workflow]") { TestCommon::TempFile installResultPath("TestExeInstalled.txt"); diff --git a/src/AppInstallerCommonCore/Public/winget/UserSettings.h b/src/AppInstallerCommonCore/Public/winget/UserSettings.h @@ -87,6 +87,7 @@ namespace AppInstaller::Settings EnableSelfInitiatedMinidump, LoggingLevelPreference, InstallIgnoreWarnings, + DisableInstallNotes, PortableAppUserRoot, PortableAppMachineRoot, UninstallPurgePortablePackage, @@ -139,6 +140,7 @@ namespace AppInstaller::Settings SETTINGMAPPING_SPECIALIZATION(Setting::InstallLocalePreference, std::vector<std::string>, std::vector<std::string>, {}, ".installBehavior.preferences.locale"sv); SETTINGMAPPING_SPECIALIZATION(Setting::InstallLocaleRequirement, std::vector<std::string>, std::vector<std::string>, {}, ".installBehavior.requirements.locale"sv); SETTINGMAPPING_SPECIALIZATION(Setting::InstallIgnoreWarnings, bool, bool, false, ".installBehavior.ignoreWarnings"sv); + SETTINGMAPPING_SPECIALIZATION(Setting::DisableInstallNotes, bool, bool, false, ".installBehavior.disableInstallNotes"sv); SETTINGMAPPING_SPECIALIZATION(Setting::PortableAppUserRoot, std::string, std::filesystem::path, {}, ".installBehavior.portableAppUserRoot"sv); SETTINGMAPPING_SPECIALIZATION(Setting::PortableAppMachineRoot, std::string, std::filesystem::path, {}, ".installBehavior.portableAppMachineRoot"sv); SETTINGMAPPING_SPECIALIZATION(Setting::UninstallPurgePortablePackage, bool, bool, false, ".uninstallBehavior.purgePortablePackage"sv); diff --git a/src/AppInstallerCommonCore/UserSettings.cpp b/src/AppInstallerCommonCore/UserSettings.cpp @@ -239,6 +239,7 @@ namespace AppInstaller::Settings WINGET_VALIDATE_PASS_THROUGH(EFDirectMSI) WINGET_VALIDATE_PASS_THROUGH(EnableSelfInitiatedMinidump) WINGET_VALIDATE_PASS_THROUGH(InstallIgnoreWarnings) + WINGET_VALIDATE_PASS_THROUGH(DisableInstallNotes) WINGET_VALIDATE_PASS_THROUGH(UninstallPurgePortablePackage) WINGET_VALIDATE_SIGNATURE(PortableAppUserRoot)