如何使用 godotenv.Load() .env 文件的动态位置?

Eri*_*eer 9 environment-variables go go-testing

问题

我正在用 Go 构建 REST API。godotenv 包用于加载环境变量。运行go run main.go,项目按预期运行 API,环境变量已加载。

但是,当想要使用以下命令运行测试时:go test ./...- 其中运行config/config_test.go- 它会抛出以下错误:(Error loading .env file如函数中指定的)。

鉴于以下项目结构:

> app
> auth
> config
  - config.go
  - config_test.go
> migrations
> static
> vendor
- .env
- .gitignore
- docker-compose.yml
- go.mod
- go.sum
- main.go
- README.md
Run Code Online (Sandbox Code Playgroud)

config.go中,我使用以下函数来加载数据库配置。

func GetConfig() *Config {
    err := godotenv.Load(".env")

    if err != nil {
        log.Fatalf("Error loading .env file")
    }

    dbHost := os.Getenv("DB_HOST")
    dbPort := os.Getenv("DB_PORT")
    dbName := os.Getenv("DB_DATABASE")
    dbUsername := os.Getenv("DB_USERNAME")
    dbPassword := os.Getenv("DB_PASSWORD")

    return &Config{
        DB: &DBConfig{
            Connection: "mysql",
            Host:       dbHost,
            Port:       dbPort,
            Username:   dbUsername,
            Password:   dbPassword,
            Name:       dbName,
            Charset:    "utf8",
        },
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道它在从 root 运行时有效,因为它.env驻留在 root 中。运行时config/config_test.go,它会尝试.env/config/.env. 如果我将行:更改err := godotenv.Load(".env")err := godotenv.Load("../.env"), config_test.go 会成功运行,但go run main.gofrom root 不会成功运行。

问题

如何.envGetConfig()中的函数动态加载位置config.go,以便 和 都go test ./...可以go run main.go加载.env

编辑

我知道将path string参数传递给GetConfig()函数可以在我的应用程序中工作(我正在应用程序包中初始化此配置)。但是,我想在不同的目录中创建多个测试,并且不希望传递参数。还有其他方法可以实现此目的吗?

Eri*_*eer 16

Following the suggestion of @Inian, I implemented the following solution, also listed on the Issues tab of the godotenv package.

In config.go I added a constant for the directory name (which is rest-api in my case). I added a loadEnv function that tries to get the root path of the project dynamically, based on the project name and the current working directory.

const projectDirName = "rest-api" // change to relevant project name

func loadEnv() {
    projectName := regexp.MustCompile(`^(.*` + projectDirName + `)`)
    currentWorkDirectory, _ := os.Getwd()
    rootPath := projectName.Find([]byte(currentWorkDirectory))

    err := godotenv.Load(string(rootPath) + `/.env`)

    if err != nil {
        log.Fatalf("Error loading .env file")
    }
}

func GetConfig() *Config {
    loadEnv()

    dbHost := os.Getenv("DB_HOST")
    dbPort := os.Getenv("DB_PORT")
    dbName := os.Getenv("DB_DATABASE")
    dbUsername := os.Getenv("DB_USERNAME")
    dbPassword := os.Getenv("DB_PASSWORD")

    return &Config{
        DB: &DBConfig{
            Connection: "mysql",
            Host:       dbHost,
            Port:       dbPort,
            Username:   dbUsername,
            Password:   dbPassword,
            Name:       dbName,
            Charset:    "utf8",
        },
    }
}
Run Code Online (Sandbox Code Playgroud)