A .env file in the working directory is now optional
This commit is contained in:
1 parent
0b1952bd69
commit
1e3acaeff3
5 files changed
+30
-9
No files matched your search
@@ -46,8 +46,8 @@ Configuration is read from, in increasing priority:
|
|||||||
given with `--config`
|
given with `--config`
|
||||||
3. `JOBSEARCH_*` environment variables, e.g. `JOBSEARCH_LOGGING_LEVEL=debug`
|
3. `JOBSEARCH_*` environment variables, e.g. `JOBSEARCH_LOGGING_LEVEL=debug`
|
||||||
|
|
||||||
A `.env` file in the working directory is loaded into the environment first,
|
A `.env` file in the working directory, if there is one, is loaded into the
|
||||||
and must exist.
|
environment first.
|
||||||
|
|
||||||
Example `config.yaml`:
|
Example `config.yaml`:
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -73,11 +73,17 @@ func TestConfigFlag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMissingEnvFile(t *testing.T) {
|
// A .env file is optional, but one that can't be parsed is an error.
|
||||||
|
func TestEnvFile(t *testing.T) {
|
||||||
cmdtest.Setup(t, appConfig)
|
cmdtest.Setup(t, appConfig)
|
||||||
if err := os.Remove(".env"); err != nil {
|
if err := os.Remove(".env"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if _, err := cmdtest.Run(t, newRoot, "", "level"); err != nil {
|
||||||
|
t.Errorf("without a .env file: %v; want no error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdtest.WriteFile(t, ".env", "NOT VALID\n")
|
||||||
_, err := cmdtest.Run(t, newRoot, "", "level")
|
_, err := cmdtest.Run(t, newRoot, "", "level")
|
||||||
cmdtest.ErrContains(t, err, ".env")
|
cmdtest.ErrContains(t, err, ".env")
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,8 @@ environment variables, merged through [Viper](https://github.com/spf13/viper).
|
|||||||
## Loading order
|
## Loading order
|
||||||
`Init(cfgFile, &conf)` builds the configuration in this order:
|
`Init(cfgFile, &conf)` builds the configuration in this order:
|
||||||
|
|
||||||
1. Loads `.env` from the working directory into the environment. A missing
|
1. Loads `.env` from the working directory into the environment, if there
|
||||||
`.env` file is an error.
|
is one. A `.env` file that can't be read or parsed is an error.
|
||||||
2. Sets the defaults from the `default` struct tags as Viper defaults.
|
2. Sets the defaults from the `default` struct tags as Viper defaults.
|
||||||
3. Reads the config file: `cfgFile` if given, otherwise the first
|
3. Reads the config file: `cfgFile` if given, otherwise the first
|
||||||
`config.yaml` found in `/etc/job-search` then the working directory. If no
|
`config.yaml` found in `/etc/job-search` then the working directory. If no
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package config
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -34,9 +35,13 @@ func isExplicitlySet(key string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// loadEnv loads environment variables from a .env file in the working
|
// loadEnv loads environment variables from a .env file in the working
|
||||||
// directory.
|
// directory, if there is one. One that can't be read or parsed is an error.
|
||||||
func loadEnv() error {
|
func loadEnv() error {
|
||||||
if err := godotenv.Load(); err != nil {
|
err := godotenv.Load()
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
return fmt.Errorf("invalid .env file: %w", err)
|
return fmt.Errorf("invalid .env file: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -141,10 +141,20 @@ func TestInitKeepsCommandLineLevel(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInitErrors(t *testing.T) {
|
// A .env file is optional.
|
||||||
t.Run("no .env file", func(t *testing.T) {
|
func TestInitWithoutEnvFile(t *testing.T) {
|
||||||
initDir(t, nil, testConfigYAML)
|
initDir(t, nil, testConfigYAML)
|
||||||
var conf JobSearchConfig
|
var conf JobSearchConfig
|
||||||
|
if err := Init("", &conf); err != nil {
|
||||||
|
t.Fatalf("err = %v; want nil without a .env file", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInitErrors(t *testing.T) {
|
||||||
|
t.Run("invalid .env file", func(t *testing.T) {
|
||||||
|
dir := initDir(t, nil, testConfigYAML)
|
||||||
|
writeFile(t, filepath.Join(dir, ".env"), "NOT VALID\n")
|
||||||
|
var conf JobSearchConfig
|
||||||
if err := Init("", &conf); err == nil ||
|
if err := Init("", &conf); err == nil ||
|
||||||
!strings.Contains(err.Error(), ".env") {
|
!strings.Contains(err.Error(), ".env") {
|
||||||
t.Fatalf("err = %v; want an invalid .env file error", err)
|
t.Fatalf("err = %v; want an invalid .env file error", err)
|
||||||
|
|||||||
Reference in new issue
Block a user