How to use Renovate to maintain your project dependencies

You are currently viewing How to use Renovate to maintain your project dependencies
Please share

The key to a sustainable codebase: continuous maintenance

As a Software Engineer, you often have to reconcile two conflicting objectives: maintaining your existing applications available and secured, while delivering new and exciting features to the world. Since you have limited time on your hands, keeping your old projects up to date with the latest software version is treated as a tedious task, which is postponed until an EOL of a major framework is coming.

It often seems counter-intuitive: why change something that already works? That’s why management is often not keen on investing time (and therefore money) into maintaining frozen projects.

They would pay just to keep the same value or even lose a bit since, every time you touch old software, there is indeed a risk of breaking the existing setup. Yep, even with the 80% test coverage, you touched on an inconspicuous part of the code which was holding everything together.

But this is a short-term view, in fact, you invest a bit of time to prevent big incidents (or a complete software rewrite) months or years later. For a more concrete example, let’s assume that you manage a few Java applications, and then the Log4J vulnerability is revealed to the world. Suddenly, you have to drop all your current work to update a bunch of applications that you may have never touched.

Their maintainer has obviously left the company, but you just need to update a dependency file, commit to the main branch, and CI/CD will take care of the rest, right? That is often the moment that you discover that the app needs some manual steps for proper development, that a token is expired, and that the app only works because it had not been restarted for 6 months.

Now that you understand the struggle for one exceptional event, the hard truth is that it happens quite often (EOL of a framework is also a good example), and for your teams, it is nerve-breaking to always struggle with big and dangerous updates.

That’s why continuous dependency management is the key to sustainable project management. It promotes a healthy work schedule for your teams (no urgency, just daily or weekly updating work) and forces them to invest in proper continuous delivery automation to reduce the toil. You don’t leave any old project behind, and there is no uncharted part of your codebase.

Renovate: a great tool to automate dependency updates

While there are other tools (listed below), I recommend Renovate for both its simplicity and heavy customization.

On GitHub, you simply need to add the Renovate App to some or all the repos of your organization. It is a managed app and runs regularly on repositories, or when a change occurs, such as a commit on the main branch.

When Renovate runs on a repository that doesn’t contain a renovate.json file, it creates a welcome Pull Request, which lists all the detected dependencies of your project.

It adds the following renovate.json at the root of the repository.

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:base"
  ]
}

You can merge it right away to go with the default configuration (which is quite fine), or modify the PR to configure Renovate to your needs (see below for recommended configurations).

How it works

Renovate runs regularly on your repos, detecting dependencies such as NPM packages, Docker tags, Terraform versions, etc… It then fetches the latest versions from the upstream registries. If a new version is available, it will then open a PR with the proposed changes. Renovate will group changes if possible: for example, it will update the python version on all Dockerfile with the same PR).

Renovate can also automatically merge PRs if they successfully pass tests. For patch or minor versions, it is a sane idea, as long as you have automated tests… If you modify the main branch, it will automatically rebase the PR to keep up with the latest trunk versions.

50 ways to configure Renovate

Renovate can be extensively configured with its renovate.json file.

The easiest way is to extend an existing configuration, which packages one or several options, in a preset. By default, it extends the config:base preset.

When you need to modify a parameter, have a look at the existing presets. If you find one that suits you, add it to the extends list. For instance, if you want to deactivate Major version updates, use the:disableMajorUpdates preset.

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:base",
    ":disableMajorUpdates"
  ]
}

For example, the following basic presets are interesting:

  • :label(renovate): use the renovate label on all PRs opened by Renovate. It helps organize PRs.
  • :separateMultipleMajorReleases: open one PR per Major update. It allows to migrate one major at a time, which is recommended to handle breaking changes or a bug.

Lastly, if you need finer control over this tool, the packageRules block is another powerful element of Renovate: by matching package names, update types, and other criteria, you can configure specific actions on some packages only.

For example, a useful packageRules is to regroup all Patches together, to reduce the number of PR.

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:base",
    ":disableMajorUpdates"
  ]
}

All these options will contribute to creating quite a lot of pull requests, that you can track with a handy Dependency Dashboard, opened as an issue in your repository.

Now your maintenance work is automatically delivered to your backlog!

Going on with automation

However, you now have a bunch of small updates to handle, which you often merge anyway since it’s a minor and unimpactful update. It seems that you have added toil to your daily work. As an SRE, a tedious and repetitive task is an opportunity for automation!

That’s why one of the more powerful features of Renovate is the automated merging, or automerging, of dependencies updates if tests are OK. The official Renovate documentation recommends that “you enable automerge for any type of dependency update where you would just click Merge anyway.

If you have tests, and all your tests are successful, Renovate will merge the PR. That is now a good excuse to invest in a proper CI/CD toolchain, and some code coverage.

Renovate also correctly handles semantic versioning with conventional commits to integrate tightly into your CI/CD workflow, which is mandatory if you use release automation tools such as Release Please or Semantic Release. By default, Renovate will analyze your repo commits, and determine if you use semantic commits for its PR, with the following convention:

  • defaults to the chore prefix: chore(deps): update...
  • uses the fix prefix for npm production dependencies: fix(deps): update...
  • uses the chore prefix for npm development dependencies (devDependencies)

For a lot of use cases, such as Terraform modules, it means it will use chore by default, which is not always the desired behaviour. Indeed, if you update a dependency in your module, it will impact downstream, you want to inform your users of a new release. Therefore you can force the use of the fix prefix with the following preset :semanticPrefixFix

Finally, if you have strong test and deployment automation with tools such as ArgoCD Image Updater, you will have a self-maintained repository, for which you will only handle major updates.

Self-hosting and alternatives

If you are not on GitHub, or simply value your privacy, you can easily self-host Renovate. It is a simple CLI, which only needs a Git Provider token and some configuration. For example, it can run in a GitLab CI schedule, or as a Kubernetes cronjob.

There are other tools in the same field that I find less complete or easy to use:

  • Github Dependabot is the strongest opponent of Renovate, GitHub’s integrated supply chain security bot. It bases its security alerts on the GitHub Advisory Database, which contains advisories reviewed by GitHub, as well as many, many more unreviewed advisories. It will then open PRs with suggested updates. It supports fewer languages that Renovate and does not have the same automation options. However, if you only want to be warned of security updates, it is a fine tool.
  • Snyk is a security chain SaaS. It is similar to SonarQube as it has a separate interface to monitor security, According to the Snyk documentation, “Snyk currently supports the Automatic dependency upgrade pull requests feature for npm, Yarn, and Maven-Central repositories”. I haven’t had an opportunity to test it, but it seems less powerful than the other tools.
  • ArgoCD Image Updater can be seen as a dependency automation tool since it commits new versions to a Git Repository. If you use ArgoCD, it is a great tool that I recommend! It is complementary to Renovate, for the final container images that you deploy.

Conclusion

I hope that I convinced you to try to Renovate to automate the maintenance of your repositories. As the mass of software keeps growing in your projects, investing in automation is the key to sustainable software companies. Renovate can be one of the many tools in your CI/CD toolchain!