diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h index 771e42568e..2c28feb70b 100644 --- a/src/AppInstallerCLICore/Resources.h +++ b/src/AppInstallerCLICore/Resources.h @@ -507,7 +507,7 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(UpdateNoPackagesFound); WINGET_DEFINE_RESOURCE_STRINGID(UpdateNoPackagesFoundReason); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeAvailableForPinned); - WINGET_DEFINE_RESOURCE_STRINGID(UpgradeBlockingPinCount); + WINGET_DEFINE_RESOURCE_STRINGID(UpgradeBlockedByPinCount); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeCommandLongDescription); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeDifferentInstallTechnology); diff --git a/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp b/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp index 2f4f693dde..319d866ea1 100644 --- a/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp +++ b/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp @@ -728,10 +728,16 @@ namespace AppInstaller::CLI::Workflow std::vector lines; std::vector linesForExplicitUpgrade; + std::vector linesForPins; int availableUpgradesCount = 0; + + // We will show a line with a summary for skipped and pinned packages at the end. + // The strings suggest using a --include-unknown/pinned argument, so we should + // ensure that the count is 0 when using the arguments. int packagesWithUnknownVersionSkipped = 0; int packagesWithUserPinsSkipped = 0; + auto &source = context.Get(); bool shouldShowSource = source.IsComposite() && source.GetAvailableSources().size() > 1; @@ -755,6 +761,7 @@ namespace AppInstaller::CLI::Workflow { auto latestVersion = match.Package->GetLatestAvailableVersion(pinBehavior); bool updateAvailable = match.Package->IsUpdateAvailable(pinBehavior); + bool updateIsPinned = false; if (m_onlyShowUpgrades && !context.Args.Contains(Execution::Args::Type::IncludeUnknown) && Utility::Version(installedVersion->GetProperty(PackageVersionProperty::Version)).IsUnknown() && updateAvailable) { @@ -768,8 +775,21 @@ namespace AppInstaller::CLI::Workflow bool updateAvailableWithoutPins = match.Package->IsUpdateAvailable(PinBehavior::IgnorePins); if (updateAvailableWithoutPins) { - ++packagesWithUserPinsSkipped; - continue; + // When given the --include-pinned argument, report blocking and gating pins in a separate table. + // Otherwise, simply show a count of them + if (context.Args.Contains(Execution::Args::Type::IncludePinned)) + { + updateIsPinned = true; + + // Override these so we generate the table line below. + latestVersion = match.Package->GetLatestAvailableVersion(PinBehavior::IgnorePins); + updateAvailable = true; + } + else + { + ++packagesWithUserPinsSkipped; + continue; + } } } @@ -802,7 +822,11 @@ namespace AppInstaller::CLI::Workflow ); auto pinnedState = ConvertToPinTypeEnum(installedVersion->GetMetadata()[PackageVersionMetadata::PinnedState]); - if (m_onlyShowUpgrades && pinnedState == PinType::PinnedByManifest) + if (updateIsPinned) + { + linesForPins.push_back(std::move(line)); + } + else if (m_onlyShowUpgrades && pinnedState == PinType::PinnedByManifest) { linesForExplicitUpgrade.push_back(std::move(line)); } @@ -839,6 +863,12 @@ namespace AppInstaller::CLI::Workflow OutputInstalledPackagesTable(context, linesForExplicitUpgrade); } + if (!linesForPins.empty()) + { + context.Reporter.Info() << std::endl << Resource::String::UpgradeBlockedByPinCount(linesForPins.size()) << std::endl; + OutputInstalledPackagesTable(context, linesForPins); + } + if (m_onlyShowUpgrades) { if (packagesWithUnknownVersionSkipped > 0) diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw index 853c4340eb..31c66b4d37 100644 --- a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +++ b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -1684,9 +1684,9 @@ Please specify one of them using the --source option to proceed. Search failed for: {0} {Locked="{0}"} Error message displayed when the user attempts to search for multiple application packages and one of the searches fails. This message is for generic failures, we have more specific messages for when the search returns no results, or when it returns more than one result. {0} is a placeholder replaced by the package name or query. - - {0} package(s) have a blocking pin that needs to be removed before upgrade - {Locked="{0}"} {0} is a placeholder that is replaced by an integer number of packages with blocking pins + + {0} package(s) have a pin that needs to be removed before upgrade + {Locked="{0}"} {0} is a placeholder that is replaced by an integer number of packages with pins that prevent upgrade Upgrade packages even if they have a non-blocking pin