おそらくはそれさえも平凡な日々

Dependabotを使ってGoプロジェクトの依存を更新するノウハウ

システムを運用していく以上、ライブラリは常に最新を使いたい。最近は依存ライブラリの更新を検知してくれる便利なサービスがいくつかあって、Nature社ではDependabotを使っている。

https://dependabot.com/

Renovateの方が便利そう、という話も聞くのだが、とりあえずDependabotはGitHubが買収して、privateリポジトリでも無料で使えるので利用している。

導入自体は簡単で、画面のガイドどおりに進んでいけば、良い感じに言語や依存管理ツールも自動検出してくれる。設定ファイルは特に置いていない。慣れてきたり、設定を横展開したくなった場合に置くと便利そう。

参考: Dependabotの設定ファイルを置くようにした

動作の様子

前提としてGo Modulesで依存管理をしているが、依存ライブラリの更新があると以下のようにpull requestを上げてくれる。

差分等も見やすく出してくれるし、まあまあ便利。pull request上にコメントしてbotを操作するのも面白いが、その手引も丁寧に書いてある。

しかし、いくつか使いづらい点があるので自前でハックしてなんとかしている。この辺りは諸々公式対応を望む部分。

go mod tidyして欲しい

これが一番大きな問題。以下のissueでやり取りされている。

https://github.com/dependabot/feedback/issues/215

dependabotのpull requestは、go get <module>@<new-version> しかしていない状態で上がってくる。つまり推移依存の解決は全くやってくれない。本来であれば、go mod tidyを実行して依存ツリーの構築をし直して欲しいところなのだがそれをやってくれない。

とは言え、実はgo mod tidyを実行するのはそう簡単ではない。公開ライブラリだけ使っていれば話は簡単だが、プライベートモジュールがある場合それらへのアクセス権がないとgo mod tidyが失敗してしまうからだ。

上のissueもだいぶロングランで苦戦している。去年の5月の以下のコメントがちょっと愉快。

We've been busy with the acquisition recently so haven't made progress on this yet. I'm hoping we'll be able to build out better Go support over the next few months though. -- https://github.com/dependabot/feedback/issues/215#issuecomment-496516828

自前でgo mod tidyして更新をpushする

どう対処しているかというと、dependabotのpull requestの更新をフックして、CircleCI上でpull requestの上書き更新をしている。具体的には、以下のようなシェル芸を.circleci/config.ymlに仕込んでいる。

command: |
  if $(echo {{CI{RCLE_BRANCH}" | grep '^dependabot/' >/dev/null) && [ "${CIRCLE_USERNAME}" = "" ]; then
    go mod tidy
    go mod vendor
    git add vendor go.sum go.mod
    export GIT_COMMITTER_NAME=nature-bot
    export GIT_AUTHOR_NAME=nature-bot
    export EMAIL='nature-bot@example.com'
    git commit -m "make vendor"
    git push origin "${CIRCLE_BRANCH}"
  fi

以前のエントリで説明したとおり、CircleCI上ではMachine account(この場合nature-bot)に、privateリポジトリへのアクセス権限を与えているので、その権限を使って、go mod tidy および go mod vendor (vendoringしているので) を実行して、その更新差分のcommitとpushをおこなっているという具合。pushできる権限渡してしまうのは嫌な感じがするが致し方ない。

dependabotによる更新かどうかを状況証拠的に判別している。上のif条件がそれだが以下の通り。

  • $CIRCLE_BRANCH が "dependabot/" で始まる
  • $CIRCLE_USERNAME が空文字列

特殊なbotによる更新であるためか、$CIRCLE_USERNAMEが空文字列なのである。これはどこにもドキュメントはされていないので急に変わる可能性はある。

ちなみに、自前でpull requestブランチに更新をかけているので、Dependabotに対して一部追加の操作がさせられなくなる。例えば追加の依存が降ってきた場合にそれを更新させられないなど。その場合は @dependabot recreate とpull requestにコメントすることで、Dependabotにpull requestを作り直させている。

セマンティックバージョニングされていないライブラリは更新対象外となる

これも地味に困る点。タグが適宜打たれていないライブラリはDependabotは更新を抽出してくれない。また、ライブラリのセマンティックバージョン以外の地点(コミットハッシュ)に依存している場合も更新されない。

後者の場合は、単純にセマンティックバージョニングされた地点まで依存ライブラリを自力で更新すれば、以後はDependabotの更新対象となる。

問題は前者。基本的にはライブラリ作者に働きかけてバージョニングをしてもらうのが良いし、現在は多くが対応していますが、ポリシーとしてバージョニングをしていないライブラリ類が困りもの。

つまりはよく使う golang.org/x 系がバージョニングしないポリシーなので困るのです。

この辺りは推移依存で上がっていくのに任せるか、go get golang.org/x/net@latest みたいなコマンドを定期的に実行して手動で依存を更新する感じになります。ここもDependabotの公式対応が望まれます。

更新がうるさい場合

これは些末な問題だし、頑張って対応するのが本道。ただ、ライブラリによっては関係ない依存更新がバンバン飛んできてめんどくさいことがあります。まあ、aws-sdk-go のことなんですけど。

その場合の対処方法の一つとして、 @dependabot ignore this minor version というコメント操作があります。これは「このマイナーバージョンの間は更新を無視する」という意味で、次にマイナーバージョンが更新されるまではDependabotによる当該ライブラリに対するpull request起票がなくなります。

まあ、aws-sdk-goのパッチアープデートはほぼノールックマージでもいいとは思うし、実際場合によってはチラ見でマージしています。

まとめ

不便な点もあるが、なかった時代よりかは格段に便利なので助かってはいる。変なハック無しで公式で全部まかなえるようになって欲しい。

ただあまりアップデートが活発ではないような…?というところが気になっている。

created at
last modified at
comments powered by Disqus