-
Notifications
You must be signed in to change notification settings - Fork 253
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
dotnet update package for NuGet packages. #11812
base: dev
Are you sure you want to change the base?
Conversation
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.
Looks awesome overall! Main thing it's missing is example outputs.
dotnet update package --dry-run | ||
``` | ||
|
||
#### Exit Codes |
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.
Is it all or nothing? Is it possible for some packages to update while others fail?
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.
Still thinking through it. Any suggestions?
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.
IMO, it shouldn't be all or nothing by default - but may want to provide an option for it if users want to take advantage of the exit code - but that's a secondary need.
If I have a project with an older framework where the latest version of half my packages still support my TFM, but the latest version of the other half don't, an all or nothing design would prevent me from bulk updating altogether.
Based on feedback about version preferences from the HaTS survey, I think the typical user will likely want to update all compatible packages to the latest stable version, even if other will fail. I think it's probably a fairly small subset that will take advantage of the exit code for automation purposes.
Maybe --atomic
or --disable-partial
would make sense as an option for all or nothing 🤷♂️
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 think update by tfm compatibility
is a special scenario.
It's one of those few scenarios where a failure is that exact package only.
The trickier one is what if the latest versions causes resolution conflicts, such as downgrades etc.
It becomes a user decision what they'd want to do then, so something semi interactive.
--no-restore
is a an option that skips validations.
Right now the most common failures at, NU1605, NU1105, NU1201 and NU1104.
Back to the compat scenario, I think it's the one that we're most likely to solve. Worth noting that we'd have performance/implementation challenges for any source that isn't nuget.org.
Right now, search by tfm is a search thing only, we'd need to validate the perf issues.
tldr; I feel the pain of the customers, I run into some of these myself, but solving this in the first iteration might be a reach.
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.
Another "fun" case when updating by tfm compatibility that I run in to is that dotnet-ef supports something like dotnet core 2.1 in the latest version so if you update everything to the latest compatible version the EF Core packages might get out-of-sync. I really whish to be to update all packages to the latest compatible version but it's not as easy as it might seem.
<!-- What parts of the proposal need to be resolved before the proposal is stabilized? --> | ||
<!-- What related issues would you consider out of scope for this proposal but can be addressed in the future? --> | ||
- Should this command use `dotnet add package` under the hood for the scenarios that make sense such as finding the latest version of a specific package name? | ||
- What verb makes most sense? `update`, `upgrade`, `refresh`, etc? Update seems the most consistent for package managers such as cargo, npm, rubygems, and NuGet. Upgrade seems the most consistent for package managers such as pip. |
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.
Worth noting that "update" is consistent with the current PMUI terminology.
|
||
The URI of the NuGet package source to use during the restore operation. | ||
|
||
- -v|--version <VERSION> |
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.
Can you specify version for a glob of packages as well?
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.
We will need to lock down the update strategies first I think. In general, I don't think so unless people have a compelling reason to do this!
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 remember having a conversation with @nkolev92 about how some packages need to have their version kept in sync, particularly in ASP.NET Core world. I believe a lot of those packages also share prefixes like these:
Azure packages are also versioned similarly:
In these cases dotnet projectA update package Azure.Storage.* 12.10.0
might be pretty handy
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.
That should be supported with current spec right?
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.
Yes, unless explicitly disallowed. I just wanted to clarify the intention 🙂
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.
Would it be preferrable to specify a list of ids instead?
|
||
Version of the package. See NuGet package versioning. | ||
|
||
- --dry-run |
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.
Will this display the changes in transitive packages as well?
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.
Top-level for now since those would be the only "affected" packages per-say. But let's keep this open for more perspectives.
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.
IMO, top-level only by default but have a --verbosity option to include more info.
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 think we should start with top level ones, but we can consider adding it later.
It's probably worth considering whether we do deltas or maybe just display the new list of packages.
|
||
#### Arguments | ||
|
||
- PROJECT | SOLUTION |
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.
Is there way to specify a directory of projects? i.e. I want to update all my packages in my \test directory?
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.
We'll need to limit the scope. So let's start with project or solution. Updating the world would be amazing, but very complex I think!
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.
Is it? This design already necessitates the ability to "find a project" within the current directory when the <PROJECT>
isn't specified. Might be oversimplifying, but isn't the functionality I'm describing just a loop to do that for all projects recursively within a directory?
Conceivably, one of the biggest users of this feature will be VS Code .NET devs who might not have a solution file to target. However, we know that many users prefer to keep all of their packages across all projects at the latest stable version.
It also adds a nice algorithmic component for an intern 😉
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 believe it's possible. For example if you ran the command on the repo folder, it should work recursively.
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.
Based on this line:
The project or solution file to operate on. If not specified, the command searches the current directory for one. If more than one solution or project is found, an error is thrown.
The current design will error out if you run it on the repo folder because multiple projects will be found. My expectation would be that it would run recursively/ apply to all found projects.
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.
Let's change this language then!
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.
How many folders deep would you search for projects?
All of it?
I think deciding the target
of a command should be something we involve the SDK team on given that package
is a first class noun in dotnet.exe.
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.
@baronfel Any idea how we can get more eyes from SDK team on these types of things? :)
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.
You can unfortunately can't tag @dotnet/dotnet-cli, so I'll poke a few here: @dsplaisted, @joeloff, @gkulin
I'd generally be in favor of globs/patterns for more SDK operations - I know a similar capability has been requested for many of the MSBuild-driving commands in the past. It's common to use globs for this kind of thing - **/*Test.*proj
to grab every test project in a solution recursively, for example.
- `?` - single occurrence of any character. | ||
- `.` - literal "." character | ||
|
||
#### Options |
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.
Any plan to include a --compatible
or have it automatically update packages to the latest compatible version if the package latest stable version doesn't support the TFM?
It's referenced in this comment: #4103 (comment)
It's probably beyond the scope an initial release, but a maybe a cool idea 🤷♂️
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.
Not yet. We don't have compat client tooling yet outside of one field. Once we can use the server side stuff, perhaps we can light up this.
To be clear, please do not update the version string in the csproj file. This is what lock files are for. What I set in csproj should be a resolvable version constraint, not an exact pinned version. |
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.
This proposals brings up all the discussion points that we'll need to have when we implement this features.
Thanks for the initial write-up @JonDouglas
Most of my comments are doc readiness, but a good amount are about the functionality itself as well.
|
||
- PACKAGE_NAME | ||
|
||
The package reference to add. Package name wildcards should be supported and update a subset of a glob-style pattern package name. i.e. `Microsoft.*` would update Microsoft packages. The commonly used symbols to support are: |
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.
Do we know if there's an ask for this at this point?
Would a list of package ids be preferable instead?
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.
The primary ask is updating all packages. The secondary ask is having control of updating. A list of package IDs can be preferable for sure. This shorthand might be helpful in our ecosystem given prefix/source mapping.
|
||
#### Options | ||
|
||
- -f|--framework <FRAMEWORK> |
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.
This becomes tricky quickly in the solution case.
For example, what if a project in a solution does not target that exact framework?
|
||
- -f|--framework <FRAMEWORK> | ||
|
||
Adds a package reference only when targeting a specific framework. |
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.
Probably meant to say update.
|
||
- --package-directory <PACKAGE_DIRECTORY> | ||
|
||
The directory where to restore the packages. The default package restore location is %userprofile%\.nuget\packages on Windows and ~/.nuget/packages on macOS and Linux. For more information, see Managing the global packages, cache, and temp folders in NuGet. |
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 wonder if we can not add this.
I know add package has it, but I'm wondering how commonly it's used if at all.
Specifying the global packages folder makes more scene in commandline restore scenarios that add/update imo.
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.
Sadly we don't have much of a signal of how much this is used. Does this still make sense for update scenario?
|
||
- --prerelease | ||
|
||
Allows prerelease packages to be installed. Available since .NET Core 5 SDK |
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.
nit: Copied from add package? :D Probably remove the last part.
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.
Yes for consistency sake!
|
||
- --dry-run | ||
|
||
Displays what would be updated, but doesn't actually do the operation. |
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.
Default is major?
Wonder if we need an option that takes parameters instead?
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.
Open to perspectives! Right now yes, major default with two flags for minor and patch.
dotnet update package --dry-run | ||
``` | ||
|
||
#### Exit Codes |
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 think update by tfm compatibility
is a special scenario.
It's one of those few scenarios where a failure is that exact package only.
The trickier one is what if the latest versions causes resolution conflicts, such as downgrades etc.
It becomes a user decision what they'd want to do then, so something semi interactive.
--no-restore
is a an option that skips validations.
Right now the most common failures at, NU1605, NU1105, NU1201 and NU1104.
Back to the compat scenario, I think it's the one that we're most likely to solve. Worth noting that we'd have performance/implementation challenges for any source that isn't nuget.org.
Right now, search by tfm is a search thing only, we'd need to validate the perf issues.
tldr; I feel the pain of the customers, I run into some of these myself, but solving this in the first iteration might be a reach.
<!-- What parts of the proposal do you expect to resolve before this gets accepted? --> | ||
<!-- What parts of the proposal need to be resolved before the proposal is stabilized? --> | ||
<!-- What related issues would you consider out of scope for this proposal but can be addressed in the future? --> | ||
- Should this command use `dotnet add package` under the hood for the scenarios that make sense such as finding the latest version of a specific package name? |
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 think that's a technical question that'll likely be accounted for by the implementer.
These 2 commands will share a bunch of common functionality.
<!-- What related issues would you consider out of scope for this proposal but can be addressed in the future? --> | ||
- Should this command use `dotnet add package` under the hood for the scenarios that make sense such as finding the latest version of a specific package name? | ||
- What verb makes most sense? `update`, `upgrade`, `refresh`, etc? Update seems the most consistent for package managers such as cargo, npm, rubygems, and NuGet. Upgrade seems the most consistent for package managers such as pip. | ||
- Should `--highest-minor` and `--highest-patch` be replaced with a single `--dependency-version <version>` parameter to account for more scenarios like `Lowest(default)` and `Highest`? |
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.
The Lowest
vs Highest
is a larger feature than the update command itself.
it makes it difficult for me to suggest a name based on what that feature may turn out to be.
|
||
#### Arguments | ||
|
||
- PROJECT | SOLUTION |
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.
How many folders deep would you search for projects?
All of it?
I think deciding the target
of a command should be something we involve the SDK team on given that package
is a first class noun in dotnet.exe.
|
||
The project or solution file to operate on. If not specified, the command searches the current directory for one. If more than one solution or project is found, an error is thrown. | ||
|
||
- PACKAGE_NAME |
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.
going to throw out a crazy idea here that might consolidate a few flags/options.
PACKAGE_NAME
can be
- pattern as described below, or
- a list of 'package with version spec's, where 'package with version spec' means a string of the format
{PACKAGE_NAME}@{npm-style version expression}
The NPM(and also gem/paket/etc)-style expressions allow you to easily express bounds for the update operation on a package-by package basis, unambiguously, in a way that PACKAGENAME -version VERSION
can't scale to. It also removes the need for --higest-minor
, --highest-patch
, and --prerelease
, as those can be specified with appropriate syntax in the correct positions.
This does come with a downside of a) documenting these and b) writing code to parse them, however.
Introduction to an updating experience in the .NET CLI that allows one to update dependencies in projects and solutions while supporting helpful options to stay current based on an individuals update strategy.
This proposal introduces one new command to .NET CLI known as
dotnet update package
.Rendered Spec
Please 👍 or 👎 this comment to help us with the direction of this feature & leave as much feedback/questions/concerns as you'd like on this issue itself and we will get back to you shortly.
Thank You 🎉