-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Automagically update NuGet packages in .NET projects.
NuKeeper is a global tool on NuGet. Install with
dotnet tool install nukeeper --global
NuKeeper automates the routine task of discovering and applying NuGet package updates.
NuKeeper will compare the NuGet packages used in your solution to the latest versions available on NuGet.org, and:
- List available NuGet package updates on .NET code on the local file system or on a remote server.
- Apply NuGet package updates to .NET code on the local file system.
- Make pull requests containing updates to code on a server.
Package update automation is necessary because .NET developers are bad at applying NuGet package updates. To increase visibility of package updates, and decrease cycle time.
Why do we deploy code changes frequently but seldom update NuGet packages? In Continuous delivery, we know that there is a vicious cycle of "deploys are infrequent and contain lots of changes, therefore deploys are hard and dangerous, therefore deploys are infrequent and contain lots of changes" and a virtuous cycle of "deploys are frequent and contain incremental changes, therefore deploys are easy and low risk, therefore deploys are frequent and contain incremental changes" and so we work hard to move into the second cycle, and afterwards, life is easier.
But NuGet package updates are a form of change that should be deployed, and we likewise want to change the cycle from "NuGet package updates are infrequent and contain lots of package changes, therefore NuGet package updates are hard and dangerous..." to "NuGet package updates are frequent and contain small changes, therefore NuGet package updates are easy and routine...".
NuKeeper is written in .NET Core 2.1, using HTTP APIs and command-line tools. It runs on Linux and on Windows.
NuKeeper was designed from the start to work on .NET Core and .NET Full Framework solutions. It can work on the new "Visual Studio 2017" format of .csproj
files, with <PackageReference>
elements, and on the older "Visual Studio 2015" format, with a packages.config
file.
NuKeeper will also work in .vbproj
and .fsproj
project files.
Private package sources are supported. To specify package sources other than the public NuGet.org feed, it is recommended that you use a NuGet.config
file in your repository. It will be used by NuKeeper, and by other tools. NuKeeper also allows these sources to be specified on the command line.
Libraries:
- LibGit2Sharp for git automation.
- Octokit for GitHub automation.
- NuGet.Protocol for NuGet api queries.
-
NuGet.CommandLine for updating
packages.config
style projects. - McMaster.Extensions.CommandLineUtils for command line parsing.
Command lines called: nuget.exe
and/or dotnet
.
NuKeeper works with git, no other source control systems are supported for raising pull requests. You can however use the public github.com
, dev.azure.com
or an internal hosted GitHub instance by specifying its location with the --api
option. You can also apply changes locally with the update
command.
When the package version used is a prerelease (AKA a beta), later betas or release versions will be found and applied. When the package version used is not a beta, they will not.
You will need the command line version of dotnet
installed. NuKeeper can run on all platforms where dotnet
runs, including Windows, linux and MacOS. Inspection should work on all of these platforms.
However not all update cases work on all platforms. In short: You can update windows-only code on windows, and update cross-platform code on any platform.
NuKeeper will invoke dotnet
or the NuGet.exe
tool as needed to update packages. The "windows only" restriction is due to the older .csproj
and packages.config
file format requiring NuGet.exe
, which is windows only. There are no plans to port NuGet.exe
; dotnet
is the portable replacement. This is another reason to update these projects to the new <PackageReference>
style, so that they can be worked with using dotnet
instead.
Also, not all linux distributions are supported by LibGit2Sharp, which is a c# wrapper for the platform-specific binaries of LibGit2.
For projects using packages.config
, NuGet.exe
no longer runs install.ps1
and uninstall.ps1
scripts from command line.
Those are still executed from Visual Studio, resulting in different behaviour for packages relying on this functionality.
An example of this is StyleCop.Analyzers which (when used with a packages.config
style project) will not update the <Analyzers>
node in the project file.
This does not affect projects using <PackageReference>
project file format, as that format replaces install scripts with content transformations, which are supported.
NuKeeper, right from the start, aimed to be a package updater for all .NET scenarios. This means both .NET Core and .NET Full framework are supported; old and new project file format, and .csproj
, .vbproj
and .fsproj
files are all supported. Additional custom package feeds are supported, as many larger companies use internal nuget feeds to manage internal artefacts.
We do not plan to make NuKeeper a general update tool for multiple languages and package managers such as Node.js NPM and Ruby gems. Such update management tools already exist, and some are listed here. These tools tend to have only basic .NET Core support and are not coded in c#. We feel that we would rather embrace the .NET project and package system to the exclusion of others, since no other tool covers this case as well.
NuKeeper was initially created raising Pull Requests for the GitHub collaboration platform, in both the public and internal enterprise versions, as this is what we used. The code was tightly coupled to GitHub Octokit. However, due to demand for other back ends, and the submitted code; it is now a model where the source control platform is selected at runtime. Supported platforms are:
NuKeeper is free open source, but you will have to run it yourself to update your code.
If the project is a library that itself produces a NuGet package, it is usually best not to update it aggressively without cause. Consider carefully whether you want to force your users to also update entire dependency chains.
e.g. if MyFancyLib
depends upon Newtonsoft.Json
version 9.0.1
then an application that depends upon MyFancyLib
can use Newtonsoft.Json
version 9.0.1
or a later version. Updating the reference in MyFancyLib
to Newtonsoft.Json
version 10.0.3
takes away some flexibility in the application using MyFancyLib
.
It might even cause problems.
Libraries should, however, update their packages when there is a breaking change in the features that they use or another compelling reason. e.g. If MyFancyLib
uses Newtonsoft.Json
version 8.0.1
, but since it only calls JsonConvert.DeserializeObject<>
many versions of Newtonsoft.Json
can be used.
But now I am converting MyFancyLib
to NetStandard for use in .NET Core. The lowest version of Newtonsoft.Json
that supports this is 9.0.1
, so we use that.
Although there are later versions of Newtonsoft.Json
, this gives MyFancyLib
what it needs and allows clients the most choice within the constraint of supporting NetStandard. Another compelling reason to update a dependency would be if there is a bug fix that impacts the working of MyFancyLib
, so users of MyFancyLib
really should apply it.
In an end-product deployable application, frequent updating of packages is a better tactic. Supported by comprehensive automated testing, regular updates will keep your application up to date with security fixes and prevent it from relying on potentially outdated libraries.
This is an application of Postel's Law: Packages should be liberal in the range of package versions that they can accept, and applications should be strict about using up to date packages when they run.
It is similar to this rule of preferring to use a parameter of a base type or interface as it allows wider use.
Inspired by Greenkeeper.