昔作った notify-issues-to-slackの依存モジュールはdepのままで管理していたが、勉強がてらGo Modulesに移行することにした。
参考にした資料
- Go 1.13 に向けて知っておきたい Go Modules とそれを取り巻くエコシステム - blog.syfm
- Go Modulesについてざっくり知ることができてよかった
- Modules · golang/go Wiki · GitHub
- ざっくり知った上でちゃんと理解するために公式ドキュメントを読む
- depからgo modulesへの移行と、移行時にTravis CI & GoReleaserでハマる(かもしれない)ポイント · horizoon
- 移行手順で参考にした
- Goモジュールでツールもバージョン管理する - Plan 9とGo言語のブログ
- ツールも含めてgo.modに入れていく手順で参考にした
やったこと
Pull Requestは https://github.com/shibayu36/notify-issues-to-slack/pull/10
- コード上で使っている依存モジュールをgo.modで管理するように
- ツール郡をgo.modで管理するように
- Makefileなどを修正する
の三段階で行った。
コード上で使っている依存モジュールをgo.modで管理するように
まずはコード上で使っている依存モジュールをgo.modで管理するように変更する。golintなどのツール群は後回し。
go mod initする。
$ go mod init github.com/shibayu36/notify-issues-to-slack go: creating new go.mod: module github.com/shibayu36/notify-issues-to-slack go: copying requirements from Gopkg.lock go: converting Gopkg.lock: stat github.com/karrick/tparse@v2.6.1: github.com/karrick/tparse@v2.6.1: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2 go: converting Gopkg.lock: stat github.com/google/go-github@v21.0.1: github.com/google/go-github@v21.0.1: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v21
するとtparseとgo-githubで invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v21
というエラーが出たので、次にこれを解決する。
Go Modulesの仕様として、v2以上のモジュールをimportする時はimport path自体を変えるという仕様があるようだ。Go ModulesドキュメントのSemantic Import Versioningという章が参考になる。
これに従いつつ、バージョンはGopkg.lockに載っていたものを使うようにimport pathを変えていく。変更はこちら。
ここまで出来たらdep用のファイルを全て削除し、go buildすることでgo.modとgo.sumが更新される。
$ rm Gopkg.toml Gopkg.lock $ rm -fr vendor/ $ go build
これでコード上で使っている依存モジュールをgo.modで管理できるようになった。
ツール郡をgo.modで管理する
さらにgolintなどのツール郡もgo.modに載せていく。Goモジュールでツールもバージョン管理する - Plan 9とGo言語のブログを参考にする。変更点はこのcommit
まずツール郡はtools.goにimportだけするというのがベストプラクティスのようだ。これをしておかないと、go getでツールをインストールしてgo.modに載せても、go mod tidyなどを実行した時に消されてしまう。
tools.go
// +build tools package main import ( _ "github.com/Songmu/ghch/cmd/ghch" _ "github.com/Songmu/goxz/cmd/goxz" _ "github.com/mattn/goveralls" _ "github.com/tcnksm/ghr" _ "github.com/x-motemen/gobump/cmd/gobump" _ "golang.org/x/lint/golint" )
この状態でまたgo buildすると最新版がインストールされ、ツール郡もgo.modで管理できるようになった。
Makefileを修正する
最後にMakefileでdepを使っていたところを修正する。変更点は https://github.com/shibayu36/notify-issues-to-slack/pull/10/files#diff-b67911656ef5d18c4ae36cb6741b7965
- GO111MODULE=onにしておく
- go testやgo buildで勝手に依存モジュールを取得してくれるようになったので、depsのようなタスクは必要なくなった
- ツール郡はgo installで入れることで、go.modで指定されたバージョンをインストールする
これでdepからgo.modへの移行が完了した。
学んだこと
- ツール郡の管理はtools.goにimport & go installで行う
- Go ModulesではMinimal version selection algorithmという考え方を取っている
- https://github.com/golang/go/wiki/Modules#version-selection
- ロックファイルが要らなくなる、というのは面白い
- 一方で他の依存モジュール管理ツールと考え方が違うので、少しハマりそうではある
- v2以上の場合import pathを変える
- go.modのindirectというのは直接依存でない、依存モジュールの依存という意味
- go.modのincompatibleというのはSemantic Import Versioningに従ってない場合についている
- go get (module名)@(バージョン名) みたいなのでうまく取れなかった時は、go proxyに登録されているモジュールのバージョンを確認してみると良い
go proxyに登録されているモジュールのバージョンを確認する方法はこんな感じ。
$ curl 'https://proxy.golang.org/github.com/google/go-github/v21/@v/list' v21.0.1 v21.0.0 $ curl 'https://proxy.golang.org/github.com/karrick/tparse/v2/@v/list' v2.3.0 v2.2.0 v2.6.0 v2.1.2 v2.3.4 v2.1.3 v2.4.0 v2.7.1 v2.8.0 v2.3.2 v2.4.1 v2.7.0 v2.8.1 v2.1.0 v2.3.3 v2.1.4 v2.3.1 v2.4.2 v2.6.1 v2.1.1 v2.1.5 v2.5.0
まとめ
depからGo Modulesへの移行を試したので、やったことを記録に残しておいた。Go Modulesについて知見が多少深まった気はする。