Golang中如何让`go mod tidy`从同一域名但不同访问令牌下载依赖包

Golang中如何让go mod tidy从同一域名但不同访问令牌下载依赖包 你好,我们使用自己的仓库时遇到了一个关于 go get 的问题。

背景

我们使用了两个托管在我们 GitLab 上的包。这两个包位于不同的仓库中,尽管它们共享同一个域名。

  • 模块 1 位于 gitlab.mycompany.com/groupA/module1
  • 模块 2 位于 gitlab.mycompany.com/groupB/module2

然后,我们有一个 go.mod 文件需要这两个模块,如下所示。

module gitlab.mycompany.com/mymodule

go 1.20

require (
	gitlab.mycompany.com/groupA/module1 v0.0.0
	gitlab.mycompany.com/groupB/module2 v0.0.0
)

每个仓库都有一个 GitLab 部署令牌,用于授予代码的读取权限(以便可以克隆)。为了让 go get 使用它们,我们按照这里的说明使用了 .netrc 文件。 这对于单个仓库/包来说工作正常。在 .netrc 中,你为域名 gitlab.mycompany.com 添加用户和令牌,go get 就可以下载该包。

问题

这对于单个包来说工作正常。然而,当执行 go mod tidy 时,你需要下载 go.mod 中指定的两个包(当它们未被缓存时)。问题是,对于私有仓库,go get 会在 .netrc 中查找域名,但是,我们有两个具有相同域名不同用户和令牌的模块。因此,go mod tidy 会失败,因为它不知道为每个包使用哪个用户/令牌,因为它只考虑域名。

.netrc:

machine gitlab.mycompany.com login module1_user password module1_token
machine gitlab.mycompany.com login module2_user password module2_token

module1module2 都位于 gitlab.mycompany.com,但在该域名下的不同仓库中。

目前,我们能够解决这个问题的唯一方法是:先在 .netrc 中设置 user1/token1,然后为 module1 执行 go get。接着,覆盖为 user2/token2 并为 module2 执行 go get。这会将包保存在缓存中,go mod tidy 就不需要再次下载它们。

这种方法并不理想,因为无法直接执行 go mod tidy,你需要先执行其他步骤。这不仅增加了复杂性,而且安全性也较低,因为用户/令牌必须放在 .netrc 文件之外。

问题:是否有任何方法可以避免这种行为,并告诉 go mod tidy/go get 每个包使用哪个用户/令牌,而不是基于域名?


更多关于Golang中如何让`go mod tidy`从同一域名但不同访问令牌下载依赖包的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中如何让`go mod tidy`从同一域名但不同访问令牌下载依赖包的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go模块系统中,可以通过配置.gitconfig或使用环境变量来为同一域名的不同路径指定不同的认证凭据。以下是几种解决方案:

方案1:使用.gitconfig配置替代凭据(推荐)

~/.gitconfig中添加以下配置:

[url "https://module1_user:module1_token@gitlab.mycompany.com/groupA"]
    insteadOf = https://gitlab.mycompany.com/groupA

[url "https://module2_user:module2_token@gitlab.mycompany.com/groupB"]
    insteadOf = https://gitlab.mycompany.com/groupB

这样配置后,当Go工具访问gitlab.mycompany.com/groupA时,会自动使用module1_user:module1_token,访问gitlab.mycompany.com/groupB时使用module2_user:module2_token

方案2:使用环境变量配置

在shell配置文件(如.bashrc.zshrc)中添加:

export GOPRIVATE="gitlab.mycompany.com/*"
export GIT_TERMINAL_PROMPT=0

然后通过环境变量设置凭据:

# 为不同路径设置不同的环境变量
export GITLAB_GROUP_A_TOKEN="module1_token"
export GITLAB_GROUP_B_TOKEN="module2_token"

方案3:使用.netrc配合路径前缀

虽然标准的.netrc不支持路径前缀,但可以通过脚本动态生成:

// generate_netrc.go
package main

import (
    "fmt"
    "os"
)

func main() {
    netrcContent := `machine gitlab.mycompany.com/groupA login module1_user password module1_token
machine gitlab.mycompany.com/groupB login module2_user password module2_token`

    home, _ := os.UserHomeDir()
    netrcPath := home + "/.netrc"
    
    if err := os.WriteFile(netrcPath, []byte(netrcContent), 0600); err != nil {
        panic(err)
    }
    
    fmt.Println("Generated .netrc with path-specific credentials")
}

方案4:使用Git凭证助手

创建自定义的Git凭证助手脚本:

#!/bin/bash
# ~/.git-credential-helper.sh

case "$1" in
    get)
        if [[ "$2" == *"groupA"* ]]; then
            echo "username=module1_user"
            echo "password=module1_token"
        elif [[ "$2" == *"groupB"* ]]; then
            echo "username=module2_user"
            echo "password=module2_token"
        fi
        ;;
    *)
        ;;
esac

配置Git使用此助手:

chmod +x ~/.git-credential-helper.sh
git config --global credential.helper "/bin/bash ~/.git-credential-helper.sh"

方案5:使用Go 1.19+的GOPROXY配置

创建私有代理配置:

# 设置私有模块使用direct模式
export GOPROXY="https://proxy.golang.org,direct"
export GOPRIVATE="gitlab.mycompany.com/*"

# 使用多个replace指令(在go.mod中)
replace gitlab.mycompany.com/groupA => gitlab.mycompany.com/groupA v0.0.0

replace gitlab.mycompany.com/groupB => gitlab.mycompany.com/groupB v0.0.0

完整示例:结合使用方案1

这是最简洁的解决方案。配置完成后,直接运行:

go mod tidy

Go工具会自动使用正确的凭据下载两个模块。示例输出:

go: downloading gitlab.mycompany.com/groupA/module1 v0.0.0
go: downloading gitlab.mycompany.com/groupB/module2 v0.0.0
go: added gitlab.mycompany.com/groupA/module1 v0.0.0
go: added gitlab.mycompany.com/groupB/module2 v0.0.0

这些方案都能解决同一域名下不同仓库需要不同认证凭据的问题,其中方案1(.gitconfig配置)是最直接且维护性最好的方法。

回到顶部