Metabase is a really nice free software business intelligence tool. It’s quite easy to deploy; they provide a Docker image and all you really need for a production instance is your own database.

I use Flux to manage my cluster so I thought it would be nice to utilise image update automation to keep up to date with updates automatically. But Metabase makes this slightly difficult because it doesn’t use proper semantic versioning on the image tags.

Normally one would write an ImagePolicy like the following to pick up all minor and patch releases on the 54 major version:

 1apiVersion: image.toolkit.fluxcd.io/v1beta2
 2kind: ImagePolicy
 3metadata:
 4  name: metabase
 5spec:
 6  imageRepositoryRef:
 7    name: metabase
 8  policy:
 9    semver:
10      range: "54.x"

Metabase’s versioning scheme is described as loosely like semver with the major difference being they prepend a 0. to the beginning to indicate it’s the OSS version of the software. So rather than v54.7.2 it’s v0.54.7.2.

This is no problem because Flux supports a pattern and extract allowing you to write a regular expression and extract parts of the tag representing the semver, like so:

 1apiVersion: image.toolkit.fluxcd.io/v1beta2
 2kind: ImagePolicy
 3metadata:
 4  name: metabase
 5spec:
 6  imageRepositoryRef:
 7    name: metabase
 8
 9  filterTags:
10    pattern: '^v0.(?P<version>.*)$'
11    extract: '$version'
12
13  policy:
14    semver:
15      range: "54.x"

This would take v0.54.7.2 and extract 54.7.2. Perfect.

But there is another problem: for some reason the first release of each minor version is not tagged the same. Instead of v0.54.8.0 it gets tagged simply as v0.54.8 which would be turned into 54.8 by the above and not parsed correctly as semver.

This took a lot more head scratching. We need to somehow append an extra .0 to the end of the version in case we find a “degenerate” semver like 54.8. The problem with regexp is we can’t generate anything that isn’t there in the string we are matching against; there’s no default if no match is found for a group. But luckily there is both a dot and a zero in the tag for us to use. So behold the following monstrosity:

 1apiVersion: image.toolkit.fluxcd.io/v1beta2
 2kind: ImagePolicy
 3metadata:
 4  name: metabase
 5spec:
 6  imageRepositoryRef:
 7    name: metabase
 8
 9  filterTags:
10    pattern: '(^v(?P<patch>0)(?P<dot>\.)(?P<majorminor>\d+\.\d+)$)|(^v0\.(?P<majorminorpatch>\d+\.\d+\.\d+)$)'
11    extract: '$majorminor$dot$patch$majorminorpatch'
12
13  policy:
14    semver:
15      range: "54.x"

This now works for both full patch level versions like v0.54.7.2 and the degenerate versions like v0.54.8. Hope this helps someone.