You probably have seen or even use GitHubs dependabot. I couldn’t easily find how I might be able to use it in my homelab, on-premise. I came across Renovate Bot from Mend recently-ish. The docs looked promising. So, I tried it out on GitHub first.

The docs are very comprehensive, however you still get started quickly. They might be overwhelming (but, to be fair, only at the very beginning) if you want to fine-tune things.

What are my dependencies?

So, my use case was easy keep the dependencies of my small testing app up to date. But hold on, what are my dependencies actually?

The obvious ones:

  • Basically everything with a version in the pom.xml
  • The base images I use to build the container image, referenced in the respective containerfile

The not so obvious ones:

Initial Setup

Potentially having more than one app / repo to keep up to date, I opted to create my own repo which basically just has two jobs:

  1. provide a general renovate config I can use for all of my repos, so I don’t have to specify everything for each and every repo again. That works well, knowing that renovate configs can be inherited, and therefore, specific settings you might want to configure differently, can still be overriden.
  2. Let the renovate bot run regularly to update my repos

The repo where this is setup is https://github.com/jeichler/renovate-bot

Basically I needed 3 things: a config that handles onboarding, a default config that others repo can inherit from, and a workflow that runs the renovate bot regularly.

Here goes…

The Renovate Configs

The config to handle onboarding etc., renovate.json:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "local>jeichler/renovate-bot",
    "default:automergeDigest"
  ],
  "dryRun": null,
  "onboarding": true,
  "dependencyDashboard": true,
  "platform": "github",
  "repositories": [
    "jeichler/renovate-bot",
    "jeichler/api-endpoint",
    "jeichler/execution-environments",
  ]
}

I like the dependency dashboard, great overview about my deps. I do not want automatic onboarding of every repo, so I selectively decide which one to include. Platform is GitHub, and since it’s just me, myself, and I, who needs a dry run anyway :) If it fails, it fails.

The config that other repos can inherit from, default.json

{
    "$schema": "https://docs.renovatebot.com/renovate-schema.json",
    "extends": [
        "config:base",
        ":rebaseStalePrs",
        ":semanticCommits",
        "docker:pinDigests",
        ":pinVersions"
    ],
    "rebaseWhen": "behind-base-branch",
    "automergeType": "pr",
    "platformAutomerge": true,
    "packageRules": [
      {
        "matchUpdateTypes": ["minor", "patch", "pin", "digest"],
        "automerge": true
      }
    ],
    "regexManagers": [
      {
        "description": "Update _VERSION variables in Dockerfiles",
        "fileMatch": ["(^|/|\\.)Dockerfile$", "(^|/)Dockerfile\\.[^/]*$"],
        "matchStrings": [
          "# renovate: datasource=(?<datasource>[a-z-]+?) depName=(?<depName>.+?)(?: (?:packageName|lookupName)=(?<packageName>.+?))?(?: versioning=(?<versioning>[a-z-]+?))?\\s(?:ENV|ARG) .+?_VERSION=(?<currentValue>.+?)\\s"
        ],
        "versioningTemplate": "{{#if versioning}}{{versioning}}{{else}}semver{{/if}}"
      }
    ]
  }

Ok, that looks like a bit much at the beginning. It has grown over time, don’t worry.

Basically what it says (the important bits):

  • inherit solid defaults defined by the renovate team (config:base).
  • use semantic commit messages (:semanticCommits). Using that in combo wiht semantic-releases is on my todo-list.
  • packageRules: automerge various things. I am lazy, so I don’t want to review each and every PR whenever something changes. Since it’s just pet projects, and at least for my testing app there are tests before a PR can be merged, I automerge pretty much everything relevant for me that is not a major version change.
  • docker:pinDigests: In times of floating tags for container images, I want to make sure I build my images when the base image gets updated. So, digests are for me non-optional and the only true unique identifier.
  • the elephant in the room. the regexManagers. Why? Remember my ARG in the Dockerfile? It’s nothing the renovate bot automatically detects, so that’s the mechanism to instruct renovate to thread *_VERSION in *Dockerfile* as dependency. This relies on me having a comment field above the actual _VERSION string in this file that tells renovate which dependency it is, what it’s datasource is etc.

The GitHub Workflow

The GH workflow is fairly simple:

name: Renovate
on:
  workflow_dispatch:
  schedule:
    - cron: '0 0/1 * * *'
  push:
    branches:
      - main

jobs:
  renovate:
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v3.6.0
      - name: renovate
        uses: renovatebot/github-action@v39.0.4
        with:
          useSlim: true
          configurationFile: renovate.json
          token: ${{ secrets.RENOVATE_TOKEN }}
        env:
          LOG_LEVEL: info

Obviously the github actions are updated by renovate itself. It uses the renovate.json file I showed above.

Granted, the workflow runs a bit often (hourly), but it’s still early days for me, so once I have a more stable config, I shall reduce it to potentially daily.

Happy renovate-ing!