DEV Community

Cover image for Automated NuGet package version range updates in .NET projects using Renovate
Anthony Simmon
Anthony Simmon

Posted on • Originally published at anthonysimmon.com

Automated NuGet package version range updates in .NET projects using Renovate

In my previous post about how to locally test and validate Renovate configuration files, we saw how Renovate can be helpful in keeping our dependencies up-to-date. It recommended updates for the Microsoft.Extensions.Hosting package from 7.0.0 to 7.0.1 (minor) or 8.0.0 (major).

By default, the way Renovate handles NuGet package updates in .NET projects is suitable for the majority of cases. According to the Renovate NuGet manager documentation (a manager is a module that manages updates for a type of dependency), the following files are analyzed:

  • Project files .csproj, .fsproj, and .vbproj,
  • MSBuild files .props and .targets, including Directory.Build.props, Directory.Build.targets, and Directory.Packages.props,
  • .NET tool installation manifests dotnet-tools.json,
  • .NET SDK version definition files global.json.

Any reference to a NuGet package in these files will be analyzed by Renovate, and if a new version is available, a pull request will potentially be created to update it.

What is not specified in the Renovate NuGet manager documentation page is that it can only process packages referenced with the basic package version notation, for example:

<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
Enter fullscreen mode Exit fullscreen mode

However, specifying a package version in a .NET project can be much more advanced than that. Indeed, it's possible to specify a version range:

Notation Applied rule Description
1.0 x ≥ 1.0 Minimum version, inclusive
[1.0,) x ≥ 1.0 Minimum version, inclusive
(1.0,) x > 1.0 Minimum version, exclusive
[1.0] x == 1.0 Exact version match
(,1.0] x ≤ 1.0 Maximum version, inclusive
(,1.0) x < 1.0 Maximum version, exclusive
[1.0,2.0] 1.0 ≤ x ≤ 2.0 Exact range, inclusive
(1.0,2.0) 1.0 < x < 2.0 Exact range, exclusive
[1.0,2.0) 1.0 ≤ x < 2.0 Mixed inclusive minimum and exclusive maximum version

Take, for example, the library OpenTelemetry.Instrumentation.Hangfire, which imports the Hangfire.Core library:

<PackageReference Include="Hangfire.Core" Version="[1.7.0,1.9.0)" />
Enter fullscreen mode Exit fullscreen mode

Unfortunately, Renovate does not support NuGet version ranges by default. However, it is possible to extend its capabilities with regular expressions.

It's required to extract the dependency name and the current version. In my previous example, the dependency name is Hangfire.Core, and I will consider the current version to be the left side of the range, which is 1.7.0. You are free to decide which part of the range you wish to update.

Here's the regular expression that allows extracting the dependency name and the current version:

<PackageReference\s+Include="(?<depName>[^"]+)"\s+Version="\[(?<currentValue>[^,]+),.*"
Enter fullscreen mode Exit fullscreen mode

depName and currentValue are mandatory group names that can be interpreted by Renovate to perform the update.

Let's update our Renovate file to include the custom regex manager with our regular expression. I've omitted any content from the file that's not relevant for this article.

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:best-practices"
  ],
  "enabledManagers": [
    "nuget",
    "custom.regex"
  ],
  "customManagers": [
    {
      "customType": "regex",
      "fileMatch": [
        "\\.csproj$"
      ],
      "matchStrings": [
        "<PackageReference\\s+Include=\"(?<depName>[^\"]+)\"\\s+Version=\"\\[(?<currentValue>[^,]+),.*\""
      ],
      "datasourceTemplate": "nuget",
      "versioningTemplate": "nuget"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

If we execute Renovate locally with our new configuration, we should see that Renovate is capable of identifying the 1.7.0 version of Hangfire.Core and proposes an update:

DEBUG: packageFiles with updates (repository=local)
       "config": {
         "regex": [
           {
             "deps": [
               {
                 "depName": "Hangfire.Core",
                 "currentValue": "1.7.0",
                 "datasource": "nuget",
                 "versioning": "nuget",
                 "replaceString": "<PackageReference Include=\"Hangfire.Core\" Version=\"[1.7.0,1.9.0)\"",
                 "updates": [
                   {
                     "bucket": "non-major",
                     "newVersion": "1.8.11",
                     "newValue": "1.8.11",
                     "releaseTimestamp": "2024-02-23T11:56:41.437Z",
                     "newMajor": 1,
                     "newMinor": 8,
                     "updateType": "minor",
                     "branchName": "renovate/hangfire-monorepo"
                   }
                 ],
                 "packageName": "Hangfire.Core",
                 "warnings": [],
                 "sourceUrl": "https://github.com/HangfireIO/Hangfire",
                 "registryUrl": "https://api.nuget.org/v3/index.json",
                 "homepage": "https://www.hangfire.io/",
                 "currentVersion": "1.7.0",
                 "isSingleVersion": true,
                 "fixedVersion": "1.7.0"
               }
             ],
             "matchStrings": [
               "<PackageReference\\s+Include=\"(?<depName>[^\"]+)\"\\s+Version=\"\\[(?<currentValue>[^,]+),.*\""
             ],
             "datasourceTemplate": "nuget",
             "versioningTemplate": "nuget",
             "packageFile": "Project.csproj"
           }
         ]
       }
Enter fullscreen mode Exit fullscreen mode

The Renovate Regex manager has many other parameters, so be sure to check out the documentation.

References

Top comments (0)