Renovate Bot - Packages upgrade made easy

In the software world, we want to keep close control of our dependencies to prevent unwanted bugs but we also wanna keep those same dependencies up to date to prevent getting behind on safety or performance. Unfortunately, this is not an easy task to achieve and can on large projects easily fall behind or overwhelm the team with constant upgrades.

Recently we found that there's a better way to do it, with renovate you can configure a bot that will create pull requests automatically with the outdated packages.

Let's start putting these concepts in practice so we can learn a little more

Create a basic project

First, let's create a basic react project using CRA.

npx create-react-app my-renovate-app --template typescript cd my-renovate-app

Now if you open the package.json file you will see the small ~ before the package version, let's remove it.

{ ... "dependencies": { "@testing-library/jest-dom": "5.11.4", "@testing-library/react": "11.1.0", "@testing-library/user-event": "12.1.10", "@types/jest": "26.0.15", "@types/node": "12.0.0", "@types/react": "17.0.0", "@types/react-dom": "17.0.0", "react": "17.0.1", "react-dom": "17.0.1", "react-scripts": "4.0.3", "typescript": "4.1.2", "web-vitals": "1.0.1" }, ... }

This will force the versions on the package.json to be the exact one that was defined.

Also to enforce the version of any future installation set the flag save-exact to true.

echo "save-exact=true" >> .npmrc

Finally, clean the old lock file and generate a new one.

rm -rf node_modules yarn.lock yarn

Now we have a project that enforces the exact version on all the packages and we're ready to configure the renovate.

Configure renovate

First, we need to install renovate on the GitHub market place, link here. We can either apply renovate to all the repo or to only one, to start we select only the repo that we created before. Once you install and select the repo it will generate a PR with some context and a renovate.json file where you can configure the application.

Instead of renovate.json we rename the file to .renovaterc.json mostly to hide the file on the folder but you can choose the name that you wanna from this list.

Let's merge this now and we can see the default config of renovate.

  • 2 PR's per hour
  • max of 10 PR's
  • No automerge

But this doesn't suit my needs, it creates PR with Major upgrades v1.x.x to v2.x.x for example and personally, I don't like that option because from my experience major upgrades come with bugs that require some extra debugging.

Let's change the configs to suit our needs

{ "timezone": "Europe/London", // set a timezone is good for team on different timezones "extends": [ "config:base", ":maintainLockFilesWeekly", //Run lock file maintenance (updates) early Monday mornings ":renovatePrefix", // Use renovate/ as prefix for all branch names ":prHourlyLimitNone", // no limit of PR's per hour ":prConcurrentLimit10", // limit the number of PR's to 10 ":disableMajorUpdates", // disable the major upgrades v1.x to v2.x ":automergeDisabled" // Disable automerging feature - wait for humans to merge all PRs ], "baseBranches": ["master"], // name of the main branch that the bot will use to compare versions "labels": ["renovate"], // label used on the PR's "gitAuthor": "Renovate Bot <bot@renovateapp.com>", "dependencyDashboard": true, // creates a dashboard under issues on the repo for easy maintenance "dependencyDashboardTitle": "Renovate Dependency Dashboard", "commitMessagePrefix": "[RENOVATE] ", // Prefix of the PR "stabilityDays": 3, "schedule": [ "before 7am on Monday" // run every monday at 7AM UTC ], "packageRules": [ { "groupName": "devDependencies", "matchDepTypes": ["devDependencies"], // update dev dependencies last and group them "prPriority": -1 // priority -1 will make this rule run last }, { "groupName": "definitelyTyped", "matchPackagePatterns": ["^@types/"], "prPriority": -1 } ] }

Now we have a full renovate bot configured that will make create PR's for all the minor and patches on our codebase until the maximum of 10.

On this configuration, we choose not to group all the non-major upgrades but that can be easily done with this

{ "packageRules": [ { "matchPackagePatterns": ["*"], "matchUpdateTypes": ["minor", "patch"], "groupName": "all non-major dependencies", "groupSlug": "all-minor-patch" } ] }

Code

You can see a repo with an example of the code that we created here on this repo. It has the dashboard and the open PR's that are left open by purpose.