Photo by David Pisnoy on Unsplash

Renovate Your Software

Johann Gyger
ITNEXT
Published in
5 min readApr 6, 2021

--

Code rots. The day you release it, your software becomes a legacy. Some call this technical debt. You have to maintain actively. This article shows you how.

Problem statement

Today's software contains many dependencies. Typically, you use a plethora of open-source libraries for your programming language of choice. Your build tool will introduce additional dependencies. Moreover, you’ll probably use container technology to ship your program, adding even more dependencies.

Those dependencies impose the core problem: New versions get released quickly. There are different drivers: bugs are fixed, features are added—changes may be downwards compatible or breaking. You typically don’t want to manually update all dependencies to the latest version all the time because it is tedious work and would take too much time.

However, severe bugs and security vulnerabilities need to be fixed quickly. And if you don’t update your dependencies regularly, you might be confronted with a lot of work because the gap gets larger and larger, ending up in a costly migration project.

Let me illustrate this with a couple of popular dependencies:

Let’s have a look at recent severe vulnerabilities:

Solution strategy

So, what are your options?

The best strategy to tackle this problem is to automate dependency updates.

Why? First, you keep up-to-date with your dependencies. No more extra planning for major updates—you do it continuously. Second, you’ll get immediate feedback if something breaks due to a dependency update (provided you have enough automated tests). Third, you're much less confronted with vulnerabilities because you’ve already updated. No application security testing tool will nag you anymore.

Renovate

Are there any tools that help you implement this strategy? Yes, there are. Renovate is such a tool. It helps you automate dependency updates, and it does so very well.

Step 1: Getting started

There are basically two ways how you can use Renovate:

  • GitHub App: To activate your repositories on GitHub, use this handy integration. (Note that for GitLab.com, you have to use the self-hosted variant below.)
  • Self-hosted: For all other variants (on-premises including GitLab.com and local execution), Renovate is packaged as a Node module and Docker image with various integrations for different platforms.

Step 2: Onboarding

When the Renovate bot runs for the first time, it will look for a renovate.json config file in the root of your project repositories. If it doesn’t find such a file (or some alternate location), it will create an onboarding pull/merge request and will propose to add such a file with the following default configuration:

{
"extends": [
"config:base"
]
}
Onboarding PR

Once you merge this PR, Renovate will start to … renovate 😃

Step 3: Configuration

Renovate is highly configurable. This might be a bit overwhelming when you start to use Renovate. You can browse all the configuration options, and there are even more options for self-hosted instances.

Note that you can add configuration options to renovate.json; self-hosted options — including the configuration options above — act as a central config and belong to a config.js/config.json in your self-hosted instance.

Step 4: Re-use configuration

You can re-use common configuration by adding it to the “extends” array of a renovate.json. Here’s an example of how to enable Docker major updates:

{
"extends": [
"config:base",
"docker:enableMajor"
]
}

Renovate already comes with a rich set of config presets. Additionally, you can define your presets and share them with your software projects. Here’s an example of a custom preset usage located at github>johanngyger/blog (see naming conventions for all preset hosting options):

{
"extends": [
"config:base",
"github>johanngyger/blog"
]
}

For self-hosted instances, you can also add your default config in config.js so that you don’t have to add it to the “extends” array of each renovate.json.

Renovate concepts

Before we can dig deeper into the configuration options, you have to understand some core concepts of Renovate:

Managers act as the main abstraction for language-dependent package managers, such as npm (JavaScript), Maven (Java), Bundler (Ruby), Composer (PHP), and so on. A manager's goal is to detect a certain type of dependency called a “package” in Renovate terminology.

Data sources know how to update a package. Once a manager identifies a package, it will be assigned to a corresponding data source that knows how to get available versions.

Versioning is the abstraction for different versioning schemes, such as semantic versioning. This is the last step of the update process. After a package has been identified and available versions have been detected, the versioning scheme determines the new version.

Package rules

Renovate supports a wide range of languages and tries to reflect their ecosystem's features. Renovate has sensible defaults, but sometimes you want to override these, and that's where package rules come into play. You can add your own rules to the “packageRules” array.

Here are some examples I found useful. The first one will enable Docker updates for major versions which are disabled by default:

"packageRules": [
{
"matchDatasources": ["docker"],
"matchUpdateTypes": ["major"],
"enabled": true
}
]

The next one will automatically merge all Docker packages. By default, Renovate will do so in two runs. The first run will create the PR, and a subsequent run will merge the PR. (For GitLab, there’s a nifty gitLabAutomerge option, so that merge requests are automatically merged when the pipeline succeeds.)

"packageRules": [
{
"matchDatasources": ["docker"],
"automerge": true,
"gitLabAutomerge": true
}
]

The following rule will group Go module updates so that PRs won’t flood you:

"packageRules": [
{
"matchDatasources": ["go"],
"groupName": "Go modules",
"groupSlug": "gomod",
"separateMajorMinor": false
}
]

Regex managers

Sometimes the default managers don’t spot a package. You can add your manager by using a custom regular expression.

The following example changes how Docker repositories are organized, i.e., it supports sub-repositories. Additionally, a different versioning scheme is used:

"regexManagers": [
{
"fileMatch": [
"(^|/|\\.)Dockerfile$",
"(^|/)Dockerfile\\.[^/]*$"
],
"matchStrings": ['FROM (?<depName>\\S*):(?<currentValue>\\S*)'],
"datasourceTemplate": "docker",
"versioningTemplate": "loose"
}
]

Conclusion

Managing dependencies in your code takes time. Renovate can automate a part of it by updating dependencies automatically. Renovate already does a fantastic job in the base configuration, and you should activate it right now. However, Renovate will create PRs constantly, so you have to react.

To get the most out of Renovate, you have to study the docs. You also have to understand the configuration options and experiment with them. Sometimes you even have to study the Renovate source code. However, once Renovate operates according to your needs, it is a great joy.

--

--