https://github.com/simoncropp/packageupdate
A dotnet tool that updates packages for all solutions in a directory.
https://github.com/simoncropp/packageupdate
Last synced: 4 months ago
JSON representation
A dotnet tool that updates packages for all solutions in a directory.
- Host: GitHub
- URL: https://github.com/simoncropp/packageupdate
- Owner: SimonCropp
- License: mit
- Created: 2019-06-25T00:29:27.000Z (about 7 years ago)
- Default Branch: main
- Last Pushed: 2025-04-09T00:43:29.000Z (about 1 year ago)
- Last Synced: 2025-04-12T03:25:08.942Z (about 1 year ago)
- Language: C#
- Homepage:
- Size: 775 KB
- Stars: 28
- Watchers: 2
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
- Funding: .github/FUNDING.yml
- License: license.txt
- Code of conduct: code_of_conduct.md
Awesome Lists containing this project
README
#
PackageUpdate
[](https://ci.appveyor.com/project/SimonCropp/PackageUpdate)
[](https://www.nuget.org/packages/PackageUpdate/)
A [dotnet tool](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools) that updates packages for all solutions in a directory.
**See [Milestones](../../milestones?state=closed) for release notes.**
## Requirements/Caveats
* .net SDK 10 is required. https://dotnet.microsoft.com/en-us/download
* Only solutions using [Central Package Management (CPM)](https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management) are supported.
## NuGet package
https://nuget.org/packages/PackageUpdate/
## Installation
Ensure [dotnet CLI is installed](https://docs.microsoft.com/en-us/dotnet/core/tools/).
Install [PackageUpdate](https://nuget.org/packages/PackageUpdate/)
```ps
dotnet tool install -g PackageUpdate
```
## Performance characteristics
73 seconds for the following scenario
* 50 solutions
* 2 NuGet sources
* 384 nuget packages
* Network (Mbps): 94 up / 35 down. 17ms ping
## Usage
```ps
packageupdate C:\Code\TargetDirectory
```
If no directory is passed the current directory will be used.
### Arguments
#### Target Directory
```ps
packageupdate C:\Code\TargetDirectory
```
```ps
packageupdate -t C:\Code\TargetDirectory
```
```ps
packageupdate --target-directory C:\Code\TargetDirectory
```
#### Package
The package name to update. If not specified, all packages will be updated.
```ps
packageupdate -p packageName
```
```ps
packageupdate --package packageName
```
#### Build
Build the solution after the update
```ps
packageupdate -b
```
```ps
packageupdate --build
```
### Behavior
* Recursively scan the target directory for all directories containing a `.sln` file.
* Perform a [dotnet restore](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-restore) on the directory.
* Recursively scan the directory for `*.csproj` files.
* Call [dotnet list package](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-list-package) to get the list of pending packages.
* Call [dotnet add package](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-add-package) with the package and version.
## PackageUpdateIgnores
When processing multiple directories, it is sometimes desirable to "always ignore" certain directories. This can be done by adding a `PackageUpdateIgnores` environment variable:
```
setx PackageUpdateIgnores "AspNetCore,EntityFrameworkCore"
```
The value is comma separated.
## Add to Windows Explorer
Use [context-menu.reg](/src/context-menu.reg) to add PackageUpdate to the Windows Explorer context menu.
```reg
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\Directory\Shell]
@="none"
[HKEY_CLASSES_ROOT\Directory\shell\packageupdate]
"MUIVerb"="run packageupdate"
"Position"="bottom"
[HKEY_CLASSES_ROOT\Directory\Background\shell\packageupdate]
"MUIVerb"="run packageupdate"
"Position"="bottom"
[HKEY_CLASSES_ROOT\Directory\shell\packageupdate\command]
@="cmd.exe /c packageupdate \"%V\""
[HKEY_CLASSES_ROOT\Directory\Background\shell\packageupdate\command]
@="cmd.exe /c packageupdate \"%V\""
```
snippet source | anchor
## Authenticated feed
To use authenticated feed, add the [packageSourceCredentials](https://docs.microsoft.com/en-us/nuget/reference/nuget-config-file#packagesourcecredentials) to the global nuget config:
```xml
```
## Package Version Pinning
### Overview
prevent specific packages from being automatically updated by adding the `Pinned="true"` attribute to package entries in the `Directory.Packages.props` file.
### Usage
#### Pin a Single Package
```xml
```
In this example:
- `System.ValueTuple` will remain at version `4.5.0` and will **not** be updated
- `Newtonsoft.Json` will be updated to the latest version when running the updater
#### Pin Multiple Packages
```xml
```
#### Document Why a Package is Pinned
It's good practice to add comments explaining why a package is pinned:
```xml
```
### Behavior
#### When Running Update All Packages
```bash
dotnet run -- update
```
- All packages **without** `Pinned="true"` will be checked for updates
- Pinned packages are skipped entirely
#### When Running Update Specific Package
```bash
dotnet run -- update --package System.ValueTuple
```
- Even when explicitly targeting a pinned package, it will **not** be updated
- The pin is always respected, regardless of how the updater is invoked
### Common Use Cases
#### 1. Breaking Changes
Pin packages when newer versions introduce breaking changes you're not ready to handle:
```xml
```
#### 2. Framework Constraints
Pin packages that have specific framework version requirements:
```xml
```
#### 3. Security Fixes
Pin to a specific patched version while waiting for a proper migration:
```xml
```
#### 4. Performance Regressions
Pin when a newer version causes performance issues:
```xml
```
#### 5. Vendor Dependencies
Pin packages that must match versions used by third-party SDKs:
```xml
```
### Unpinning a Package
To allow a package to be updated again, remove the `Pinned="true"` attribute:
```xml
```
The next time you run the updater, it will update to the latest version.
### Technical Details
- The `Pinned` attribute is a custom attribute used by this updater tool
- It has no effect on NuGet's normal package resolution
- The attribute follows MSBuild conventions (similar to how `Pinned` works in project files)
- Comments and formatting around pinned packages are preserved during updates
## Automatic Package Migration
### Overview
PackageUpdate automatically detects and migrates deprecated NuGet packages to their recommended alternatives. When a package is marked as deprecated on NuGet.org with an alternative package specified, the tool will automatically replace it during updates.
### How It Works
When updating packages, PackageUpdate:
1. Checks if the **current version** of each package is marked as deprecated
2. If an alternative package is specified in the deprecation metadata:
- Verifies the alternative package exists in configured NuGet sources
- Checks that the alternative doesn't already exist in `Directory.Packages.props`
- Replaces the package reference with the alternative
- Sets the version to the latest available version of the alternative
3. Logs the migration with the deprecation reason
### Example Migration
**Before:**
```xml
```
**After running `packageupdate`:**
```xml
```
Console output:
```
Migrated WindowsAzure.Storage -> Azure.Storage.Common (Version: 12.26.0) [Deprecated: Legacy]
Updated Newtonsoft.Json: 13.0.1 -> 13.0.3
```
### Migration Behavior
#### Automatic by Default
Migrations happen automatically without requiring any flags or configuration. The tool detects deprecated packages and migrates them seamlessly.
#### Pinned Packages Are Never Migrated
If a package is pinned, it will not be migrated even if it's deprecated:
```xml
```
This package will remain unchanged.
#### When Alternative Already Exists
If the alternative package already exists in `Directory.Packages.props`, the migration is skipped:
```xml
```
Output:
```
Package WindowsAzure.Storage is deprecated with alternative Azure.Storage.Common, but alternative already exists
```
Both packages remain in the file, and only `Azure.Storage.Common` gets updated to the latest version.
#### When No Alternative is Available
If a package is deprecated but has no alternative specified, the tool logs a warning and continues with normal version update:
```
Package SomeDeprecatedPackage is deprecated but has no alternative. Reasons: Legacy
```
#### Current Version Check
The tool only migrates if the **current** version you're using is deprecated. If you're on an older, non-deprecated version, and only newer versions are deprecated, no migration occurs. This prevents unnecessary migrations when you're deliberately staying on an older version.
#### Specific Package Flag
The migration feature works with the `--package` flag:
```bash
packageupdate --package WindowsAzure.Storage
```
If `WindowsAzure.Storage` is deprecated with an alternative, it will be migrated automatically.
### Common Scenarios
#### Scenario 1: Microsoft Azure SDK Packages
Many older Azure SDK packages have been deprecated in favor of the new Azure SDK:
- `WindowsAzure.Storage` → `Azure.Storage.Common` or `Azure.Storage.Blobs`
- `Microsoft.Azure.Storage.Blob` → `Azure.Storage.Blobs`
- `Microsoft.Azure.DocumentDB` → `Microsoft.Azure.Cosmos`
These migrations happen automatically when you run `packageupdate`.
#### Scenario 2: Preventing Migration
If you want to prevent migration of a deprecated package (e.g., you're not ready to migrate yet), pin the package:
```xml
```
#### Scenario 3: Manual Review After Migration
After automatic migration, you may want to:
1. Review the changes in `Directory.Packages.props`
2. Update your code to use the new package's API (if breaking changes exist)
3. Test thoroughly before committing
The migration updates the package reference but doesn't modify your source code.
### Logging
#### Successful Migration
```
Migrated WindowsAzure.Storage -> Azure.Storage.Common (Version: 12.26.0) [Deprecated: Legacy]
```
#### Migration Skipped (Alternative Exists)
```
Package WindowsAzure.Storage is deprecated with alternative Azure.Storage.Common, but alternative already exists
```
#### Migration Skipped (No Alternative)
```
Package MyOldPackage is deprecated but has no alternative. Reasons: Legacy, Critical Bugs
```
#### Migration Skipped (Alternative Not Found)
```
Package OldPackage is deprecated with alternative NewPackage, but alternative not found in sources
```
### Technical Details
- Migration uses NuGet's official deprecation metadata API (`PackageDeprecationMetadata`)
- The `AlternatePackage` information comes directly from package authors via NuGet.org
- File formatting, comments, and XML structure are preserved during migration
- Migrations are logged distinctly from version updates for clarity
## Icon
[Update](https://thenounproject.com/search/?q=update&i=2060555) by [Andy Miranda](https://thenounproject.com/andylontuan88) from [The Noun Project](https://thenounproject.com/).