diff --git a/schemas/JSON/settings/settings.schema.0.2.json b/schemas/JSON/settings/settings.schema.0.2.json index 50cb8d1894..47f6fcdf43 100644 --- 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 index f75b351918..c160cb1688 100644 --- 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 index 111a0dff63..eb767202a9 100644 --- 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 index 09d1f7d684..b6b8fcc594 100644 --- 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()) + { + const auto& manifest = context.Get(); + auto installationNotes = manifest.CurrentLocalization.Get(); + + if (!installationNotes.empty()) + { + context.Reporter.Info() << Resource::String::Notes << ' ' << installationNotes << std::endl; + } + } + } + void ShowPackageAgreements::operator()(Execution::Context& context) const { const auto& manifest = context.Get(); @@ -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 index 640d90305f..8872f86af3 100644 --- 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 index fdf0e9dad5..9dab392f53 100644 --- 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(); + if (!installationNotes.empty()) + { + info << Execution::ManifestInfoEmphasis << Resource::String::ShowLabelInstallationNotes << ' ' << installationNotes << std::endl; + } auto agreements = manifest.CurrentLocalization.Get(); if (!agreements.empty()) { diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index 3a3a24aaab..9c6ddce42f 100644 --- 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. Related Link + + Notes: + + + InstallationNotes: + \ No newline at end of file diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj index 04a985704d..e7c6a57cc4 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -267,6 +267,9 @@ true + + true + true diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters index 092f901c9d..66a35c91b0 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -444,6 +444,9 @@ TestData + + TestData + TestData diff --git a/src/AppInstallerCLITests/TestData/InstallFlowTest_InstallationNotes.yaml b/src/AppInstallerCLITests/TestData/InstallFlowTest_InstallationNotes.yaml new file mode 100644 index 0000000000..730e433fe2 --- /dev/null +++ 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 index b7b4a41a5f..7b93d5808a 100644 --- 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 index f215db2baa..747b8f711b 100644 --- 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::vector, {}, ".installBehavior.preferences.locale"sv); SETTINGMAPPING_SPECIALIZATION(Setting::InstallLocaleRequirement, std::vector, std::vector, {}, ".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 index 799714d509..49e3e178cc 100644 --- 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)