Skip to content

Update all projects in solution with dotnet package update#7014

Merged
zivkan merged 4 commits intodevfrom
dev-zivkan-dotnet-package-update-multiple-projects
Dec 30, 2025
Merged

Update all projects in solution with dotnet package update#7014
zivkan merged 4 commits intodevfrom
dev-zivkan-dotnet-package-update-multiple-projects

Conversation

@zivkan
Copy link
Member

@zivkan zivkan commented Dec 18, 2025

Bug

Fixes: NuGet/Home#14309

Description

Makes dotnet package update support solutions with multiple projects.

Key points:

  • Projects are processed in parallel, so the perf isn't terrible on huge solutions. Each project still handles packages serially, so that's a room for improvement, as it could theoretically be slow if a project has a huge number of packages.
  • Copilot was suggesting that when upgrading specific packages (for example, dotnet package update Microsoft.Extensions.DependencyInjection), if no packages were updated, then don't return an error exit code. I remember being unsure about this when implementing the first versions of package update. But now I agree to make the command idempotent. On Linux and other UNIX's, it's typically not an error to delete a file or directory that doesn't exist, because the user was asking for an outcome, even if the outcome was true in the precondition. Similarly, asking to upgrade a package to the latest version when it's already the latest, the outcome is achieved. Asking to upgrade a package that isn't referenced by a project doesn't require the project to be modified. I think this makes it easier to script package update since you no longer need to worry about whether the package is referenced or if it's already up to date. Anyway, this could be considered a breaking change, but I feel like it's better ergonomics.
  • Changed the final summary message "Updated x packages from y scanned" to report the unique package id counts, so that the same package being updated in multiple projects, or the same package being checked across multiple projects, doesn't double-count. From some technical point of view, it might make sense to double count, but I think from a human point of view, if I ask for Contoso.Utils to be upgraded, it should be 1 package scanned, 1 package updated, no matter how many projects it appears in.
  • Added a bunch of tests. The PackageUpdateIO class was previously untested, and it was much easier to add tests for multiple projects and debug the failing tests, than to do manual testing and debug when it crashed or had the wrong outcomes.
    • The PackageUpdateIO tests I decided to try creating a directory for the class, and then one test file per method being tested. I think I've used this pattern before in NuGet.Client, but I like it because when there are a lot of tests for a class in a single file, the test file can get very long, and then it's hard to check if a specific scenario is already tested. I hope it's easier when each method being tested has a test class.
  • Made the XPlat func test collection use a const string, rather than a duplicated string literal. This caused a one line change in a bunch of files.

PR Checklist

  • Meaningful title, helpful description and a linked NuGet/Home issue
  • Added tests
  • Link to an issue or pull request to update docs if this PR changes settings, environment variables, new feature, etc.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements support for updating packages across all projects in a solution using the dotnet package update command. Previously, the command only supported updating a single project at a time. The implementation introduces parallel processing to efficiently handle multiple projects.

Key changes:

  • Refactored package selection logic to process multiple projects in parallel using Parallel.ForEachAsync
  • Updated method signatures to return HashSet<string> for scanned packages instead of integer counts
  • Modified the final summary to report unique package counts across all projects

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
PackageUpdateCommandRunner.cs Core logic refactored to support multi-project updates with parallel processing; new ProcessProjectsInParallelAsync method coordinates concurrent package selection across projects
IPackageUpdateIO.cs Interface updated: GetProjectAssetsFileAsync now requires explicit projectPath parameter to support multi-project scenarios
PackageUpdateIO.cs Implementation updated to use the new projectPath parameter instead of assuming single project from dgSpec
SingleProjectTests.cs Added test for vulnerable package updates with audit mode verification; imports added for Protocol namespace
MultiProjectTests.cs Three new tests added: updating same package across projects, updating specific packages selectively, and vulnerable package handling in multi-project scenarios
GetPackageToUpdateTests.cs Updated assertions to verify the new scannedPackages return value alongside existing package update results

@zivkan zivkan marked this pull request as ready for review December 20, 2025 06:20
@zivkan zivkan requested a review from a team as a code owner December 20, 2025 06:20
@zivkan zivkan merged commit a99b70c into dev Dec 30, 2025
17 of 18 checks passed
@zivkan zivkan deleted the dev-zivkan-dotnet-package-update-multiple-projects branch December 30, 2025 05:07
};

var globalPackagesFolder = dgSpec.GetProjectSpec(dgSpec.Restore.Single()).RestoreMetadata.PackagesPath;
var globalPackagesFolder = dgSpec.GetProjectSpec(dgSpec.Restore.First()).RestoreMetadata.PackagesPath;
Copy link
Member

Choose a reason for hiding this comment

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

The GPF can be configured per project, so I think our code should probably account for that.

In fact, I think you probably do not need to set this here at all and let the rest of the restore mechanism figure out the gpf.

private string GetPackagesPath(RestoreArgs restoreArgs, PackageSpec project)
{
if (!string.IsNullOrEmpty(restoreArgs.GlobalPackagesFolder))
{
project.RestoreMetadata.PackagesPath = restoreArgs.GlobalPackagesFolder;
}
return project.RestoreMetadata.PackagesPath;
}

This ensures the one from the package spec is being used, which is what we're setting up here anyways.

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.

dotnet package update should support multiple projects

5 participants