Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added argument to control whether to upgrade packages if they have "unknown" versions #1765

Merged
merged 12 commits into from
Dec 9, 2021

Conversation

jedieaston
Copy link
Contributor

@jedieaston jedieaston commented Dec 2, 2021


Related to #1692.

This PR adds a argument, --include-unknown, to winget upgrade. This argument controls whether to evaluate packages for upgrade if they have "Unknown" versions (basically, if the version is not set in the ARP table). This resolves a lot of user confusion where every time they run winget upgrade --all, packages will be upgraded regardless of whether they actually need it because winget is not sure if it needs an upgrade or not.

I know nobody from MS commented on that issue, so if anyone has issues with this solution, I'm happy to redo this. The issue also has some discussion on whether or not upgrades for unknown packages should be shown by default in the upgrade table. The way I have it, the argument must be used for the upgrade to show in the table.

Tested: manually. As always, I'm happy to write unit tests if needed.

image

Microsoft Reviewers: Open in CodeFlow

@jedieaston jedieaston requested a review from a team as a code owner December 2, 2021 16:56
Copy link
Member

@JohnMcPMS JohnMcPMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@denelon , does this seem like fine behavior to you? Nothing springs to mind as to why we wouldn't want it.

@lechacon , does there need to be additional work done for import? It does upgrade-like things but I don't think it uses this code path. If it would only attempt to upgrade in the event that a specific version was given in the import file, then I think it is probably ok to leave as is, even if that means attempting to re-install.

src/AppInstallerCLICore/Commands/UpgradeCommand.cpp Outdated Show resolved Hide resolved
@@ -46,6 +47,7 @@ namespace AppInstaller::CLI
Argument::ForType(Args::Type::AcceptSourceAgreements),
Argument::ForType(Execution::Args::Type::CustomHeader),
Argument{ "all", Argument::NoAlias, Args::Type::All, Resource::String::UpdateAllArgumentDescription, ArgumentType::Flag },
Argument{ "include-unknown", Argument::NoAlias, Args::Type::IncludeUnknown, Resource::String::IncludeUnknownArgumentDescription, ArgumentType::Flag }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@denelon for argument name review.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I find the argument name somewhat awkward for a single app: winget upgrade SomeApp --include-unknown
For upgrade --all I understand it as "include apps with unknown version", but I don't quite get what we are "including" for a single app.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if the user explicitly specifies an app, --include-unknown would/should be redundant.

I also think winget upgrade AwesomePackage --all would be similarly strange.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current behavior is that upgrade <ID> doesn’t upgrade a package if already at latest. I had the argument behavior stay the same so the expectation of winget not doing an upgrade unless it has to holds.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Community opinion here; I would think that if I specify an ID, it should attempt to be upgraded even if the version is unknown. I would think that even if the version doesn't change, from a user perspective, an upgrade was at least attempted. It could be very confusing if the user knows there is an update, and they try to upgrade it only to be told that no applicable update was found.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also a message that prints:

PS C:\Users\easton> wingetdev upgrade GOG.Galaxy
This package's version number cannot be determined. To upgrade it anyway, add the argument --include-unknown to your previous command.
PS C:\Users\easton>

There was some discussion in the issue about whether or not there should be a setting to restore the current behavior (when in doubt, upgrade), but by default I think it should prompt the user to make a decision. The infinite reupgrading is causing more confusion than this is, IMO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I must have missed that. I would be fine with that approach, since it is clear and informative

@florelis
Copy link
Member

florelis commented Dec 2, 2021

@lechacon , does there need to be additional work done for import? It does upgrade-like things but I don't think it uses this code path. If it would only attempt to upgrade in the event that a specific version was given in the import file, then I think it is probably ok to leave as is, even if that means attempting to re-install.

Yes, there needs to be some work done for import as it doesn't use this code path. If there is no specific version in the file, I think import will try to update to the latest.

Import does call EnsureUpdateVersionApplicable, so we could do the unknown version check there and import would also pick it up. There are also some upgrade flows that don't use SelectLatestApplicableUpdate but do use EnsureUpdateVersionApplicable, like updating from a manifest or to a specific version; so maybe we need it there regardless.

@denelon
Copy link
Contributor

denelon commented Dec 2, 2021

The current behavior lists everything.

This PR could be considered a breaking change. I'm leaning in the direction of agreeing to do this since most of the packages listed from the "msstore" source today have version: "Unknown" and are expected to upgrade themselves. We are working towards getting versions from the Microsoft Store, so this will improve over time.

@JohnMcPMS does this code path get used for winget list? We should be consistent in both places.

I'm ok with "--include-unknown". I think this will help much more than hurt or confuse.

It might help to include a count for the number of packages with an unknown version.

PS C:\Users\denelon>winget upgrade
No installed package found matching input criteria. <n> packages specify "Unknown" version. Use "--include unknown" to see all results.

I would add the " packages... Use..." at the end of the winget upgrade --all as well. That will help make this option more discoverable. If we do this for winget list it should be there as well.

Note, we should ensure the value "Unknown" is appropriately defined for a private REST source so the behavior extends there as well @RDMacLachlan.

@denelon
Copy link
Contributor

denelon commented Dec 2, 2021

@lechacon we should consider this for import as well.

@jedieaston
Copy link
Contributor Author

jedieaston commented Dec 2, 2021

does this code path get used for winget list? We should be consistent in both places.

It appears to, but since the argument doesn't exist for winget list it will not show an available upgrade for applications with no version number. The app still is shown in the list, it just doesn't check for an upgrade. I can add the argument there too if you want to keep it consistent.

Co-authored-by: Chacón <lechacon@users.noreply.github.com>
@denelon
Copy link
Contributor

denelon commented Dec 3, 2021

"Unknown" is considered to be a sentinel value meaning the lowest version of a package. When the installed version is also Unknown, no upgrade is shown as available.

So, there shouldn't be a case where an available package with version "Unknown" is displayed as a potential upgrade in list when there is a version present in Apps & Features.

I am just trying to make sure we capture all of the scenarios:

  1. An installed version is known, and the only available package version is "Unknown"
  2. An installed version is known, and the latest version of an available package is lower.
  3. An installed version is known, and the latest version of an available package is higher.
  4. An installed version is Unknown.

I believe the work here is for the last scenario.

@JohnMcPMS to keep me honest, or at least correct me if I'm mistaken.

@jedieaston
Copy link
Contributor Author

jedieaston commented Dec 3, 2021

@denelon, does this look good to you?

image

Edit: note that the last commit doesn't output this message on upgrade --all, so I'll do that this afternoon when I have some time.

@@ -766,6 +774,10 @@ namespace AppInstaller::CLI::Workflow
context.Reporter.Info() << availableUpgradesCount << ' ' << Resource::String::AvailableUpgrades << std::endl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that you are using different strings to report the count depending on whether there is a single package or multiple, but here we were using the same string for both cases. I think we should be doing the same for both messages; although I'm not sure which one would be better. I would lean towards using a single string regardless of the number of packages as I don't know if there are any languages that make any distinction beyond 1/many or that don't make distinctions at all.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked a bit into pluralization and it's a whole rabbit hole one can go into. I found it interesting to look at the rules for all languages...
I found some internal references to string formats for putting all variants in a single string and using libraries for handling that. @JohnMcPMS does the current setup support something like that? @JohnMcPMS , @denelon , is this something we would want to handle?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw that too, but figured it was a separate PR... thanks for pointing it out :D

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we wanted to do something to handle plurals programmatically, then we could probably do it at the same time as the dynamic string replacement mentioned above. I don't see it as important as the dynamic strings though, so depending on the complexity we might just leave a nice place for it. I don't know if the english standard of making it "optional" like:

N installed package version(s) cannot be determined.

applies to the other supported languages. But it might be an option.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I go ahead and use a optional plural for now? SourceOpenFailedSuggestion uses it ("Failed when opening source(s); try the 'source reset' command if the problem persists.")...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds good to me.

@jedieaston
Copy link
Contributor Author

@lechacon Do you want me to add the argument to import as well? The only case where upgrade only uses EnsureUpdateVersionApplicable and not SelectLatestApplicableUpdate is where the user specifies a version, and in that scenario, they probably want to get to that version and winget telling them "I don't know if that's an upgrade or not..." wouldn't be helpful. But if we need the logic for import, might as well make it work the same way in both places...

@florelis
Copy link
Member

florelis commented Dec 8, 2021

@lechacon Do you want me to add the argument to import as well? The only case where upgrade only uses EnsureUpdateVersionApplicable and not SelectLatestApplicableUpdate is where the user specifies a version, and in that scenario, they probably want to get to that version and winget telling them "I don't know if that's an upgrade or not..." wouldn't be helpful. But if we need the logic for import, might as well make it work the same way in both places...

It makes sense to me to not consider if the current version is unknown when updating to a specific version.

If the installed version is unknown and we are installing specific versions from the json, I would agree with making it work the same as upgrade, which I'm fine if that is always updating from unknown versions. If we are installing the latest, I think the behavior would be better driven by whether the package is already installed (#1763) and not by whether it has unknown version.

So I don't think we need the --include-unknown argument for import.

@florelis
Copy link
Member

florelis commented Dec 8, 2021

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Member

@florelis florelis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants