プライベートリポジトリをgo getして「terminal prompts disabled」とか「Confirm the import path was entered correctly.」とか言われたときのメモ

プライベートリポジトリのモジュールをgo getするための設定(https

社内のプライベートリポジトリをgo getする際にしばしば混乱するのでメモ。httpsでのアクセスが必要な環境なので、https前提の話となっている。

何も設定していない場合に発生するエラー

前提:

  • go version go1.15.6 linux/amd64 (ちょっと古い…)
  • GOPRIVATEを設定していない
  • httpsの認証情報を設定してない
  • キャッシュクリア
  • go.modがあるディレクトリで実行

go get, go get ${モジュール名}

  • go.modに記載のモジュールをインストールする。
  • ①プライベートリポジトリの認証を突破できない
❯ go get
①go: github.com/Sho372/mysecret@v0.0.0-20221015173609-50bc2589408e: invalid version: git fetch -f origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/sho/goworkspace/pkg/mod/cache/vcs/f7c95e78ccfc05412466703c9dfe4d96cfb78fa98dc272d0d7347bff3f468e2d: exit status 128:
        fatal: could not read Username for 'https://github.com': terminal prompts disabled

ちなみに、go.modがない環境で実行すると…

  • ①に加えて②も起きる
❯ go get github.com/Sho372/go-const
①go get github.com/Sho372/go-const: module github.com/Sho372/go-const: git ls-remote -q origin in /home/sho/goworkspace/pkg/mod/cache/vcs/1213af4aff3f33e0fc4e0690d9630417ffc2fcdd363e78fe9cf3cf41f1e5a64c: exit status 128:
        fatal: could not read Username for 'https://github.com': terminal prompts disabled
②Confirm the import path was entered correctly.
If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.

1. GOPRIVAETを設定

今回はモジュール名を直接指定する。モジュール名はモジュール側のgo.modに書いてある。

❯ export GOPRIVATE=github.com/Sho372/mysecret
❯ env | grep GOPRIVATE
GOPRIVATE=github.com/Sho372/mysecret

指定するもジュルー名がわからない時はモジュール側のgo.modを確認する

❯ cat go.mod
module github.com/Sho372/mysecret

go 1.15

上記のexportで設定してもいいが、goの設定なので、go env -wで設定するようにしている。

go env -w GOPRIVATE=github.com/Sho372/mysecret

2. httpsの認証情報を設定に追加して、認証情報入力をスキップする

.netrc

Frequently Asked Questions (FAQ) - The Go Programming Language

git confg

プライベートリポジトリをgo getする方法 - 尋常でないもふもふ

bitbucket, gitlab

Today I Learned - Fix: go get private repository return error terminal prompts disabled

こちらも.netrcで設定してもいいが、.gitconfigで設定がまとまっている方がいいので、gitの設定で解決するようにしている。

git config --global url."https://${githubのaccess token}:x-oauth-basic@github.com/".insteadOf "https://github.com/"
❯ cat ~/.gitconfig
[user]
        email = 32non23ca@gmail.com
        name = Sho372
[url "https://${githubのaccess token}:x-oauth-basic@github.com/"]
        insteadOf = https://github.com/

3. go get

設定が完了したら、欲しいプライベートモジュールをgo getする

❯ go get [github.com/Sho372/mysecret](http://github.com/Sho372/mysecret)
go: downloading [github.com/Sho372/mysecret](http://github.com/Sho372/mysecret) v0.0.0-20221015173609-50bc2589408e
go: [github.com/Sho372/mysecret](http://github.com/Sho372/mysecret) upgrade => v0.0.0-20221015173609-50bc2589408e
❯ cat go.mod
module go-import-package
go 1.15

require github.com/Sho372/mysecret v0.0.0-20221015173609-50bc2589408e // indirect

go getが成功すると、GOMODCACHE配下にread onlyで格納される

❯ go env | grep GOMODCACHE
GOMODCACHE="/home/sho/goworkspace/pkg/mod"
❯ pwd
/home/sho/goworkspace/pkg/mod/github.com/!sho372
❯ ll
total 16
drwxr-xr-x  4 sho sho 4096 Oct 16 02:41 .
drwxr-xr-x 40 sho sho 4096 Oct 16 04:43 ..
dr-x------  2 sho sho 4096 Oct 16 02:41 mysecret@v0.0.0-20221015173609-50bc2589408e
❯ go env | grep GOCACHE
GOCACHE="/home/sho/.cache/go-build"

4. ソース上で取得したモジュールをimportして使う

最後にソース上でimportする

import (
        "fmt"
        "log"

        "github.com/Sho372/mysecret" ★
        "github.com/shopspring/decimal"
)

go mod vendor (vendoring)

go mod vendorを実行すると、vendorディレクトリが生成され、ソースコードが格納される。

  • vendorディレクトリが生成され、この配下に依存モジュールのソースがダウンロードされる
  • vendorがある場合は、そこにあるモジュールで依存が解決されるらしい
  • GOMODCACHE配下とは異なり、修正可能なのでデバッグコードを差し込むことができる
❯ ll
total 2368
drwxrwxrwx 1 sho sho     512 Oct 17 04:49 .
drwxrwxrwx 1 sho sho     512 Oct 16 03:31 ..
-rwxrwxrwx 1 sho sho     148 Oct 16 05:41 go.mod
-rwxrwxrwx 1 sho sho     404 Oct 16 04:54 go.sum
-rwxrwxrwx 1 sho sho 2421984 Oct 16 05:33 main
-rwxrwxrwx 1 sho sho     261 Oct 16 04:57 main.go

❯ go mod vendor

❯ ll
total 2368
drwxrwxrwx 1 sho sho     512 Oct 17 04:49 .
drwxrwxrwx 1 sho sho     512 Oct 16 03:31 ..
-rwxrwxrwx 1 sho sho     148 Oct 16 05:41 go.mod
-rwxrwxrwx 1 sho sho     404 Oct 16 04:54 go.sum
-rwxrwxrwx 1 sho sho 2421984 Oct 16 05:33 main
-rwxrwxrwx 1 sho sho     261 Oct 16 04:57 main.go
drwxrwxrwx 1 sho sho     512 Oct 17 04:49 vendor ★

❯ ll vendor/github.com/Sho372
total 0
drwxrwxrwx 1 sho sho 512 Oct 17 04:49 .
drwxrwxrwx 1 sho sho 512 Oct 17 04:49 ..
drwxrwxrwx 1 sho sho 512 Oct 17 04:49 mysecret ★

キャッシュクリア実験

上記の手順でプライベートパッケージからパッケージを取得したあとに、以下を実施してキャッシュクリアの挙動を確かめた

1 go clean -modcache

  • GOMODCACHE="/home/sho/goworkspace/pkg/mod" ディレクトリが削除される
  • このあとにgo buildを実行してもまだ通る

2 go clean --cache

  • GOCACHE="/home/sho/.cache/go-build"配下のキャッシュが削除される
  • このあとにgo buildを実行してもまだ通る

3 rm -rf vendor,go clean -modcache,go clean --cache

  • vendorディレクトリを削除
  • go buildするとGOCACHEにキャッシュが残るので再度これもクリア
  • 念のためGOMODCACHEもクリア
  • これで完全にローカルからパッケージが消え去ったはず

4 go build

  • パッケージのダウンロードが開始した。(ただし、Go 16ではgo build時の自動ダウンロードはなくなったらしいので、go get or go mod tidyを実行)
❯ go build
go: downloading github.com/shopspring/decimal v1.3.1
go: downloading github.com/Sho372/mysecret v0.0.0-20221015173609-50bc2589408e

キャッシュクリアまとめ

つまり、ローカルのパッケージを完全に削除して、再ダウンロードしたい場合は以下ぽい

  1. もしvendorディレクトリがあるなら、rm -rf vendor
  2. go clean --cache
  3. go clean -modcache
  4. go get or go mod tidy
  5. もしvendorディレクトリが必要なら、go mod vendor

プライベートモジュールの改修

  • プライベートパッケージ側でブランチを切って改修
  • そのブランチ版をインポートして使ってみる

1. プライベートモジュールで改修

  • feature ブランチを作成して改修し、push
  • 新たに pokemons パッケージを作成

2. featureブランチ版をgo get

  • @${ブランチ名}で指定できる
  • go get -uだとさらにモジュールが依存するモジュールの最新も取得してくれるらしい。こっちが適切?
❯ go get github.com/Sho372/mysecret@feature
go: github.com/Sho372/mysecret feature => v0.0.0-20221016202503-eb4c4bc6b253
go: downloading github.com/Sho372/mysecret v0.0.0-20221016202503-eb4c4bc6b253
❯ cat go.mod
module go-import-package

go 1.15

require (
        github.com/Sho372/mysecret v0.0.0-20221016202503-eb4c4bc6b253
        github.com/shopspring/decimal v1.3.1
)

3. 使ってみる

  • 今回は、「モジュール名」と「パッケージ名」が異なるから?、${モジュール名}/${パッケージ名}で指定するとimportできた
import (
    "fmt"
    "log"

    "github.com/Sho372/mysecret"
    "github.com/Sho372/mysecret/pokemons""github.com/shopspring/decimal"
)

func main() {

    mysecret.SecretProcess()
    fmt.Println(pokemons.PIKACHU) ★

    amount, err := decimal.NewFromString("1.23")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(amount.String())
}

4. 元のmainブランチ版に戻す

  • go get ${モジュール名}@latestでも、元のmasterブランチの最新に戻った
  • go get ${モジュール名}@latestはgo get ${モジュール名}と同じ意味らしい
go get github.com/Sho372/mysecret@latest
go: github.com/Sho372/mysecret latest => v0.0.0-20221015173609-50bc2589408e
❯ cat go.mod
module go-import-package

go 1.15

require (
        github.com/Sho372/mysecret v0.0.0-20221015173609-50bc2589408e
        github.com/shopspring/decimal v1.3.1
)
❯ go build
go: finding module for package github.com/Sho372/mysecret/pokemons
main.go:8:2: module github.com/Sho372/mysecret@latest found (v0.0.0-20221015173609-50bc2589408e), but does not contain package github.com/Sho372/mysecret/pokemons

masterブランチ指定でもいける

go get github.com/Sho372/mysecret@master
go: github.com/Sho372/mysecret master => v0.0.0-20221015173609-50bc2589408e

Modules · golang/go Wiki

goコマンド

公式ドキュメント

Go Modules Reference - The Go Programming Language

go.modで定義された、プロジェクトの依存モジュールを取得したい時

  • go get or go mod tidy
    • 格納先:GOMODCACHE="/home/sho/goworkspace/pkg/mod"
cd ${go.modがあるディレクトリ}
go get or go mod tidy

プロジェクトに新しいモジュールを追加したい時(go.modへの追記)

  • go get ${モジュール名}
    • 格納先:GOMODCACHE="/home/sho/goworkspace/pkg/mod"
cd ${go.modがあるディレクトリ}
go get ${モジュール名}
cat go.mod  //取得したモジュール名が追記されている