Skip to content

Commit a1f2afe

Browse files
fix viper binding for StringArray flags from YAML config
1 parent 181be80 commit a1f2afe

File tree

2 files changed

+131
-2
lines changed

2 files changed

+131
-2
lines changed

internal/cmdutils/bind-viper-to-flags.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,24 @@ func BindViperToFlags(cmd *cobra.Command, viperInstance *viper.Viper) {
3131

3232
if !flag.Changed && viperInstance.IsSet(configName) {
3333
value := viperInstance.Get(configName)
34-
err := cmd.Flags().Set(flag.Name, fmt.Sprintf("%v", value))
35-
cobra.CheckErr(err)
34+
setFlagFromViper(cmd, flag, value)
3635
}
3736
})
3837

3938
for _, subcmd := range cmd.Commands() {
4039
BindViperToFlags(subcmd, viperInstance)
4140
}
4241
}
42+
43+
func setFlagFromViper(cmd *cobra.Command, flag *pflag.Flag, value interface{}) {
44+
switch v := value.(type) {
45+
case []interface{}:
46+
for _, elem := range v {
47+
err := cmd.Flags().Set(flag.Name, fmt.Sprintf("%v", elem))
48+
cobra.CheckErr(err)
49+
}
50+
default:
51+
err := cmd.Flags().Set(flag.Name, fmt.Sprintf("%v", v))
52+
cobra.CheckErr(err)
53+
}
54+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
Copyright © 2023 OpenFGA
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cmdutils_test
18+
19+
import (
20+
"testing"
21+
22+
"github.com/spf13/cobra"
23+
"github.com/spf13/viper"
24+
"github.com/stretchr/testify/assert"
25+
"github.com/stretchr/testify/require"
26+
27+
"github.com/openfga/cli/internal/cmdutils"
28+
)
29+
30+
func TestBindViperToFlags_StringArrayFromYAML(t *testing.T) {
31+
t.Parallel()
32+
33+
testcases := []struct {
34+
name string
35+
config map[string]interface{}
36+
expected []string
37+
}{
38+
{
39+
name: "yaml list binds as multiple values",
40+
config: map[string]interface{}{
41+
"custom-headers": []interface{}{
42+
"X-Custom-Header: value1",
43+
"X-Request-ID: abc123",
44+
},
45+
},
46+
expected: []string{"X-Custom-Header: value1", "X-Request-ID: abc123"},
47+
},
48+
{
49+
name: "single element list",
50+
config: map[string]interface{}{
51+
"custom-headers": []interface{}{
52+
"X-Custom-Header: value1",
53+
},
54+
},
55+
expected: []string{"X-Custom-Header: value1"},
56+
},
57+
{
58+
name: "no config leaves default",
59+
config: map[string]interface{}{},
60+
expected: []string{},
61+
},
62+
}
63+
64+
for _, test := range testcases {
65+
t.Run(test.name, func(t *testing.T) {
66+
t.Parallel()
67+
68+
cmd := &cobra.Command{Use: "test"}
69+
cmd.Flags().StringArray("custom-headers", []string{}, "test flag")
70+
71+
v := viper.New()
72+
for k, val := range test.config {
73+
v.Set(k, val)
74+
}
75+
76+
cmdutils.BindViperToFlags(cmd, v)
77+
78+
result, err := cmd.Flags().GetStringArray("custom-headers")
79+
require.NoError(t, err)
80+
assert.Equal(t, test.expected, result)
81+
})
82+
}
83+
}
84+
85+
func TestBindViperToFlags_ScalarFlagUnchanged(t *testing.T) {
86+
t.Parallel()
87+
88+
cmd := &cobra.Command{Use: "test"}
89+
cmd.Flags().String("api-url", "http://localhost:8080", "test flag")
90+
91+
v := viper.New()
92+
v.Set("api-url", "https://api.fga.example")
93+
94+
cmdutils.BindViperToFlags(cmd, v)
95+
96+
result, err := cmd.Flags().GetString("api-url")
97+
require.NoError(t, err)
98+
assert.Equal(t, "https://api.fga.example", result)
99+
}
100+
101+
func TestBindViperToFlags_CLIFlagTakesPrecedence(t *testing.T) {
102+
t.Parallel()
103+
104+
cmd := &cobra.Command{Use: "test"}
105+
cmd.Flags().StringArray("custom-headers", []string{}, "test flag")
106+
107+
require.NoError(t, cmd.Flags().Set("custom-headers", "X-CLI: from-flag"))
108+
109+
v := viper.New()
110+
v.Set("custom-headers", []interface{}{"X-Config: from-yaml"})
111+
112+
cmdutils.BindViperToFlags(cmd, v)
113+
114+
result, err := cmd.Flags().GetStringArray("custom-headers")
115+
require.NoError(t, err)
116+
assert.Equal(t, []string{"X-CLI: from-flag"}, result)
117+
}

0 commit comments

Comments
 (0)