Anthony Steele edited this page Nov 11, 2018 · 36 revisions

NuKeeper Logo

Automagically update NuGet packages in .NET projects.

NuKeeper is a global tool on NuGet. Install with dotnet tool install nukeeper --global

Build Status Gitter NuGet

Other pages

What

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 GitHub server.
  • Apply NuGet package updates to .NET code on the local file system.
  • Make pull requests containing updates to code on a GitHub server.

Why

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...".

How

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:

Command lines called: nuget.exe and/or dotnet.

Limitations and warnings

Source control

NuKeeper works with git, no other source control systems are supported for raising pull requests. You can however use the public github.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.

Betas

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.

Package tools required

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.

Install scripts

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.

When to use NuKeeper

Scope of NuKeeper

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.

Updating libraries

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.

Footnote

Inspired by Greenkeeper.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.