📚

Renovateで任意のファイルをアップデート対象にする(Earthfileの例)

2022/08/15に公開

以前Earthlyというビルドツールについての紹介記事を書きました。

https://zenn.dev/kesin11/articles/7f4eed7cabf38d

Earthlyによる開発体験はおおむね気に入っているのですが、Dockerfileでビルドしていたときに便利だったRenovateによるイメージタグの自動アップデートができなくなってしまったのは唯一の心残りでした。

Renovateはかなり多様なパッケージマネージャに対応しているのですがEarthlyはまだ未対応です。おそらくEarthly自体が英語圏を含めてもまだそれほど知名度が高くないのか、執筆時の2022/08/15時点では機能追加のIssueがかろうじて最近作られたばかりのようです。

https://gkzz.dev/posts/renovate-regex-manager

先日見たこちらの記事に触発され、もしかしてRenovateに機能追加されなくてもrenovate.jsonの設定をちょっと頑張ればEarthfileをDockerfileとして認識させてアップデートできるのでは?と考えたので試してみました。

EarthfileをDockerfileとして認識させる

先ほどの記事はRegex Managerでファイル名と文字列のパース方法の両方を指定するものでしたが、Earthfileの FROM に指定するイメージタグの記法は基本的にDockerfileと同じ[1]なので、バージョン文字列をパースする正規表現を再発明する必要はありません。

いきなり結論を書くと、renovate.jsonを以下のように設定することでRenovateはEarthfileをDockerfileとして認識してくれるようになり、FROM に指定されているイメージタグを自動でアップデートしてくれるようになりました。

// 最小構成のrenovate.json
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:base"
  ],
  "dockerfile": {
    "fileMatch": ["(^|/)Earthfile[^/]*$"]
  }
}

この設定で以下のようなEarthfileに対してもRenovateがアップデートしてくれるようになります。Earthfileはディレクトリの下にネストして置かれていたり、ルートの位置に配置したEarthfileと合わせて複数存在していても問題ありません。

# Earthfile
VERSION 0.6

FROM ubuntu:18.04
WORKDIR /build

all:
  BUILD +major
  BUILD +minor
  BUILD +patch
  BUILD +withdigest

major:
  FROM node:16
  RUN echo "major"
minor:
  FROM node:16.15
  RUN echo "minor"
patch:
  FROM node:16.15.0
  RUN echo "patch"
withdigest:
  FROM node:lts-alpine3.15@sha256:e49e95e3f8848efc271b45633bddf49b125dac4d9f1a100b32bb0b1e0bfa1b13
  RUN echo "withdigest"

このサンプルのEarthfileよりはイメージタグ指定に関してはシンプルなものですが、実際に自分がメンテしているCIAnalyzerではこのように2つのpull-requestが作成されました。

https://github.com/Kesin11/CIAnalyzer/pull/599
https://github.com/Kesin11/CIAnalyzer/pull/600

ちなみに#600のnode.js v18へのアップデートがcloseしているのは故意です。18は現時点でまだLTSではないため今すぐにはアップデートしたくないのでcloseしてあります。

仕組み

Renovateのconfigの各項目は複雑で、自分も完全に正しく把握していない可能性がありますが現時点での理解を説明します。

Renovateはおおむねこの3つの要素でアップデートする対象を追跡しているようです。

  • ファイル名(fileMatch
  • 書き換えるバージョン文字列のパターン(matchStrings
  • アップデート情報の元となるデータベース(Datasource

この3つの設定をセットにしているのがManagerです。Renovateはリポジトリに含まれるファイル名からどのManagerが利用できるかを自動で判断してくれるため、通常は全く意識する必要がありません。

Renovateにとって未知のフォーマットを新たに対応させたい場合、新たなDatasourceに対応させる必要がある場合はおそらくRenovate本体に実装を追加してもらう必要があると思われます。一方で、Datasourceとして実装済みの既存のいずれかが使い回せる場合では書き換えるべきバージョン文字列を定義するだけでRenovateとしては未知のフォーマットでも対応可能になります。これがRegex Managerです。

ではEarthfileの場合はどうなるかというと、元となるデータベースと書き換えたいバージョン文字列は通常のDockerfileと同一で問題なさそうなのでカスタムが必要なのはファイル名だけとなります。

このようなパターンの先例としてCircleCI、GitHub Actions、CloudBuildといったYAML内にイメージタグを記述するタイプのフォーマットが既に存在していることを思い出したので、その実装がどうなっているのかを見てみます。

https://github.com/renovatebot/renovate/tree/main/lib/modules/manager/cloudbuild

3つのうちどれでもいいのですが、CloudBuildが一番シンプルだったのでこれを見ていきます。どうやらindex.tsとextract.tsという2つのファイルだけで構成されているようです。extract.tsにはYAMLの中身をどのようにパースするかという処理が書かれており、index.tsにはこのように対象とするファイル名を定義している fileMatch が書かれています。

export const defaultConfig = {
  fileMatch: ['(^|/)cloudbuild\\.ya?ml'],
};

ということはDockerfile用のmanagerの設定の fileMatch だけを自分のrenovate.jsonによって上書きすることでEarthfileもDockerfileとみなしてもらえるのでは?と思いつきました。

Dockerfile用mangerのfileMatchを上書きする

ここまで理解してから改めてRenovateのドキュメントを見直したところ、実はそのものズバリの例が記載されていました。

{
  "dockerfile": {
    "fileMatch": ["does-not-look-like-a-docker-file"]
  }
}

https://docs.renovatebot.com/modules/manager/#extending-a-managers-default-filematch

あとは fileMatch に設定するファイル名の正規表現を決めるだけですが、最初に単に ^Earthfile$ としたところルートに置かれたEarthfile以外のディレクトリにネストして置かれたEarthfileを対象としてくれませんでした。

元々のDockerfileのアップデートではネストされていたものも対象としてくれていたはずなのでDockerfile managerのindex.tsを見てみたところ、以下のような正規表現でネストされた場合にも対応されていました。

export const defaultConfig = {
  fileMatch: ['(^|/|\\.)Dockerfile$', '(^|/)Dockerfile[^/]*$'],
};

あとはこの正規表現を拝借して fileMatch にコピペしまして、DockerfileEarthfileと書き換えることで無事にRenovateがアップデート対象としてみなしてくれるようになりました。

fileMatch を上書きしたら元々のファイル名パターンは対象外になるのか?

という疑問も浮かんだのですが、これも先ほどのドキュメントに記載されていました。

Renovate will extend the existing fileMatch, meaning you don't need to include the default regular expressions like Dockerfile in your own array. In other words, the regular expression are "additive".

自分でカスタムした fileMatch はデフォルトのものを上書きするのではなく、追加として扱われるようです。つまりEarthfileとDockerfileが同居するようなリポジトリであったとしてもRenovateは両方ともアップデート対象として見てくれるということですね。

まとめ

Renovateが未対応のEarthfileであっても、renovate.jsonにちょっと手を加えるだけでDockerfileとみなしてアップデート対象にする方法を紹介しました。

自分は今のところEarthfile以外に応用は思いついていないですが、もし同じようなケースに遭遇したらこういう方法もあるということを思い出してもらえればと思います。

脚注
  1. Earthly独自の拡張としてEarthfile内の別のターゲットを参照したり、オプションの指定なども可能です https://docs.earthly.dev/docs/earthfile#from ↩︎

Discussion