An open API service indexing awesome lists of open source software.

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.

Awesome Lists containing this project

README

          

# PackageUpdate

[![Build status](https://img.shields.io/appveyor/build/SimonCropp/PackageUpdate)](https://ci.appveyor.com/project/SimonCropp/PackageUpdate)
[![NuGet Status](https://img.shields.io/nuget/v/PackageUpdate.svg)](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/).