古い依存関係をチェックするツールを作った話

6 min読了の目安(約5500字TECH技術記事

この記事は Clojure Advent Calendar 2020 の8日目の穴埋めに向けたものです。

TL;DR

  • Clojure 向けに antq という古い依存ライブラリなどを検知するツールを作ったよ
  • ライブラリに限らず GitHub Actions の YAML もチェックするよ

これまでの古い依存ライブラリ検知ツール

Clojure にはプロジェクトが依存しているライブラリで古いものがあれば教えてくれるツール類が昔からあります。

おそらく一番有名なものでは Leiningen 向けのプラグインとして xsc/lein-ancient があり、
Boot 向けの martinklepsch/boot-depsClojure CLI 向けの Olical/depot というように基本的に検知用のツールは出揃っている状況です。

なのでこれらのツールを使えば現時点でも基本的には困らないというのが正直なところです。

antq

そんな中、新たに古い依存ライブラリを検知するためのツールを作りました。

https://github.com/liquidz/antq

なぜツール類が出揃っているこの状況で新しいツールを作ったのかというと、以下の理由が大きなところです。

  • shadow-cljs.edn 向けのツールが無さそうだった
  • 1つのプロジェクト内で Leiningen / shadow-cljs など複数のツールをターゲットとしたファイルが共存している場合でも一括でチェックしたかった
  • GitHub Actions でスムーズに使いたかった

そんな理由から現状 antq は以下のファイルに対応しています。

Clojure 関連のプロジェクトファイルはおそらく網羅できていると思います。
唯一異端に見える GitHub Actions の YAML については、Clojure プロジェクトの CI を GitHub Actions でやっていく中で、使っている Action のバージョンアップも検知したいという個人的要望から対応されています。

使い方

簡単なのは Docker、もしくは Clojure CLI を使う方法です。
以下のコマンドを任意のプロジェクトのルートディレクトリで実行すれば、直下にある各種ファイルを読み込んで古くなっている依存関係を洗い出してくれます。

## Docker を使う場合
$ docker run --rm -v $(pwd):/src -w /src uochan/antq:latest

## Clojure CLI を使う場合
$ clojure -Sdeps '{:deps {antq/antq {:mvn/version "RELEASE"}}}' -M -m antq.core

出力例は以下の通りです。

|    :file |         :name | :version | :latest-version |
|----------+---------------+----------+-----------------|
| deps.edn |     merr/merr |    0.3.0 |           0.3.1 |
|          | metosin/malli |  a7f5664 |         4c854a2 |

もし lein-modules のようなプラグインを使ったマルチモジュールなプロジェクトの場合は --directory オプションを使うことで、カレントディレクトリ直下以外のディレクトリも対象とできます。

$ clojure -Sdeps '{:deps {antq/antq {:mvn/version "RELEASE"}}}' -M -m antq.core \
    --directory path1 --directory path2

なお project.clj や deps.edn 内に antq への依存関係を記載して、プロジェクトの一部として antq を実行する方法も勿論あり、それらは README の Usage にまとめてあるので必要に応じて参照していただければと思います。

ちなみに作者としては uberjar したものに java -jar /path/to/antq-standalone.jar のようなエイリアスを貼って antq コマンドで実行できるようにしています。
これだとカレントディレクトリ直下にあるプロジェクトファイルの影響を受けずにチェックできる(例えば存在しないバージョン番号を適当に入力して最新バージョンを知りたい場合など)ので何かと便利です。

依存ライブラリの更新

既存のツール類でも対応しているものは多いので目新しさはないですが、antq は古い依存ライブラリのチェックに限らず 更新 にも対応しています。

実行時に --upgrade オプションをつけることで、古い依存ライブラリがあった場合にプロジェクトファイル内のバージョン番号の記載を自動的に最新のバージョン番号に更新できます。

デフォルトでは以下のように古い依存関係毎に更新して良いかの確認が入ります。
なお全部を無条件で更新することはまず無いとは思いますが、 --force オプションで確認は省略できます。
--focus オプションを使うとチェックするライブラリを限定できるので、 --focus--force を併用することで特定ライブラリのバージョン更新は楽かもしれません。

$ cat deps.edn
{:paths ["src"]
 :deps {org.clojure/clojure {:mvn/version "1.10.1"}
        merr/merr {:mvn/version "0.3.0"}
        metosin/malli {:git/url "https://github.com/metosin/malli"
                       :sha "a7f5664"}}}

$ antq --upgrade

|    :file |         :name | :version | :latest-version |
|----------+---------------+----------+-----------------|
| deps.edn |     merr/merr |    0.3.0 |           0.3.1 |
|          | metosin/malli |  a7f5664 |         4c854a2 |
Do you upgrade merr/merr '0.3.0' to '0.3.1' in deps.edn (y/n): y
Upgraded merr/merr '0.3.0' to '0.3.1' in deps.edn.
Do you upgrade metosin/malli 'a7f5664' to '4c854a283697fbc22856145e514be7c2b1853edf' in deps.edn (y/n): y
Upgraded metosin/malli 'a7f5664' to '4c854a283697fbc22856145e514be7c2b1853edf' in deps.edn.

$ cat deps.edn
{:paths ["src"]
 :deps {org.clojure/clojure {:mvn/version "1.10.1"}
        merr/merr {:mvn/version "0.3.1"}
        metosin/malli {:git/url "https://github.com/metosin/malli"
                       :sha "4c854a283697fbc22856145e514be7c2b1853edf"}}}

なお README にも注意書きしてありますが、現状 --upgrade option は GitHub Actions の YAML には対応していません。
これは Clojure で利用できる YAML パーサーが元々の構成(例えばコメントを残しつつとか)を保持したままの値の変更に対応していないのが主な原因です。
このあたりは何か解決策を探して対処したいなとは思っています。

GitHub Actions

antq を作った目的の1つに GitHub Actions での利用がありました。
というのも今まで古い依存関係のチェックは Deps Versions を使っていたのですが、これは deps.edn の依存関係のチェックをしてくれないという問題があったので、これを antq + GitHub Actions(スケジュール) に置き換えたいという目論見が元になっています。

antq では簡単に使えるよう Marketplace に Action を公開しています。

https://github.com/marketplace/actions/antq-action

中身は単に uberjar したものを含む Docker イメージを使って antq を実行しているだけですが、出力フォーマットを GitHub Actions 向けに最適化しているため、以下のように Annotations に古い依存関係を表示できるようになっています。

具体的な workflow については以下を antq 自体の workflow を参照してください。(antq は antq で古い依存関係のチェックを行っています!)

https://github.com/liquidz/antq/blob/master/.github/workflows/dependencies.yml

最後に

後発のツールなので知名度はまだまだ低いですが、最近では Clojurists Together の支援を受けた Practicalli で提供されている deps.edn にも採用してもらえたりと少しずつ使われ始めている気配があります。

https://github.com/practicalli/clojure-deps-edn/

作者個人としても便利に使えているので、もっとたくさんの方に使っていただきたくさんのフィードバックがもらえると嬉しいなと思っています!