Small recap
In my earlier post, I already mention Renovate few times:
But a small recap about, what is Renovate. Renovate is an automated dependency update tool. It helps to update dependencies in your code without needing to do it manually. When Renovate runs on your repo, it looks for references to dependencies (both public and private) and, if there are newer versions available, Renovate can create pull requests to update your versions automatically.
What is the plan for now?
I want to expand that things that I can monitor with Renovate. It is very easy, out of the box solution, to monitor Containerfile or Dockerfile. But what about packages within it? To see what is my point here, let’s see a Containerfile implementation:
FROM docker.io/library/debian:bookworm-slim@sha256:b1211f6d19afd012477bd34fdcabb6b663d680e0f4b0537da6e6b0fd057a3ec3
RUN apt-get update \
&& apt-get -y install \
git \
wget \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir /app
WORKDIR /app
COPY ./build.sh .
RUN wget -q https://github.com/gohugoio/hugo/releases/download/v0.147.0/hugo_extended_0.147.0_Linux-64bit.tar.gz \
&& mkdir hugo_pack \
&& tar -xvf hugo_extended_0.147.0_Linux-64bit.tar.gz -C hugo_pack/ \
&& mkdir bin \
&& mv hugo_pack/hugo bin/hugo \
&& rm -rf hugo pack hugo_extended_0.147.0_Linux-64bit.tar.gz \
&& chmod +x ./build.sh
CMD ["./build.sh"]
So, what is the problem here? Container version is pinned, so that should be fine, so this is a good Containerfile, right? Unfortunately, not enough good (at lest for me). Why? The installed packages are not tracked, like git and wget from Debian repository and hugo from Github release.
So the plan is to make it possible to monitor those with Renovate!
Modify Containerfile
First, I modify the Containerfile. I pin the version for the apt packages. But for practical reasons, I store the version in variables, because it will be easier make regex for that.
Debian package version can be fetched with apt search command. Example for wget:
$ apt search wget
wget/stable,stable,now 1.21.3-1+deb12u1 amd64 [installed]
retrieves files from the web
The version number for wget is 1.21.3-1+deb12u1.
For Hugo, the version is visible in the Github release page: Hugo releases.
When I write this article, it is 0.147.0.
After a small modification, this is my Containerfile.
FROM docker.io/library/debian:bookworm-slim@sha256:b1211f6d19afd012477bd34fdcabb6b663d680e0f4b0537da6e6b0fd057a3ec3
ARG GIT_DEB_VERSION=1:2.39.5-0+deb12u2 # suite=bookworm depName=git
ARG WGET_DEB_VERSION=1.21.3-1+deb12u1 # suite=bookworm depName=wget
ARG HUGO_GITHUB_VERSION=0.147.0 # depName=gohugoio/hugo
RUN apt-get update \
&& apt-get -y install \
git=${GIT_DEB_VERSION} \
wget=${WGET_DEB_VERSION} \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir /app
WORKDIR /app
COPY ./build.sh .
RUN wget -q https://github.com/gohugoio/hugo/releases/download/v0.147.0/hugo_extended_${HUGO_GITHUB_VERSION}_Linux-64bit.tar.gz \
&& mkdir hugo_pack \
&& tar -xvf hugo_extended_${HUGO_GITHUB_VERSION}_Linux-64bit.tar.gz -C hugo_pack/ \
&& mkdir bin \
&& mv hugo_pack/hugo bin/hugo \
&& rm -rf hugo pack hugo_extended_${HUGO_GITHUB_VERSION}_Linux-64bit.tar.gz \
&& chmod +x ./build.sh
CMD ["./build.sh"]
Now we have pinned versions, that’s cool. But unfortunately, Renovate does not support it out of the box.
Write regex to capture the lines
Basically, I have to write two kind of regex:
- One to catch the Debian version
- Another one to catch Github release version
I have put some comment after ARG statement, that helps me to give parameters
to Renovate.
Regex for Debian package:
ARG\s+(?<depName>[A-Z0-9_]+)_DEB_VERSION=(?<currentValue>[^\s#]+)\s+#\s+suite=(?<suite>[^\s]+)\s+depName=(?<packageName>[^\s]+)
Let’s break it what it does mean:
ARG\s: Line start with “ARG” and followed by a space.(?<depName>[A-Z0-9_]+): Capture group fordepName. It can contains upper case characters, numbers and ‘_’ symbol._DEB_VERSION=: Followed by this static string.(?<currentValue>[^\s#]+): Capture group forcurrentValue. Matches with characters that are not whitespace or ‘#’ symbol.\s+#\s+suite=: Followed by a space, then ‘#’ symbol, space again, then ‘suite=’(?<suite>[^\s]+): Capture the suit. This tell which Debian repository should be checked.\s+depName=: Followed by one or more space and ‘depName=’.(?<packageName>[^\s]+): CapturepackageName.
The regex for Github release looks very similar.
"ARG\s+(?<depName>[A-Z0-9_]+)_GITHUB_VERSION=(?<currentValue>[^\s#]+)\s+#\s+depName=(?<packageName>[^\s]+)"
The final renovate.json can be seen in the next code snippet.
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"customManagers": [
{
"customType": "regex",
"managerFilePatterns": ["/^Containerfile$/"],
"matchStrings": [
"ARG\\s+(?<depName>[A-Z0-9_]+)_DEB_VERSION=(?<currentValue>[^\\s#]+)\\s+#\\s+suite=(?<suite>[^\\s]+)\\s+depName=(?<packageName>[^\\s]+)"
],
"datasourceTemplate": "deb"
},
{
"customType": "regex",
"managerFilePatterns": ["/^Containerfile$/"],
"matchStrings": [
"ARG\\s+(?<depName>[A-Z0-9_]+)_GITHUB_VERSION=(?<currentValue>[^\\s#]+)\\s+#\\s+depName=(?<packageName>[^\\s]+)"
],
"datasourceTemplate": "github-releases",
"autoReplaceStringTemplate": "ARG {{{depName}}}_GITHUB_VERSION={{{newValue}}} # depName={{{packageName}}}"
}
]
}
💡 Tip
In renovate.json the “\s” must be escaped with “\\s”.Test Renovate configuration locally
I want to be sure that this configuration works as intended before I would merge it with main. To do it, Renovate must be installed locally. This is explained here. Then it has to be run locally, by the following command.
But before run it, I reduced the version numbers in Containerfile. So I must get new version update in the log!
LOG_LEVEL=debug npx renovate --platform=local --onboarding=false
The output is verbose, I don’t paste full here, just the important part.
It can be seen, that it has found one dockerfile and 3 regex matches. First sign, it looks good.
INFO: Dependency extraction complete (repository=local)
"stats": {
"managers": {
"dockerfile": {"fileCount": 1, "depCount": 1},
"regex": {"fileCount": 2, "depCount": 3}
},
"total": {"fileCount": 3, "depCount": 4}
}
The next part validates that my configuration is okay, because it shows upgrade for Hugo and Git packages, that I set to previous version before run renovate.
DEBUG: packageFiles with updates (repository=local)
"config": {
"dockerfile": [
{
"deps": [
{
"depName": "docker.io/library/debian",
"packageName": "docker.io/library/debian",
"currentValue": "bookworm-slim",
"currentDigest": "sha256:b1211f6d19afd012477bd34fdcabb6b663d680e0f4b0537da6e6b0fd057a3ec3",
"replaceString": "docker.io/library/debian:bookworm-slim@sha256:b1211f6d19afd012477bd34fdcabb6b663d680e0f4b0537da6e6b0fd057a3ec3",
"autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
"datasource": "docker",
"depType": "final",
"updates": [],
"versioning": "docker",
"warnings": []
}
],
"packageFile": "Containerfile"
}
],
"regex": [
{
"deps": [
{
"depName": "git",
"packageName": "git",
"currentValue": "1:2.39.5-0+deb12u1",
"datasource": "deb",
"replaceString": "ARG GIT_DEB_VERSION=1:2.39.5-0+deb12u1 # suite=bookworm depName=git",
"updates": [ <==== HERE WE HAVE THE DEBIAN PACKAGE UPDATE
{
"bucket": "non-major",
"newVersion": "1:2.39.5-0+deb12u2",
"newValue": "1:2.39.5-0+deb12u2",
"newMajor": 2,
"newMinor": 39,
"newPatch": 5,
"updateType": "patch",
"branchName": "renovate/git-2.x"
}
],
"versioning": "deb",
"warnings": [],
"registryUrl": "https://deb.debian.org/debian?suite=stable&components=main,contrib,non-free&binaryArch=amd64",
"homepage": "https://git-scm.com/",
"currentVersion": "1:2.39.5-0+deb12u1",
"isSingleVersion": true,
"fixedVersion": "1:2.39.5-0+deb12u1"
},
{
"depName": "wget",
"packageName": "wget",
"currentValue": "1.21.3-1+deb12u1",
"datasource": "deb",
"replaceString": "ARG WGET_DEB_VERSION=1.21.3-1+deb12u1 # suite=bookworm depName=wget",
"updates": [],
"versioning": "deb",
"warnings": [],
"registryUrl": "https://deb.debian.org/debian?suite=stable&components=main,contrib,non-free&binaryArch=amd64",
"homepage": "https://www.gnu.org/software/wget/",
"currentVersion": "1.21.3-1+deb12u1",
"fixedVersion": "1.21.3-1+deb12u1"
}
],
"matchStrings": [
"ARG\\s+(?<depName>[A-Z0-9_]+)_DEB_VERSION=(?<currentValue>[^\\s#]+)\\s+#\\s+suite=(?<suite>[^\\s]+)\\s+depName=(?<packageName>[^\\s]+)"
],
"depNameTemplate": "{{ matches.packageName }}",
"datasourceTemplate": "deb",
"packageFile": "Containerfile"
},
{
"deps": [
{
"depName": "gohugoio/hugo",
"packageName": "gohugoio/hugo",
"currentValue": "0.146.7",
"datasource": "github-releases",
"replaceString": "ARG HUGO_GITHUB_VERSION=0.146.7 # depName=gohugoio/hugo",
"updates": [ <==== HERE WE HAVE THE HUGO GITHUB RELEASE UPDATE
{
"bucket": "non-major",
"newVersion": "v0.147.0",
"newValue": "0.147.0",
"releaseTimestamp": "2025-04-25T17:17:15.000Z",
"newVersionAgeInDays": 0,
"newMajor": 0,
"newMinor": 147,
"newPatch": 0,
"updateType": "minor",
"libYears": 0.008160641806189752,
"branchName": "renovate/gohugoio-hugo-0.x"
}
],
"versioning": "semver-coerced",
"warnings": [],
"sourceUrl": "https://github.com/gohugoio/hugo",
"registryUrl": "https://github.com",
"currentVersion": "v0.146.7",
"currentVersionTimestamp": "2025-04-22T17:48:01.000Z",
"currentVersionAgeInDays": 3,
"isSingleVersion": true,
"fixedVersion": "0.146.7"
}
],
"matchStrings": [
"ARG\\s+(?<depName>[A-Z0-9_]+)_GITHUB_VERSION=(?<currentValue>[^\\s#]+)\\s+#\\s+depName=(?<packageName>[^\\s]+)"
],
"depNameTemplate": "{{ matches.packageName }}",
"datasourceTemplate": "github-releases",
"packageFile": "Containerfile"
}
]
}
Now that everything looks good, commits can be pushed, then merged with main!
See the result in practice
After merge, I have let run my Renovate container to see what is happening. Dependency dashboard has been open and shows what is expected.

Final words
I really start to like Renovate, it has a lot of potential and customization option. It is not a question that I will keep to use it in the future!