parent
2befc27adf
commit
285502a8ae
|
@ -8,6 +8,7 @@
|
|||
1. [18541](https://github.com/influxdata/influxdb/pull/18541): Pkger allow raw github.com host URLs for yaml|json|jsonnet URLs
|
||||
1. [18546](https://github.com/influxdata/influxdb/pull/18546): Influx allow for files to be remotes for all template commands
|
||||
1. [18560](https://github.com/influxdata/influxdb/pull/18560): Extend stacks API with update capability
|
||||
1. [18568](https://github.com/influxdata/influxdb/pull/18568): Add support for config files to influxd and any cli.NewCommand use case
|
||||
|
||||
## v2.0.0-beta.12 [2020-06-12]
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package cli
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -52,7 +53,7 @@ type Program struct {
|
|||
//
|
||||
// This is to simplify the viper/cobra boilerplate.
|
||||
func NewCommand(p *Program) *cobra.Command {
|
||||
var cmd = &cobra.Command{
|
||||
cmd := &cobra.Command{
|
||||
Use: p.Name,
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
|
@ -65,11 +66,37 @@ func NewCommand(p *Program) *cobra.Command {
|
|||
// This normalizes "-" to an underscore in env names.
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||
|
||||
configFile := viper.GetString("CONFIG_FILE")
|
||||
if configFile == "" {
|
||||
// defaults to looking in same directory as program running for
|
||||
// a file `config.yaml`
|
||||
configFile = "config.yaml"
|
||||
}
|
||||
viper.SetConfigFile(configFile)
|
||||
|
||||
// done before we bind flags to viper keys.
|
||||
// order of precedence (1 highest -> 3 lowest):
|
||||
// 1. flags
|
||||
// 2. env vars
|
||||
// 3. config file
|
||||
if err := initializeConfig(); err != nil {
|
||||
panic(fmt.Sprintf("invalid config file[%s] caused panic: %s", configFile, err))
|
||||
}
|
||||
BindOptions(cmd, p.Opts)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func initializeConfig() error {
|
||||
err := viper.ReadInConfig()
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BindOptions adds opts to the specified command and automatically
|
||||
// registers those options with viper.
|
||||
func BindOptions(cmd *cobra.Command, opts []Opt) {
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type customFlag bool
|
||||
|
@ -101,3 +107,93 @@ func ExampleNewCommand() {
|
|||
// [foo bar]
|
||||
// on
|
||||
}
|
||||
|
||||
func Test_NewProgram(t *testing.T) {
|
||||
testFilePath, cleanup := newConfigFile(t, map[string]string{
|
||||
"FOO": "bar",
|
||||
})
|
||||
defer cleanup()
|
||||
defer setEnvVar("TEST_CONFIG_FILE", testFilePath)()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
envVarVal string
|
||||
args []string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "no vals reads from config",
|
||||
expected: "bar",
|
||||
},
|
||||
{
|
||||
name: "reads from env var",
|
||||
envVarVal: "foobar",
|
||||
expected: "foobar",
|
||||
},
|
||||
{
|
||||
name: "reads from flag",
|
||||
args: []string{"--foo=baz"},
|
||||
expected: "baz",
|
||||
},
|
||||
{
|
||||
name: "flag has highest precedence",
|
||||
envVarVal: "foobar",
|
||||
args: []string{"--foo=baz"},
|
||||
expected: "baz",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
fn := func(t *testing.T) {
|
||||
if tt.envVarVal != "" {
|
||||
defer setEnvVar("TEST_FOO", tt.envVarVal)()
|
||||
}
|
||||
|
||||
var testVar string
|
||||
program := &Program{
|
||||
Name: "test",
|
||||
Opts: []Opt{
|
||||
{
|
||||
DestP: &testVar,
|
||||
Flag: "foo",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
Run: func() error { return nil },
|
||||
}
|
||||
|
||||
cmd := NewCommand(program)
|
||||
cmd.SetArgs(append([]string{}, tt.args...))
|
||||
require.NoError(t, cmd.Execute())
|
||||
|
||||
require.Equal(t, tt.expected, testVar)
|
||||
}
|
||||
|
||||
t.Run(tt.name, fn)
|
||||
}
|
||||
}
|
||||
|
||||
func setEnvVar(key, val string) func() {
|
||||
old := os.Getenv(key)
|
||||
os.Setenv(key, val)
|
||||
return func() {
|
||||
os.Setenv(key, old)
|
||||
}
|
||||
}
|
||||
|
||||
func newConfigFile(t *testing.T, config interface{}) (string, func()) {
|
||||
t.Helper()
|
||||
|
||||
testDir, err := ioutil.TempDir("", "")
|
||||
require.NoError(t, err)
|
||||
|
||||
b, err := json.Marshal(config)
|
||||
require.NoError(t, err)
|
||||
|
||||
testFile := path.Join(testDir, "config.json")
|
||||
require.NoError(t, ioutil.WriteFile(testFile, b, os.ModePerm))
|
||||
|
||||
return testFile, func() {
|
||||
os.RemoveAll(testDir)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue