-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cmd: adds env var backups to command flags
Signed-off-by: Colin Lacy <colinjlacy@gmail.com>
- Loading branch information
1 parent
3acc0b9
commit b76157b
Showing
335 changed files
with
47,763 additions
and
536 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package env | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/spf13/pflag" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
type cmdFlags interface { | ||
CheckEnvironmentVariables(command *cobra.Command) error | ||
} | ||
|
||
type cmdFlagsImpl struct{} | ||
|
||
var ( | ||
CmdFlags cmdFlags = cmdFlagsImpl{} | ||
errorMessagePrefix = "error mapping environment variables to command flags" | ||
) | ||
|
||
const globalPrefix = "opa" | ||
|
||
func (cf cmdFlagsImpl) CheckEnvironmentVariables(command *cobra.Command) error { | ||
var errs []string | ||
v := viper.New() | ||
v.AutomaticEnv() | ||
if command.Name() == globalPrefix { | ||
v.SetEnvPrefix(command.Name()) | ||
} else { | ||
v.SetEnvPrefix(fmt.Sprintf("%s_%s", globalPrefix, command.Name())) | ||
} | ||
command.Flags().VisitAll(func(f *pflag.Flag) { | ||
configName := f.Name | ||
configName = strings.Replace(configName, "-", "_", -1) | ||
if !f.Changed && v.IsSet(configName) { | ||
val := v.Get(configName) | ||
err := command.Flags().Set(f.Name, fmt.Sprintf("%v", val)) | ||
if err != nil { | ||
errs = append(errs, err.Error()) | ||
} | ||
} | ||
}) | ||
|
||
if len(errs) == 0 { | ||
return nil | ||
} | ||
return fmt.Errorf("%s: %s", errorMessagePrefix, strings.Join(errs, "; ")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
package env | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
func mockRootCmd(writer io.Writer) *cobra.Command { | ||
var rootArgs struct { | ||
IntFlag int | ||
StrFlag string | ||
BoolFlag bool | ||
} | ||
cmd := cobra.Command{ | ||
Use: "opa [opts]", | ||
Short: "test root command", | ||
Long: `test root command`, | ||
PreRunE: func(cmd *cobra.Command, args []string) error { | ||
return CmdFlags.CheckEnvironmentVariables(cmd) | ||
}, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
fmt.Fprintf(writer, "%v; %v; %v", rootArgs.IntFlag, rootArgs.StrFlag, rootArgs.BoolFlag) | ||
}, | ||
} | ||
cmd.Flags().IntVarP(&rootArgs.IntFlag, "int", "i", 0, "set int") | ||
cmd.Flags().StringVarP(&rootArgs.StrFlag, "some-string", "s", "", "set string") | ||
cmd.Flags().BoolVarP(&rootArgs.BoolFlag, "bool", "b", false, "set bool") | ||
return &cmd | ||
} | ||
|
||
func mockChildCmd(writer io.Writer) *cobra.Command { | ||
var rootArgs struct { | ||
IntFlag int | ||
StrFlag string | ||
BoolFlag bool | ||
} | ||
cmd := cobra.Command{ | ||
Use: "child [opts]", | ||
Short: "test child command", | ||
Long: `test child command`, | ||
PreRunE: func(cmd *cobra.Command, args []string) error { | ||
return CmdFlags.CheckEnvironmentVariables(cmd) | ||
}, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
fmt.Fprintf(writer, "%v; %v; %v", rootArgs.IntFlag, rootArgs.StrFlag, rootArgs.BoolFlag) | ||
}, | ||
} | ||
cmd.Flags().IntVarP(&rootArgs.IntFlag, "second-int", "i", 100, "set int") | ||
cmd.Flags().StringVarP(&rootArgs.StrFlag, "second-string", "s", "child-string", "set string") | ||
cmd.Flags().BoolVarP(&rootArgs.BoolFlag, "second-bool", "b", true, "set bool") | ||
return &cmd | ||
} | ||
|
||
func TestCmdFlagsImpl_CheckEnvironmentVariables_NoEnvVarsSingleCommand(t *testing.T) { | ||
rootWriter := bytes.NewBuffer([]byte{}) | ||
root := mockRootCmd(rootWriter) | ||
if err := root.PreRunE(root, []string{}); err != nil { | ||
t.Fatalf("unexpected error: %s", err.Error()) | ||
} | ||
root.Run(root, []string{}) | ||
out := rootWriter.String() | ||
expectation := "0; ; false" | ||
if out != expectation { | ||
t.Fatalf("expected default flag values %q, got %q", expectation, out) | ||
} | ||
} | ||
|
||
func TestCmdFlagsImpl_CheckEnvironmentVariables_OneEnvVarsSingleCommand(t *testing.T) { | ||
rootWriter := bytes.NewBuffer([]byte{}) | ||
root := mockRootCmd(rootWriter) | ||
t.Setenv("OPA_INT", "3") | ||
if err := root.PreRunE(root, []string{}); err != nil { | ||
t.Fatalf("unexpected error: %s", err.Error()) | ||
} | ||
root.Run(root, []string{}) | ||
out := rootWriter.String() | ||
expectation := "3; ; false" | ||
if out != expectation { | ||
t.Fatalf("expected flag values %q, got %q", expectation, out) | ||
} | ||
} | ||
|
||
func TestCmdFlagsImpl_CheckEnvironmentVariables_AllEnvVarsSingleCommand(t *testing.T) { | ||
rootWriter := bytes.NewBuffer([]byte{}) | ||
root := mockRootCmd(rootWriter) | ||
t.Setenv("OPA_INT", "40") | ||
t.Setenv("OPA_SOME_STRING", "test") | ||
t.Setenv("OPA_BOOL", "true") | ||
if err := root.PreRunE(root, []string{}); err != nil { | ||
t.Fatalf("unexpected error: %s", err.Error()) | ||
} | ||
root.Run(root, []string{}) | ||
out := rootWriter.String() | ||
expectation := "40; test; true" | ||
if out != expectation { | ||
t.Fatalf("expected flag values %q, got %q", expectation, out) | ||
} | ||
} | ||
|
||
func TestCmdFlagsImpl_CheckEnvironmentVariables_ChildCommandAllEnvVars(t *testing.T) { | ||
root := mockRootCmd(&bytes.Buffer{}) | ||
childWriter := bytes.NewBuffer([]byte{}) | ||
child := mockChildCmd(childWriter) | ||
root.AddCommand(child) | ||
t.Setenv("OPA_CHILD_SECOND_INT", "7") | ||
t.Setenv("OPA_CHILD_SECOND_STRING", "testing child") | ||
t.Setenv("OPA_CHILD_SECOND_BOOL", "false") | ||
if err := child.PreRunE(child, []string{}); err != nil { | ||
t.Fatalf("unexpected error: %s", err.Error()) | ||
} | ||
child.Run(child, []string{}) | ||
childOut := childWriter.String() | ||
childExpectation := "7; testing child; false" | ||
if childOut != childExpectation { | ||
t.Fatalf("expected child flag values %q, got %q", childExpectation, childOut) | ||
} | ||
} | ||
|
||
func TestCmdFlagsImpl_CheckEnvironmentVariables_ChildCommandReturnsSingleErr(t *testing.T) { | ||
root := mockRootCmd(&bytes.Buffer{}) | ||
child := mockChildCmd(&bytes.Buffer{}) | ||
root.AddCommand(child) | ||
t.Setenv("OPA_CHILD_SECOND_BOOL", "7") | ||
err := child.PreRunE(child, []string{}) | ||
if err == nil { | ||
t.Fatalf("expected error, found none") | ||
} | ||
expectedString := "invalid argument \"7\"" | ||
if !strings.Contains(err.Error(), expectedString) { | ||
t.Fatalf("expected error to include %q, instead got %q", expectedString, err.Error()) | ||
} | ||
} | ||
|
||
func TestCmdFlagsImpl_CheckEnvironmentVariables_ChildCommandReturnsMultipleErr(t *testing.T) { | ||
root := mockRootCmd(&bytes.Buffer{}) | ||
child := mockChildCmd(&bytes.Buffer{}) | ||
root.AddCommand(child) | ||
t.Setenv("OPA_CHILD_SECOND_INT", "true") | ||
t.Setenv("OPA_CHILD_SECOND_BOOL", "7") | ||
err := child.PreRunE(child, []string{"child"}) | ||
expectedString := "invalid argument" | ||
if err == nil { | ||
t.Fatalf("expected error, found none") | ||
} | ||
if !strings.Contains(err.Error(), expectedString) { | ||
t.Fatalf("expected error to include %q, instead got %q", expectedString, err.Error()) | ||
} | ||
if !strings.Contains(err.Error(), "7") { | ||
t.Fatalf("expected error for invalid int 7 as argument for boolean flag") | ||
} | ||
if !strings.Contains(err.Error(), "true") { | ||
t.Fatalf("expected error for invalid int 7 as argument for int flag") | ||
} | ||
} | ||
|
||
func TestCmdFlagsImpl_CheckEnvironmentVariables_ConfirmCommandFlagPrecedence(t *testing.T) { | ||
rootWriter := bytes.NewBuffer([]byte{}) | ||
root := mockRootCmd(rootWriter) | ||
t.Setenv("OPA_INT", "3") | ||
t.Setenv("OPA_BOOL", "true") | ||
root.SetArgs([]string{"-i", "42"}) | ||
if err := root.Execute(); err != nil { | ||
t.Fatalf("unexpected error: %s", err.Error()) | ||
} | ||
out := rootWriter.String() | ||
expectation := "42; ; true" | ||
if out != expectation { | ||
t.Fatalf("expected flag values %q, got %q", expectation, out) | ||
} | ||
} |
Oops, something went wrong.