blog.syfm

徒然なるままに考えていることなどを書いていくブログ

モノレポで Go Modules を使う

Multi-Module Repository

Go Modules では Git で管理されているリポジトリ内に複数のモジュールを定義することが可能です。*1
これを利用すると、たとえばプロジェクト内で使う Go ツールの依存管理をプロジェクトのコードとは異なる go.mod で行うことができます。

$ go mod init # create project go.mod
$ mkdir tools && cd tools
$ go mod init # create tools go.mod
$ cat <<EOF
// +build tools

package tools

import (
        _ "github.com/rakyll/statik"
)
EOF
$ go get -tags tools ./... # add tool dependencies to go.mod

このとき、ディレクトリはこのような構造になっています。

.
├── go.mod
├── go.sum
└── tools
    ├── go.mod
    ├── go.sum
    └── tools.go

モジュール単位のバージョニング

Go modules はモジュール単位でバージョニングを行うため、モジュールを分ければ当然バージョニングも別々にできるようになります。
Go modules では VCS のタグから prefix を解釈することができ、マルチモジュール構成の場合は prefix を付けることでモジュール単位でバージョニングできます。
prefix はリポジトリ内のパスに対応し、ルートモジュールの prefix は空文字列であるため、単純に v0.1.0 といった見慣れたタグ名になります。 上記のマルチモジュール構成の場合、 tools のバージョニングには tools を prefix としてつけ、 tools/v0.1.0 といったタグ名になります。

モノレポと Go Modules

既存のベンダリングツールではリポジトリ単位でしかバージョニングができませんでしたが、Go modules を使うと上記のようにモノレポでも異なるリリースサイクルを持つことができるようになります。

また、Go プロジェクトのモノレポにおいて Renovate *2 のような依存パッケージ・モジュールの更新を行ってくれる bot との相性が悪くなっていました。
たとえば google-cloud-go は、GCP のサービス群のライブラリがすべて置かれているリポジトリですが、従来ではリポジトリ単位でしかバージョニングできなかったため、プロジェクトで使っていないパッケージの更新によりバージョンが上がった場合でも Renovate が動作してしまうといった問題がありました。
しかし、Go modules により必要なモジュールだけを依存対象に含められるようになっため、このような問題は解消することができるようになりました。

google-cloud-go はマルチモジュール構成のお手本としても参考になります。

Releases · googleapis/google-cloud-go · GitHub

今回紹介したことは Go Wiki にも記載されているため、詳しくはこちらを見てみてください。

Modules · golang/go Wiki · GitHub