You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Default value of Cobra flag overrides the viper env variable #671
I maybe mistaken here but i'm currently under the assumption that viper takes care of the order of precedence when it comes to where the value comes from: config file -> env var -> flag.
I'm finding that the default value that is used in the flag always overrides the env var. To overcome this i have to set the default value to be empty and then i have to check to see if the value is empty before using the env var value. Is this correct?
Here's the test code:
package cmd
import (
"fmt"
"os"
"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var defaultConfigFilename = "abc-config"
var defaultConfigExt = "json"
var defaultLogPath = "/var/logs/abc/"
func NewRootCommand() *cobra.Command {
configFile := ""
rootCmd := &cobra.Command{
Use: "test",
Short: "Test",
Long: `Test`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(configFile)
},
}
initConfig := func() {
if configFile == "" {
// Try and get from env
configFile = viper.GetString("configFile")
}
// Don't forget to read config either from configFile or from home directory!
if configFile != "" {
// Use config file from the flag.
viper.SetConfigFile(configFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Search config in home directory with name "abc-config" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(defaultConfigFilename)
}
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Can't read config:", err)
os.Exit(1)
}
}
cobra.OnInitialize(initConfig)
viper.SetEnvPrefix("ABC")
viper.AutomaticEnv()
rootCmd.Flags().StringVarP(&configFile, "configFile", "c", "", fmt.Sprintf("config file (default is ~/%s.%s)", defaultConfigFilename, defaultConfigExt))
viper.BindPFlag("configFile", rootCmd.Flags().Lookup("configFile"))
return rootCmd
}
Thank you for the quick response. I'll close this ticket since it's known. It might be worth mentioning in the readme... i guess i could change it and open a pull request too :)
Why is this a known accepted behavior?!
Cobra integration with Viper is broken and can't be used with environment variable - it should be in big bold letters on the README
Reacted by Andy Lo-A-Foe, Andy Suderman, Paul Cody, Chris Johnson, Ted Scharff, Lennart, z10n0110, mattsee, Kamran Khan, Jamie Lennox and 23 more
I've been using viper and cobra together on multiple CLIs for a couple years now and with a bit of custom code you can get them to integrate such that the config stacks:
flags > environment variables > configuration files > flag defaults
I wrote a sample working app with tests that demonstrates how to integrate them and a blog post that explains it in a bit more detail. Apologies if I am misunderstanding the OP (if I did, let me know and I'll remove/edit this), but hopefully the sample helps them out.
Reacted by ›, Robert Deusser, Dan Sikes, Nathan Witmer, Ante Gulin, Ashley Connor, alex , Andrew R. Schoewe, Anton Ustyuzhanin, Stefan Nica and 13 more
Reacted by ›, Robert Deusser, Tim Chen, Ashley Connor, Danny Kulchinsky and Wiliam Souza
Reacted by Ashley Connor, Anton Ustyuzhanin, virtualtam, Danny Kulchinsky, Georg Grütter, Maxim Makarov aka pr0n1x and Wiliam Souza
The Sting of the Viper demo by @carolynvs was written end of 2020, and uses BindEnv directly. There's a simplification possible by using viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")). Have submitted a PR in that repo.
Activity
sagikazarmark commentedon Mar 20, 2019
Yup, currently you can't really do anything else, but not define a default value for flags.
ankur22 commentedon Mar 20, 2019
Thank you for the quick response. I'll close this ticket since it's known. It might be worth mentioning in the readme... i guess i could change it and open a pull request too :)
ekampf commentedon Aug 29, 2019
Why is this a known accepted behavior?!
Cobra integration with Viper is broken and can't be used with environment variable - it should be in big bold letters on the README
carolynvs commentedon Aug 9, 2020
I've been using viper and cobra together on multiple CLIs for a couple years now and with a bit of custom code you can get them to integrate such that the config stacks:
flags > environment variables > configuration files > flag defaults
I wrote a sample working app with tests that demonstrates how to integrate them and a blog post that explains it in a bit more detail. Apologies if I am misunderstanding the OP (if I did, let me know and I'll remove/edit this), but hopefully the sample helps them out.
hyorigo commentedon Aug 20, 2020
@carolynvs Great works! Thanks!
CLI: Fixed handling of env variables for global options
CLI: Fixed handling of env variables for global options
ezk84 commentedon Aug 23, 2022
The Sting of the Viper demo by @carolynvs was written end of 2020, and uses
BindEnvdirectly. There's a simplification possible by usingviper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")). Have submitted a PR in that repo.