1

We have a binary we are starting which has several subcommands, all set up with cobra. And we want to use viper for configuration. So the initialization of this is setup according to the docs:

func init() {
    cobra.OnInitialize(initConfig)    

    RootCmd.PersistentFlags().StringVarP(&loglevel, "loglevel", "l", "info", "Default log level")
    //other persistent flags    
    viper.BindPFlags(RootCmd.PersistentFlags())

    log.CreateLogger(loglevel)

    //add all other subcommands
    RootCmd.AddCommand(...)
}

My issue is with initConfig:

func initConfig() {
    if cfgFile != "" {
        // Use config file from the flag.
        viper.SetConfigFile(cfgFile)
    } else {
        // Find home directory.
        home, err := homedir.Dir()
        if err != nil {
            handleError(err)
            os.Exit(1)
        }
        confDir = filepath.Join(home, DefaultConfigDir)
        viper.Set("configDir", configDir)

        viper.SetConfigName("config")
        viper.SetConfigType("json")
        viper.AddConfigPath(configDir)
        viper.AddConfigPath(".")

        cfgFile = filepath.Join(configDir, "config.json")
    }

    viper.AutomaticEnv()

    if err := viper.ReadInConfig(); err != nil {
        if _, ok := err.(viper.ConfigFileNotFoundError); ok {
            // Config file not found; ignore error if desired               l
            err := os.Mkdir(cfgDir, os.ModePerm)
            if err != nil {
                handleError(err)
            }
            err = viper.WriteConfigAs(cfgFile)
            if err != nil {
                handleError(err)
            }
        } else {
            handleError(err)
            os.Exit(1)
        }
    }
}

This runs inside init, and this is in my subcommands package - so my subcommands tests will run this init as well.

Trouble is it looks for the home folder, and of course may mess with existing configs. In other words, I don't want this for testing, I want a clean testing directory.

How can I achieve this? As it has to run inside init because of the flags and the early initialization of configs, I have not been able to figure out an alternative.

transient_loop
  • 5,984
  • 15
  • 58
  • 117
  • Have you truly figured out execution sequence? From documentation for cobra.OnInitialize, OnInitialize sets the passed functions to be run when each command's Execute method is called. This means that initConfig is called after command execution. One option would be to manually set value to cfgFile and point it to a valid cfgFile. This will skip home directory look-up. – praveent Apr 21 '20 at 02:17
  • hmmm looks like I may have got this wrong indeed. I will have to rethink the initialization sequence in this case. Thanks @praveent – transient_loop Apr 21 '20 at 14:25
  • What's even more bothering, but I guess it should be a separate question, is that with this code, flags cannot be passed to tests: `$ go test -v -count 1 ./cli/cmd -run TestRun --loglevel debug flag provided but not defined: -loglevel ` I have no idea what I am doing wrong there. – transient_loop Apr 21 '20 at 14:55
  • why not delete the question as it is more to do with code than cobra itself. As for your second query, here is a good article I found that can help. https://blog.jbowen.dev/2019/08/using-go-flags-in-tests/. I would advise creating a separate question on flag question as this one looks like your code issue. – praveent Apr 22 '20 at 04:13

0 Answers0