diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs index e1c398c655..c223e4ebb5 100644 --- a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs @@ -360,20 +360,12 @@ public IReadOnlyList GetAvailableUpdates_UnSafe() Manager ); - if (!WinGetPkgOperationHelper.UpdateAlreadyInstalled(UniGetUIPackage)) - { - NativePackageHandler.AddPackage(UniGetUIPackage, nativePackage); - packages.Add(UniGetUIPackage); - logger.Log( - $"Found package {nativePackage.Name} {nativePackage.Id} on source {source.Name}, from version {version} to version {nativePackage.DefaultInstallVersion.Version}" - ); - } - else - { - Logger.Warn( - $"WinGet package {nativePackage.Id} not being shown as an updated as this version has already been marked as installed" - ); - } + // Trust COM IsUpdateAvailable, not the "already upgraded" cache (issue #5042). + NativePackageHandler.AddPackage(UniGetUIPackage, nativePackage); + packages.Add(UniGetUIPackage); + logger.Log( + $"Found package {nativePackage.Name} {nativePackage.Id} on source {source.Name}, from version {version} to version {nativePackage.DefaultInstallVersion.Version}" + ); } catch (Exception ex) { diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs index fb7612638c..b43532a053 100644 --- a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/PingetCliHelper.cs @@ -58,7 +58,7 @@ public IReadOnlyList GetAvailableUpdates_UnSafe() Manager ); - if (!WinGetPkgOperationHelper.UpdateAlreadyInstalled(package)) + if (!WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)) { packages.Add(package); } diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetCliHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetCliHelper.cs index 1ee0bdaebd..0e8c22df63 100644 --- a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetCliHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/WinGetCliHelper.cs @@ -156,7 +156,7 @@ public IReadOnlyList GetAvailableUpdates_UnSafe() } var package = new Package(name, id, version, newVersion, source, Manager); - if (!WinGetPkgOperationHelper.UpdateAlreadyInstalled(package)) + if (!WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)) { Packages.Add(package); } diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs index 66e770c9c7..71641d6728 100644 --- a/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/Helpers/WinGetPkgOperationHelper.cs @@ -389,6 +389,25 @@ public static bool UpdateAlreadyInstalled(IPackage package) ) == package.NewVersionString; } + public static void ClearUpgradeMark(IPackage package) + { + Settings.RemoveDictionaryKey( + Settings.K.WinGetAlreadyUpgradedPackages, + package.Id + ); + } + + // One-shot suppression: hide a just-upgraded package once (bridges CLI index lag), then clear + // the mark so a still-outdated package reappears next scan instead of forever (issue #5042). + public static bool ConsumeAlreadyUpgradedSuppression(IPackage package) + { + if (!UpdateAlreadyInstalled(package)) + return false; + + ClearUpgradeMark(package); + return true; + } + public static string GetLastInstalledVersion(string id) { var val = Settings.GetDictionaryItem( diff --git a/src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs b/src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs index 2365d7e27c..85afe2119b 100644 --- a/src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs +++ b/src/UniGetUI.PackageEngine.Tests/WinGetManagerTests.cs @@ -1016,6 +1016,74 @@ public void WinGetGenericPingetFailureDoesNotRetry() Assert.False(package.OverridenOptions.WinGet_DropArchAndScope); } + [Fact] + public void ConsumeAlreadyUpgradedSuppression_HidesOnceThenRevealsOnNextScan() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.OneShot") + .WithVersion("1.0.0") + .WithNewVersion("2.0.0") + .Build(); + + // Simulate a completed upgrade to 2.0.0 (as MarkUpgradeAsDone records it). + Settings.SetDictionaryItem( + Settings.K.WinGetAlreadyUpgradedPackages, + package.Id, + "2.0.0" + ); + + // First scan hides the still-listed update once, then consumes the mark... + Assert.True(WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)); + Assert.False(WinGetPkgOperationHelper.UpdateAlreadyInstalled(package)); + + // ...so a genuinely-outdated package (no-op upgrade) reappears next scan (issue #5042). + Assert.False(WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)); + } + + [Fact] + public void ConsumeAlreadyUpgradedSuppression_DoesNotHideDifferentAvailableVersion() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.NewerUpdate") + .WithVersion("1.0.0") + .WithNewVersion("3.0.0") + .Build(); + + // A mark from a previous upgrade to a different version must never hide a new update. + Settings.SetDictionaryItem( + Settings.K.WinGetAlreadyUpgradedPackages, + package.Id, + "2.0.0" + ); + + Assert.False(WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)); + Assert.Equal( + "2.0.0", + Settings.GetDictionaryItem( + Settings.K.WinGetAlreadyUpgradedPackages, + package.Id + ) + ); + } + + [Fact] + public void ConsumeAlreadyUpgradedSuppression_NoMarkNeverHides() + { + var manager = new WinGet(); + var package = new PackageBuilder() + .WithManager(manager) + .WithId("Contoso.NoMark") + .WithVersion("1.0.0") + .WithNewVersion("2.0.0") + .Build(); + + Assert.False(WinGetPkgOperationHelper.ConsumeAlreadyUpgradedSuppression(package)); + } + private static void SetCliToolKind(WinGet manager, WinGetCliToolKind kind) { typeof(WinGet)