🧩

Goのサブモジュールをリリースするには

2023/09/29に公開

🎓 結論

Go のサブモジュールをリリースするには、GitHub で Release するときに submodule/v0.0.1 のようにタグにサブモジュール名を加える。


Releases - GitHub

💡 前提知識

📘 Go モジュールとは

Go 1.11 で Go モジュール (Go Modules) が導入され、公式に go.mod ファイルによってライブラリの依存関係を管理できるようになった。
当時は過渡期だったのでプロジェクトによっては GO111MODULE という環境変数で on / off してたが 2023 年現在、すべての Go のコードで Go モジュールが使われていると考えていい。

Go の慣習ではリポジトリルートに go.mod が置かれるのが好ましい。わかりやすいし、モジュール名とモジュールパスがシンプルになって import 文も簡潔になる。

/myproject
├── cmd
│   └── server
│       └── main.go
├── internal
│   └── myauth
│       └── auth.go
├── pkg
│   └── mymath
│       └── calc.go
├── go.mod
├── go.sum
└── main.go

たまに src ディレクトリを作ってその配下にコードを置いてるケースを見かけるが、それは Java の規約。Go ではメリットないので避けた方が良い。

🏗️ マルチモジュール構成

上に書いたのはのは一般的なシングルモジュール構成の話だが、1リポジトリ内で複数のモジュールを扱うマルチモジュール構成もできる。
特に Go 1.18 以降では Workspaces という機能(workspace mode とも呼ばれる)が追加され、go.work ファイルの登場によって管理しやすくなった。

📚 メインモジュールの下にサブモジュールを置くパターン

/myproject
├── cmd
├── internal
├── pkg
├── submodule
│   ├── mypackage
│   │   └── mypackage.go
│   ├── submodule.go
│   ├── go.mod (module github.com/user/myproject/submodule) 
│   └── go.sum
├── go.mod (module github.com/user/myproject)
├── go.sum
├── go.work
└── main.go

go.work

go 1.21.1

use (
	.
	./submodule
)

🧩 サブモジュールだけ複数あるパターン

/myproject
├── submodule1
│   ├── mypackage
│   │   └── mypackage.go
│   ├── submodule.go
│   ├── go.mod (module github.com/user/myproject/submodule1) 
│   └── go.sum
├── submodule2
│   ├── submodule.go
│   ├── go.mod (module github.com/user/myproject/submodule2) 
│   └── go.sum
└── go.work

go.work

go 1.21.1

use (
	./submodule1
	./submodule2
)

🚀 どうやってサブモジュールを公開すれば良いのか

Go 言語は他のどの言語よりもライブラリ公開が簡単。
GitHub に push した時点で公開が完了している。使う側は GitHub 目掛けて go get するだけでいい。

go get github.com/myorg/myproject

リリース済であればバージョン番号を指定できる。

go get github.com/myorg/myproject@1.0.2

コミットハッシュの指定もできる。

go get github.com/myorg/myproject@cc71dff

ただ、この方法はリポジトリルートにあるメインモジュールの go.mod を参照する場合の話。サブモジュールはどのように公開するかというと、サブモジュール名をタグに含めれば良い。

  • メインモジュールのタグ
    • v1.0.2
  • サブモジュールのタグ
    • submodule1/v0.1.1
    • submodule2/v0.3.0

同じリポジトリでも各モジュールのバージョンは個別に管理される。

⚠️ 勘違いしやすい初歩的なこと

  • マルチモジュール構成でモジュールとして扱うということは、モジュール用のディレクトリに必ず go.mod が存在する
    • go.mod がなければただのパッケージになる
  • go.modmodule ディレクティブに書く『モジュール名』を間違えないように
    • インターネット上で一意となる github.com/org-name/repo-name がモジュール名の基本
    • サブモジュールの場合は github.com/org-name/repo-name/submodule がモジュール名

📚 参考

Discussion