feat(config): add --configFile argument to specify custom config file

It will also look by default to `/etc/sablier/` then `$XDG_CONFIG_HOME` then `$HOME/.config/` and then `.`.

Closes #91
This commit is contained in:
Alexis Couvreur
2022-11-10 16:28:48 +00:00
parent 546b378416
commit 98023a853a
4 changed files with 26 additions and 34 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,3 @@
.devcontainer .devcontainer
config.yaml sablier.yaml
./plugins/traefik/e2e/kubeconfig.yaml ./plugins/traefik/e2e/kubeconfig.yaml

View File

@@ -16,9 +16,9 @@ RUN make ${TARGETOS}/${TARGETARCH}
FROM alpine FROM alpine
COPY --from=build /go/src/sablier/sablier* /go/bin/sablier COPY --from=build /go/src/sablier/sablier* /etc/sablier/sablier
EXPOSE 10000 EXPOSE 10000
ENTRYPOINT [ "/go/bin/sablier" ] ENTRYPOINT [ "/etc/sablier/sablier" ]
CMD [ "start", "--provider.name=docker"] CMD [ "start", "--provider.name=docker"]

View File

@@ -15,10 +15,11 @@ import (
const ( const (
// The name of our config file, without the file extension because viper supports many different config file languages. // The name of our config file, without the file extension because viper supports many different config file languages.
defaultConfigFilename = "config" defaultConfigFilename = "sablier"
) )
var conf = config.NewConfig() var conf = config.NewConfig()
var cfgFile string
func Execute() { func Execute() {
cmd := NewRootCommand() cmd := NewRootCommand()
@@ -39,6 +40,8 @@ It provides an integrations with multiple reverse proxies and different loading
}, },
} }
rootCmd.PersistentFlags().StringVar(&cfgFile, "configFile", "", "Config file path. If not defined, looks for sablier.(yml|yaml|toml) in /etc/sablier/ > $XDG_CONFIG_HOME > $HOME/.config/ and current directory")
startCmd := newStartCommand() startCmd := newStartCommand()
// Provider flags // Provider flags
startCmd.Flags().StringVar(&conf.Provider.Name, "provider.name", "docker", fmt.Sprintf("Provider to use to manage containers %v", config.GetProviders())) startCmd.Flags().StringVar(&conf.Provider.Name, "provider.name", "docker", fmt.Sprintf("Provider to use to manage containers %v", config.GetProviders()))
@@ -85,10 +88,15 @@ func initializeConfig(cmd *cobra.Command) error {
// Set the base name of the config file, without the file extension. // Set the base name of the config file, without the file extension.
v.SetConfigName(defaultConfigFilename) v.SetConfigName(defaultConfigFilename)
// Set as many paths as you like where viper should look for the v.AddConfigPath("/etc/sablier/")
// config file. We are only looking in the current working directory. v.AddConfigPath("$XDG_CONFIG_HOME")
v.AddConfigPath("$HOME/.config/")
v.AddConfigPath(".") v.AddConfigPath(".")
if cfgFile != "" {
v.SetConfigFile(cfgFile)
}
// Attempt to read the config file, gracefully ignoring errors // Attempt to read the config file, gracefully ignoring errors
// caused by a config file not being found. Return an error // caused by a config file not being found. Return an error
// if we cannot parse the config file. // if we cannot parse the config file.
@@ -96,6 +104,9 @@ func initializeConfig(cmd *cobra.Command) error {
// It's okay if there isn't a config file // It's okay if there isn't a config file
if _, ok := err.(viper.ConfigFileNotFoundError); !ok { if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
return err return err
} else if cfgFile != "" {
// But if we explicitely defined the config file it should return the error
return err
} }
} }

View File

@@ -18,24 +18,13 @@ import (
) )
func TestPrecedence(t *testing.T) { func TestPrecedence(t *testing.T) {
// Run the tests in a temporary directory
tmpDir := os.TempDir()
testDir, err := os.Getwd() testDir, err := os.Getwd()
require.NoError(t, err, "error getting the current working directory") require.NoError(t, err, "error getting the current working directory")
defer os.Chdir(testDir)
err = os.Chdir(tmpDir)
require.NoError(t, err, "error changing to the temporary test directory")
// CHANGE `startCmd` behavior to only print the config, this is for testing purposes only // CHANGE `startCmd` behavior to only print the config, this is for testing purposes only
newStartCommand = mockStartCommand newStartCommand = mockStartCommand
t.Run("config file", func(t *testing.T) { t.Run("config file", func(t *testing.T) {
configB, err := os.ReadFile(filepath.Join(testDir, "testdata", "config.yml"))
require.NoError(t, err, "error reading test config file")
err = ioutil.WriteFile(filepath.Join(tmpDir, "config.yml"), configB, 0644)
require.NoError(t, err, "error writing test config file")
defer os.Remove(filepath.Join(tmpDir, "config.yml"))
wantConfig, err := ioutil.ReadFile(filepath.Join(testDir, "testdata", "config_yaml_wanted.json")) wantConfig, err := ioutil.ReadFile(filepath.Join(testDir, "testdata", "config_yaml_wanted.json"))
require.NoError(t, err, "error reading test config file") require.NoError(t, err, "error reading test config file")
@@ -43,7 +32,10 @@ func TestPrecedence(t *testing.T) {
cmd := NewRootCommand() cmd := NewRootCommand()
output := &bytes.Buffer{} output := &bytes.Buffer{}
cmd.SetOut(output) cmd.SetOut(output)
cmd.SetArgs([]string{"start"}) cmd.SetArgs([]string{
"--configFile", filepath.Join(testDir, "testdata", "config.yml"),
"start",
})
cmd.Execute() cmd.Execute()
gotOutput := output.String() gotOutput := output.String()
@@ -52,13 +44,6 @@ func TestPrecedence(t *testing.T) {
}) })
t.Run("env var", func(t *testing.T) { t.Run("env var", func(t *testing.T) {
// 1. Load Config file for precedence assertions
configB, err := os.ReadFile(filepath.Join(testDir, "testdata", "config.yml"))
require.NoError(t, err, "error reading test config file")
err = ioutil.WriteFile(filepath.Join(tmpDir, "config.yml"), configB, 0644)
require.NoError(t, err, "error writing test config file")
defer os.Remove(filepath.Join(tmpDir, "config.yml"))
setEnvsFromFile(filepath.Join(testDir, "testdata", "config.env")) setEnvsFromFile(filepath.Join(testDir, "testdata", "config.env"))
defer unsetEnvsFromFile(filepath.Join(testDir, "testdata", "config.env")) defer unsetEnvsFromFile(filepath.Join(testDir, "testdata", "config.env"))
@@ -69,7 +54,10 @@ func TestPrecedence(t *testing.T) {
cmd := NewRootCommand() cmd := NewRootCommand()
output := &bytes.Buffer{} output := &bytes.Buffer{}
cmd.SetOut(output) cmd.SetOut(output)
cmd.SetArgs([]string{"start"}) cmd.SetArgs([]string{
"--configFile", filepath.Join(testDir, "testdata", "config.yml"),
"start",
})
cmd.Execute() cmd.Execute()
gotOutput := output.String() gotOutput := output.String()
@@ -78,14 +66,6 @@ func TestPrecedence(t *testing.T) {
}) })
t.Run("flag", func(t *testing.T) { t.Run("flag", func(t *testing.T) {
// 1. Load Config file for precedence assertions
configB, err := os.ReadFile(filepath.Join(testDir, "testdata", "config.yml"))
require.NoError(t, err, "error reading test config file")
err = ioutil.WriteFile(filepath.Join(tmpDir, "config.yml"), configB, 0644)
require.NoError(t, err, "error writing test config file")
defer os.Remove(filepath.Join(tmpDir, "config.yml"))
// 2. Load envs variable for precedence assertions
setEnvsFromFile(filepath.Join(testDir, "testdata", "config.env")) setEnvsFromFile(filepath.Join(testDir, "testdata", "config.env"))
defer unsetEnvsFromFile(filepath.Join(testDir, "testdata", "config.env")) defer unsetEnvsFromFile(filepath.Join(testDir, "testdata", "config.env"))
@@ -97,6 +77,7 @@ func TestPrecedence(t *testing.T) {
conf = config.NewConfig() conf = config.NewConfig()
cmd.SetOut(output) cmd.SetOut(output)
cmd.SetArgs([]string{ cmd.SetArgs([]string{
"--configFile", filepath.Join(testDir, "testdata", "config.yml"),
"start", "start",
"--provider.name", "cli", "--provider.name", "cli",
"--server.port", "3333", "--server.port", "3333",