Skip to content

add flag --survey to set to set/unset disable survey prompt #3732

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions cmd/skaffold/app/cmd/config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ limitations under the License.

package config

import "github.com/spf13/pflag"
import (
"github.com/spf13/pflag"
)

var (
configFile, kubecontext string
showAll, global bool
showAll, global, survey bool
)

func AddCommonFlags(f *pflag.FlagSet) {
Expand All @@ -34,4 +36,6 @@ func AddListFlags(f *pflag.FlagSet) {

func AddSetUnsetFlags(f *pflag.FlagSet) {
f.BoolVarP(&global, "global", "g", false, "Set value for global config")
f.BoolVarP(&survey, "survey", "s", false, "Set value for skaffold survey config")
f.MarkHidden("survey")
}
66 changes: 54 additions & 12 deletions cmd/skaffold/app/cmd/config/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ import (
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
)

const (
surveyFieldName = "Survey"
)

type cfgStruct struct {
value reflect.Value
rType reflect.Type
idx []int
}

func Set(out io.Writer, args []string) error {
if err := setConfigValue(args[0], args[1]); err != nil {
return err
Expand All @@ -44,34 +54,66 @@ func setConfigValue(name string, value string) error {
return err
}

fieldName := getFieldName(cfg, name)
if fieldName == "" {
return fmt.Errorf("%s is not a valid config field", name)
fieldIdx, err := getFieldIndex(cfg, name)
if err != nil {
return err
}

field := reflect.Indirect(reflect.ValueOf(cfg)).FieldByName(fieldName)
field := reflect.Indirect(reflect.ValueOf(cfg)).FieldByIndex(fieldIdx)
val, err := parseAsType(value, field)
if err != nil {
return fmt.Errorf("%s is not a valid value for field %s", value, name)
}

reflect.ValueOf(cfg).Elem().FieldByName(fieldName).Set(val)
reflect.ValueOf(cfg).Elem().FieldByIndex(fieldIdx).Set(val)

return writeConfig(cfg)
}

func getFieldName(cfg *config.ContextConfig, name string) string {
cfgValue := reflect.Indirect(reflect.ValueOf(cfg))
var fieldName string
for i := 0; i < cfgValue.NumField(); i++ {
fieldType := reflect.TypeOf(*cfg).Field(i)
func getFieldIndex(cfg *config.ContextConfig, name string) ([]int, error) {
cs, err := getConfigStructWithIndex(cfg)
if err != nil {
return nil, err
}
for i := 0; i < cs.value.NumField(); i++ {
fieldType := cs.rType.Field(i)
for _, tag := range strings.Split(fieldType.Tag.Get("yaml"), ",") {
if tag == name {
fieldName = fieldType.Name
if f, ok := cs.rType.FieldByName(fieldType.Name); ok {
return append(cs.idx, f.Index...), nil
}
return nil, fmt.Errorf("could not find config field %s", name)
}
}
}
return fieldName
return nil, fmt.Errorf("%s is not a valid config field", name)
}

func getConfigStructWithIndex(cfg *config.ContextConfig) (*cfgStruct, error) {
t := reflect.TypeOf(*cfg)
if survey {
if cfg.Survey == nil {
cfg.Survey = &config.SurveyConfig{}
}
return surveyStruct(cfg.Survey, t)
}
return &cfgStruct{
value: reflect.Indirect(reflect.ValueOf(cfg)),
rType: t,
idx: []int{},
}, nil
}

func surveyStruct(s *config.SurveyConfig, t reflect.Type) (*cfgStruct, error) {
surveyType := reflect.TypeOf(*s)
if surveyField, ok := t.FieldByName(surveyFieldName); ok {
return &cfgStruct{
value: reflect.Indirect(reflect.ValueOf(s)),
rType: surveyType,
idx: surveyField.Index,
}, nil
}
return nil, fmt.Errorf("survey config field 'Survey' not found in config struct %s", t.Name())
}

func parseAsType(value string, field reflect.Value) (reflect.Value, error) {
Expand Down
97 changes: 97 additions & 0 deletions cmd/skaffold/app/cmd/config/set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func TestSetAndUnsetConfig(t *testing.T) {
value string
kubecontext string
global bool
survey bool
shouldErr bool
}{
{
Expand Down Expand Up @@ -160,6 +161,71 @@ func TestSetAndUnsetConfig(t *testing.T) {
ContextConfigs: []*config.ContextConfig{},
},
},
{
description: "set global survey disable prompt",
key: "disable-prompt",
value: "true",
global: true,
survey: true,
expectedSetCfg: &config.GlobalConfig{
Global: &config.ContextConfig{
Survey: &config.SurveyConfig{
DisablePrompt: util.BoolPtr(true),
},
},
ContextConfigs: []*config.ContextConfig{},
},
expectedUnsetCfg: &config.GlobalConfig{
Global: &config.ContextConfig{Survey: &config.SurveyConfig{}},
ContextConfigs: []*config.ContextConfig{},
},
},
{
description: "set global survey disable prompt false",
key: "disable-prompt",
value: "false",
global: true,
survey: true,
expectedSetCfg: &config.GlobalConfig{
Global: &config.ContextConfig{
Survey: &config.SurveyConfig{
DisablePrompt: util.BoolPtr(false),
},
},
ContextConfigs: []*config.ContextConfig{},
},
expectedUnsetCfg: &config.GlobalConfig{
Global: &config.ContextConfig{
Survey: &config.SurveyConfig{},
},
ContextConfigs: []*config.ContextConfig{},
},
},
{
description: "set survey disable prompt",
key: "disable-prompt",
value: "false",
kubecontext: "this_is_a_context",
survey: true,
expectedSetCfg: &config.GlobalConfig{
ContextConfigs: []*config.ContextConfig{
{
Kubecontext: "this_is_a_context",
Survey: &config.SurveyConfig{
DisablePrompt: util.BoolPtr(false),
},
},
},
},
expectedUnsetCfg: &config.GlobalConfig{
ContextConfigs: []*config.ContextConfig{
{
Kubecontext: "this_is_a_context",
Survey: &config.SurveyConfig{},
},
},
},
},
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
Expand All @@ -169,6 +235,7 @@ func TestSetAndUnsetConfig(t *testing.T) {
t.Override(&config.ReadConfigFile, config.ReadConfigFileNoCache)
t.Override(&configFile, cfg)
t.Override(&global, test.global)
t.Override(&survey, test.survey)
if test.kubecontext != "" {
t.Override(&kubecontext, test.kubecontext)
} else {
Expand Down Expand Up @@ -196,3 +263,33 @@ func TestSetAndUnsetConfig(t *testing.T) {
})
}
}

func TestGetConfigStructWithIndex(t *testing.T) {
tests := []struct {
description string
cfg *config.ContextConfig
expectedIdx []int
survey bool
shouldErr bool
}{
{
description: "survey flag set",
cfg: &config.ContextConfig{},
survey: true,
expectedIdx: []int{5},
},
{
description: "no survey flag set",
cfg: &config.ContextConfig{},
expectedIdx: []int{},
},
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
t.Override(&survey, test.survey)
actual, err := getConfigStructWithIndex(test.cfg)
t.CheckError(test.shouldErr, err)
t.CheckDeepEqual(test.expectedIdx, actual.idx)
})
}
}