-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Add spec for package pinning. #1894
Changes from all commits
93a2631
141d794
1ab51e8
75eacca
32b5560
60bac9f
f71f0dc
f6d3c82
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
--- | ||
author: Easton Pillay jedieaston/easton@planeteaston.com | ||
created on: 2022-01-25 | ||
last updated: 2022-02-02 | ||
issue id: 476 | ||
--- | ||
|
||
# Pinning a package | ||
|
||
For [#476](https://github.com/microsoft/winget-cli/issues/476) | ||
|
||
## Abstract | ||
|
||
This spec describes the functionality behind "pinning" a package (freezing a package at a certain version so that it will be not be automatically upgraded via `winget upgrade --all`). | ||
|
||
## Inspiration | ||
|
||
This functionality is inspired by functionality in other package managers, as well as community feedback. Many packages (software development tools and libraries commonly, but other software as well) introduce breaking changes that users may not want integrate into their workflow quite yet. | ||
|
||
## Solution Design | ||
|
||
A table of packages (by Name, Version and Product Code if available) that are currently pinned will be kept in the local tracking catalog. To be repository independent, these values should be correlated from local sources (Add and Remove Programs, Appx, etc). This also means that the user should be able to pin packages that were not installed via the Windows Package Manager, so that they won't be upgraded via `winget upgrade --all`. | ||
|
||
Some applications would also like to opt-out of `winget upgrade --all` if they manage their own upgrades or often make breaking changes. As such, the `RequiresExplicitUpgrade` key was added in manifest schema v1.1. Given that this creates the same end result for the user, packages that opt-out of upgrades in this manner should behave like pinned packages to the user, and they should be able to override the behavior listed in the manifest if they choose. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does everyone like this RequiresExplicitUpgrade behavior? I believe it continues the trend of "sane defaults, but we'll let you break it". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That aligns with my desire to have safe and rational defaults, but to let "power users" drive the behavior they want with arguments and/or settings. Developers know what they want, and we should let them determine how the Windows Package Manger should behave. We should call out some of the concerns like unintended consequences when updating a package that may be breaking to other things installed on their system. |
||
|
||
|
||
## UI/UX Design | ||
|
||
Several commands will need to be added to support pinning packages. Where applicable, equivalent names (or new arguments) for PowerShell cmdlets will also be given. | ||
|
||
The main interface for the pinning feature will be a new command, `winget pin`, with a couple of options: | ||
|
||
|
||
``` | ||
winget pin | ||
PowerShell: Get-WinGetPinnedPackage | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @denelon Should this be a separate cmdlet or an argument for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would be voting for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The PowerShell convention is more likely to be discrete cmdlets for pinning and unpinning. Looking at approved PowerShell verbs: https://docs.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands?view=powershell-7.2 We may also consider Lock and Unlock, but that might be confusing when compared with the "pin" name. I've thrown a few suggestions below. I'll also mention @RDMacLachlan to get some input here: Get-WinGetPinnedPackage - shows packages that have been pinned. We may also want to consider packages that upgrade themselves as not pinnable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had a few other suggestions below earlier; I like
Note: After more consideration, I do like Set and Clear the best, since it maintains consistency |
||
``` | ||
|
||
Running `winget pin` with no arguments will show a table of currently pinned packages: | ||
|
||
``` | ||
Name Id Version Reason | ||
------------------------------------------------------------------------------------------------------------- | ||
Microsoft Bob Microsoft.Bob 2.35.0 Manual | ||
iTunes Apple.iTunes 12.0.199.4 Via manifest | ||
|
||
``` | ||
|
||
The "Reason" field serves to explain why a application was pinned. If a package designates the `RequiresExplicitUpgrade` property in their manifest, it should be explained here so that the user has a way to diagnose why it isn't automatically upgraded during `winget upgrade --all`. | ||
|
||
``` | ||
winget pin <package> | ||
PowerShell: Set-WinGetPinnedPackage | ||
``` | ||
|
||
`<package>` correlates to a query, similar to `winget list`. When running this command, the package information will be stored in the table in the tracking catalog. This command should be able to accept Package Identifers (checked against all repositories) as well as names, tags, etc. If the package does not have a version number locally but is available from a source, then the version number from the source should be used. | ||
|
||
If there is no package directly available for software a user wants to pin, but it is [included as part of another package](https://github.com/microsoft/winget-cli/issues/1073), the package which includes said piece of software should be treated as pinned unless a newer version doesn't change the version of the pinned software. | ||
|
||
``` | ||
winget pin --clear <package> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The spec should include discussion of how user driven pinning and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this is an opportunity to look at what exactly the RequiresExplicitUpgrade field is supposed to show. If it is intended to show the default pinned state, I would suggest we consider renaming the field to something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That may not be necessary, since winget can't guarantee that a package won't be upgraded anyway, it can only guarantee that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
True, but it would be an opportunity to keep the user informed if we know of specific packages that auto-upgrade. Just an idea, but probably outside the realm of this spec anyways There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. RequiresExplicitUpgrade was about apps that update themselves and was something added to the manifest to somewhat declutter Pinning a package is more about a user saying, "I don't want this upgraded". It's often the case for enterprises who have to support specific versions of applications, and developers wanting to have specific versions of packages for their needs. We may also need to consider the case where packages won't be able to support pinning. Some packages are going to update no matter what "we" want. This could help us to inform users when we can't control the software upgrade mechanism. |
||
PowerShell: Remove-WinGetPinnedPackage | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this may be very opinion based, but to me, this powershell cmdlet naming makes me think it will uninstall the package that has been pinned. I would suggest any of the followng (and encourage discussion)- |
||
``` | ||
|
||
It functions similarly to `winget pin <package>`, but it clears the pin. This should automatically happen on `winget uninstall`. | ||
|
||
Enhancements will also need to be made to other commands in the Windows Package Manager, including: | ||
|
||
``` | ||
winget upgrade --include-pinned | ||
PowerShell: Get-WinGetPackage -UpgradeAvailable -Pinned | ||
``` | ||
|
||
With the new `--include-pinned` argument, Upgrade should show a separate table in addition to the regular table which shows possible upgrades to pinned packages. | ||
|
||
``` | ||
<...> | ||
Upgrades to pinned packages: | ||
|
||
Name Id Version Available Source | ||
------------------------------------------------------------------------------------------------------------------------- | ||
Clippy for Azure 2011 Datacenter Microsoft.Clippy.2011.Datacenter 2.35.0 2.35.1.2 winget | ||
``` | ||
|
||
|
||
``` | ||
winget <upgrade/install> <package> | ||
PowerShell: Install-WinGetPackage / Upgrade-WinGetPackage | ||
``` | ||
|
||
Upgrade and Install should work as normal if a pinned package is requested, but print a warning to remind the user that it was previously pinned. | ||
|
||
|
||
``` | ||
PS C:\Users\billg> winget upgrade Microsoft.Bob | ||
WARNING: This package was previously pinned at version 2.32.0. The pin will be updated to represent the new version number. | ||
If you would like to remove the pin, use "winget pin --clear Microsoft.Bob". | ||
Found Microsoft Bob [Microsoft.Bob] Version 2.39.0 | ||
This application is licensed to you by its owner. | ||
Microsoft is not responsible for, nor does it grant any licenses to, third-party packages. | ||
Downloading https://aka.ms/importantsystemdependencies/bob.exe | ||
██████████████████████████████ 2.08 MB / 2.08 MB | ||
Successfully verified installer hash | ||
Starting package install... | ||
Successfully installed | ||
Microsoft.Bob has been pinned at version 2.39.0. | ||
``` | ||
|
||
``` | ||
winget install --pin <package> | ||
``` | ||
|
||
Install should also be extended to allow the user to pin a package at install time. | ||
|
||
|
||
|
||
In addition to commands, there should be a new `Pinned` key in exported package lists, allowing users to move their pins to different systems: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have several other enhancements to add to the packages.json schema. We've been discussing supporting essentially all the install switches in the schema so running |
||
|
||
``` | ||
// ... | ||
{ | ||
"Packages": | ||
[ | ||
{ | ||
"PackageIdentifier": "Microsoft.Bob", | ||
"PackageVersion" : 2.35.0, | ||
"Pinned" : true | ||
}, | ||
], | ||
} | ||
// ... | ||
``` | ||
|
||
Lastly, there should be good error messaging throughout the Windows Package Manager in order to explain to users when something doesn't go quite right. | ||
|
||
As an example, consider the situation where a user has pinned their favorite package, Microsoft Bob: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
😎 |
||
|
||
``` | ||
PS C:\Users\billg> winget install --pin Microsoft.Bob | ||
Found Microsoft Bob [Microsoft.Bob] Version 2.32.0 | ||
This application is licensed to you by its owner. | ||
Microsoft is not responsible for, nor does it grant any licenses to, third-party packages. | ||
Downloading https://aka.ms/importantsystemdependencies/bob.exe | ||
██████████████████████████████ 2.08 MB / 2.08 MB | ||
Successfully verified installer hash | ||
Starting package install... | ||
Successfully installed | ||
Microsoft.Bob has been pinned at version 2.32.0. | ||
``` | ||
|
||
Then, later, that user tries to install a package that is dependent on a newer version of Microsoft Bob. The Windows Package Manager should not upgrade Microsoft Bob automatically, but instead should notify the user and give them information on how to continue: | ||
|
||
``` | ||
PS C:\Users\billg> winget install --pin Microsoft.RoverTheDog | ||
Found Rover the Dog [Microsoft.RoverTheDog] Version 5.1 | ||
This application is licensed to you by its owner. | ||
Microsoft is not responsible for, nor does it grant any licenses to, third-party packages. | ||
This package requires the following dependencies: | ||
- Packages | ||
Microsoft.Bob, version 2.39.0. | ||
|
||
Microsoft Bob is currently pinned at version 2.32.0, but Rover the Dog 5.1 requires at least version 2.39.0. | ||
To upgrade Microsoft Bob and other pinned dependencies, add the argument --include-pinned to your previous command. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've gone back and forth between just "informing" users and giving an interactive [Y/N] sort of dialog to see if the user wants to perform suggested actions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A [Y/N] prompt would be more user-friendly, but it would make it harder to use winget in automation scenarios. Is there a way on Windows to detect if a user is interactively using a shell vs running a script? I know the way to tell apt on linux not to ask questions is via an environment variable, but that seems kludgy. I guess we could also say that the way forward for automating winget is via the PowerShell library or directly using COM, but since that's not complete yet... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any of the [Y/N] style prompts are likely suitable for a setting to specify a default. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Sorry for being a little off topic. Just want to make sure you're talking about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You got it :D There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've requested that @lechacon do more extensive interactivity controls for another review. The goal would be to have a common option that disables interactivity, as well as a setting. Interactivity in general is not a good way to handle these cases, because the COM (and thus PowerShell eventually) entrypoints cannot use that pattern. But with a more generic and extensive set of controls and thoughts about non-interactive defaults, we can use them more (within reason). |
||
``` | ||
|
||
## Capabilities | ||
|
||
### Accessibility | ||
|
||
Accessibility should not be impacted by this change. There will be a few more tables printed to the terminal in certain cases, but they should use the current table implementation used by `winget upgrade` and `winget list`. | ||
|
||
### Security | ||
|
||
Security of the Windows Package Manager should not be impacted by this change. However, security of user's software may be, as if they pin a insecure version of a package they currently will not be notified of important security updates within the Windows Package Manager. | ||
|
||
### Reliability | ||
|
||
The change will improve reliability, as users will be able to have fine grained control of the Windows Package Manager's upgrade functionality to ensure their workflow is not disrupted. | ||
|
||
### Compatibility | ||
|
||
There should not be any breaking changes to the code. Although there could be a mild breaking change to the behavior of `upgrade --all` (not all packages are upgraded anymore since pinned ones are skipped), this is purely opt-in from the user's perspective at this time (if they do not pin software, there should not be a change). | ||
|
||
### Performance, Power, and Efficiency | ||
|
||
There should not be any notable performance changes. | ||
|
||
|
||
## Potential Issues | ||
|
||
Outside of missing security updates and having possible dependency resolution failures due to pins, there should not be any other impacts. Considering the opt-in nature of pinning, it should not affect users unless they want to use it. | ||
|
||
## Future considerations | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another consideration. As verified publishers start adding their packages, they may want to force override pins / require an update. Do we need a provision for this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My opinion would be that publishers shouldn't be able to override pins via the manifests, as the main reason a user would want to pin a package is because they disagree with the ISV's patching schedule. If they wanted to get around it they could add an automatic updater to their piece of software (as many have chosen to do). |
||
|
||
- Group Policy or MDM control of pinned packages would be a natural addition to the defined functionality. Administrators may want to restrict upgrades for certain pieces of conflicting software if it will cause issues for some or all of their users. | ||
|
||
- Packages may want to define pins for their dependencies, if they can't use anything above a certain version of a dependency. These pins could be merged into the user's current pins, making sure that the packages currently installed keep working. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a great call out. We've been discussing this scenario with the dependency section. I'll be sure to add this kind of a concept. We've got the concept of a "minimum supported version" but were going back and forth on a "maximum supported version". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would be in favor of a maximum version, since if a package requires a specific version then the minimum and maximum could be set to the same thing. This isn't a rare scenario, but it certainly isn't as common as a minimum version. |
||
|
||
- If a user uninstalls or upgrades a pinned package without using the Windows Package Manager, the local tracking catalog (given the definitions in this spec) will become out of sync with the "reality" of the packages's current status. The pinned packages table should have a method of staying in sync. | ||
|
||
## Resources | ||
|
||
- [Brew - How do I stop certain formulae from being upgraded?](https://docs.brew.sh/FAQ#how-do-i-stop-certain-formulae-from-being-updated) | ||
|
||
- [NPM - package.json dependencies](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#dependencies) | ||
|
||
- [APT - Introduction to Holding Packages](https://help.ubuntu.com/community/PinningHowto#Introduction_to_Holding_Packages) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the traditional Microsoft Store packages, the Microsoft Store automatically updates programs. Users would not be able to pin those packages. I need to see if there is a way to pin packages from being automatically updated by the Microsoft Store.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was trying to be as repo neutral as possible, but the Microsoft Store will definitely need special treatment. We need to be able to pin packages even if they are coming from "more normal" REST sources or Intune or whatever.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we define "pinning" as in this spec to "not be automatically upgraded via
winget upgrade --all
", then anything that upgrades itself (or is upgraded by something else) automatically will be outside of our scope. We can't control most of them anyway, so it is the best thing we can do.Now if it turns out that Store MSIX upgrades can be put on hold on a per-package basis, we can certainly integrate that control. But that seems like icing rather than cake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least with chocolatey, I ended up pinning for two reasons:
So the behavior of "the package may still auto update, and is just excluded from
winget upgrade --all
makes a lot of sense to me.