モジュールの公開(Go Modules)

Goではコードを配布する仕組みとしてモジュール(Go Modules)があります。

前ページの『モジュールの作成』で作成したモジュールを公開する方法を説明します。

このページはGo1.13以降の利用を前提とします。

はじめに

モジュールは徐々に成長します。 ここでは、モジュールにバージョンをつけていない状態から始め、 セマンティックバージョニングに従いバージョンアップを重ねていく過程を時系列に沿って説明します。

説明で利用するモジュールexample.com/calcは架空のモジュールです。 実際にモジュールを公開するには、モジュールパスを実在するリポジトリにしてください。 GitHubの場合はgithub.com/<user>/<repo>のようにします。

擬似バージョン

手始めにバージョンがついていない状態でモジュールを公開します。

新たにgitリポジトリを作成し、コミットします。 外部に公開する場合はLICENSEファイルを含めます。

# パスは自身の環境に読み替えてください
cd $HOME/calc
git init
git add LICENSE go.mod go.sum calc.go calc_test.go
git commit -m "Initial commit"
git remote add origin xxx
git push origin main

これでモジュールを公開できました。 他の言語では中央集権的なサーバ(たとえばnpm)にモジュールをアップロードすることがありますが、 Goのモジュールではその必要はありません。

続いて、公開したモジュールを利用してみましょう。

# パスは自身の環境に読み替えてください
cd $HOME/myapp
go mod init example.com/myapp

main.go

package main

import (
    "fmt"

    "example.com/calc"
)

func main() {
    fmt.Println(calc.Max(1, 2))
}

依存関係を追加します。 現在はバージョンがついていないため、自動的に擬似バージョンがつけられます。 擬似バージョンはタイムスタンプやコミットハッシュを組み合わせ、v0.0.0-20170915032832-14c0d48ead0cのように表現します。

go mod tidy
go: finding module for package example.com/calc
go: downloading example.com/calc v0.0.0-20170915032832-14c0d48ead0c
go: found example.com/calc in example.com/calc v0.0.0-20170915032832-14c0d48ead0c

go.modに依存関係が追加されたことを確認します。

cat go.mod
module example.com/myapp

go 1.15

require example.com/calc v0.0.0-20170915032832-14c0d48ead0c

calcパッケージを使ったプログラムを実行します。

go run .
2

これでバージョンのついていないモジュールの公開と利用ができました。

v0

続いて、モジュールが形になってきたら、バージョンをつけて公開します。 最初は不安定なメジャーバージョンを意味するv0で公開します。

gitのタグを用いて、バージョンをつけます。

# パスは自身の環境に読み替えてください
cd $HOME/calc
go mod tidy
go test ./...
git add go.mod go.sum *.go
git commit -m "Release v0.1.0"
git tag v0.1.0
git push origin v0.1.0

モジュールを利用するプロジェクトは依存関係をv0.1.0に更新します。

# パスは自身の環境に読み替えてください
cd $HOME/myapp
go get example.com/calc
go: example.com/calc upgrade => v0.1.0
go: downloading example.com/calc v0.1.0

これでv0.1.0の公開と利用ができました。

今後の公開も次の通りバージョンをつけます。

  • 不具合修正をする場合は、パッチバージョンを加算(v0.1.1)
  • 互換性のない更新・機能追加・依存関係の更新をする場合は、マイナーバージョンを加算(v0.2.0)

v1

続いて、モジュールが安定していることを確認したら、メジャーバージョンv1をリリースできます。 メジャーバージョンv1内では互換性のない更新はできません。

# パスは自身の環境に読み替えてください
cd $HOME/calc
go mod tidy
go test ./...
git add go.mod go.sum *.go
git commit -m "Release v1.0.0"
git tag v1.0.0
git push origin v1.0.0

モジュールを利用するプロジェクトは依存関係をv1に更新します。

# パスは自身の環境に読み替えてください
cd $HOME/myapp
go get example.com/calc
go: example.com/calc upgrade => v1.0.0
go: downloading example.com/calc v1.0.0

これでv1.0.0の公開と利用ができました。

今後の公開も次の通りバージョンをつけます。

  • 不具合修正をする場合は、パッチバージョンを加算(v1.0.1)
  • 機能追加・依存関係の更新をする場合は、マイナーバージョンを加算(v1.1.0)

v2以降

続いて、互換性のない更新が必要な場合、次のメジャーバージョンで公開します。

ここで重要となるのが、メジャーバージョンが変わったらモジュールパスも変わるということです。 v2にする場合は、モジュールパスの接尾辞としてv2をつけます。 今回のサンプルの場合はexample.com/calc/v2です。

さらに、リポジトリにはv2用のサブディレクトリを作成して開発します。 サブディレクトリの作成する以外の方法もありますが、 この方法はモジュールを認識しないツールと互換性があるため、 公式が推奨する方法となっています。

# パスは自身の環境に読み替えてください
cd $HOME/calc
# これまでのリソースをサブディレクトリv2にコピー
mkdir v2
cp go.mod go.sum *.go v2
# go.modのモジュールパスをv2用に変更
go mod edit -module example.com/calc/v2 v2/go.mod
# 今後はv2ディレクトリを更新
cd v2
go mod tidy
go test ./...
git add .

これでv2用のモジュールが用意できましたが、 正式リリースの前に実験的なバージョンによるリリースをして動作確認します。

git commit -m "Release v2.0.0-alpha.1"
git tag v2.0.0-alpha.1
git push origin v2.0.0-alpha.1

問題がなければv2をリリースします。

git commit -m "Release v2.0.0"
git tag v2.0.0
git push origin v2.0.0

モジュールを利用するプロジェクトはインポートパスと互換性のないAPI利用を修正します。

import (
    "example.com/calc/v2"
)

あわせて、依存関係を更新します。

# パスは自身の環境に読み替えてください
cd $HOME/myapp
go mod tidy
go: finding module for package example.com/calc/v2
go: downloading example.com/calc/v2 v2.0.0
go: found example.com/calc/v2 in example.com/calc/v2 v2.0.0

これでv2.0.0の公開と利用ができました。 v3以降も同様に対応してきます。

参考リンク