Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ limitations under the License.
package cmd

import (
"errors"
"fmt"
"io"
"os"
"strings"

Expand Down Expand Up @@ -119,10 +121,7 @@ func initConfig() {
viperInstance.SetConfigName(".fga")
}

// If a config file is found, read it in.
if err := viperInstance.ReadInConfig(); err == nil {
fmt.Fprintln(os.Stderr, "Using config file:", viperInstance.ConfigFileUsed())
}
readConfig(viperInstance, os.Stderr)

viperInstance.SetEnvPrefix("FGA")
viperInstance.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
Expand All @@ -131,3 +130,19 @@ func initConfig() {

cmdutils.BindViperToFlags(rootCmd, viperInstance)
}

// readConfig reads the config file into viperInstance, if one is found, and reports on stderr which file is
// used. A config file that exists but can't be read, e.g. because of invalid YAML, is reported as a
// warning instead of being ignored silently.
func readConfig(viperInstance *viper.Viper, stderr io.Writer) {
err := viperInstance.ReadInConfig()
if err == nil {
fmt.Fprintln(stderr, "Using config file:", viperInstance.ConfigFileUsed())

return
}

if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
fmt.Fprintf(stderr, "Warning: ignoring config file %s: %v\n", viperInstance.ConfigFileUsed(), err)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
Comment thread
Siddhant-K-code marked this conversation as resolved.
Resolved
}
}
98 changes: 98 additions & 0 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package cmd

import (
"bytes"
"os"
"path/filepath"
"testing"

"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestReadConfig(t *testing.T) {
t.Parallel()

t.Run("valid config file", func(t *testing.T) {
t.Parallel()

configFile := filepath.Join(t.TempDir(), ".fga.yaml")
require.NoError(t, os.WriteFile(configFile, []byte("api-url: https://api.fga.example\n"), 0o600))

viperInstance := viper.New()
viperInstance.SetConfigFile(configFile)

var stderr bytes.Buffer
readConfig(viperInstance, &stderr)

assert.Equal(t, "Using config file: "+configFile+"\n", stderr.String())
assert.Equal(t, "https://api.fga.example", viperInstance.GetString("api-url"))
})

t.Run("invalid config file", func(t *testing.T) {
t.Parallel()

configFile := filepath.Join(t.TempDir(), ".fga.yaml")
// YAML doesn't allow tabs for indentation
content := "api-url: https://api.fga.example\nstore-id: 01H0H015178Y2V4CX10C2KGHF4\n\tapi-token: token\n"
require.NoError(t, os.WriteFile(configFile, []byte(content), 0o600))

viperInstance := viper.New()
viperInstance.SetConfigFile(configFile)
Comment thread
Siddhant-K-code marked this conversation as resolved.
Resolved

var stderr bytes.Buffer
readConfig(viperInstance, &stderr)

assert.Contains(t, stderr.String(), "Warning: ignoring config file "+configFile+": ")
assert.Empty(t, viperInstance.GetString("api-url"))
})

t.Run("invalid config file found in the search paths", func(t *testing.T) {
t.Parallel()

configDir := t.TempDir()
configFile := filepath.Join(configDir, ".fga.yaml")
// YAML doesn't allow tabs for indentation
content := "api-url: https://api.fga.example\nstore-id: 01H0H015178Y2V4CX10C2KGHF4\n\tapi-token: token\n"
require.NoError(t, os.WriteFile(configFile, []byte(content), 0o600))

viperInstance := viper.New()
viperInstance.AddConfigPath(configDir)
viperInstance.SetConfigName(".fga")
viperInstance.SetConfigType("yaml")

var stderr bytes.Buffer
readConfig(viperInstance, &stderr)

assert.Contains(t, stderr.String(), "Warning: ignoring config file "+configFile+": ")
assert.Empty(t, viperInstance.GetString("api-url"))
})

t.Run("config file given with --config doesn't exist", func(t *testing.T) {
t.Parallel()

configFile := filepath.Join(t.TempDir(), "missing.fga.yaml")

viperInstance := viper.New()
viperInstance.SetConfigFile(configFile)

var stderr bytes.Buffer
readConfig(viperInstance, &stderr)

assert.Contains(t, stderr.String(), "Warning: ignoring config file "+configFile+": ")
})

t.Run("no config file found", func(t *testing.T) {
t.Parallel()

viperInstance := viper.New()
viperInstance.AddConfigPath(t.TempDir())
viperInstance.SetConfigName(".fga")

var stderr bytes.Buffer
readConfig(viperInstance, &stderr)

assert.Empty(t, stderr.String())
})
}