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
, includingDirectory.Build.props
,Directory.Build.targets
, andDirectory.Packages.props
, - .NET tool installation manifests
dotnet-tools.json
, - .NET SDK version definition files
global.json
.
Any reference to a NuGet package or .NET SDK 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" />
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)" />
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>[^,]+),.*"
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"
}
]
}
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"
}
]
}
The Renovate Regex manager has many other parameters, so be sure to check out the documentation.