diff --git a/pkg/cli/command.go b/pkg/cli/command.go index 7017fe4..9cb9d1f 100644 --- a/pkg/cli/command.go +++ b/pkg/cli/command.go @@ -186,6 +186,19 @@ func StringArrayFlag(cmd *Command, ptr *[]string, name, short string, def []stri } } +// StringToStringFlag adds a string-to-string map flag to a command. +// The value will be stored in the provided pointer. +// +// var labels map[string]string +// cli.StringToStringFlag(cmd, &labels, "label", "l", nil, "Labels to apply") +func StringToStringFlag(cmd *Command, ptr *map[string]string, name, short string, def map[string]string, usage string) { + if short != "" { + cmd.Flags().StringToStringVarP(ptr, name, short, def, usage) + } else { + cmd.Flags().StringToStringVar(ptr, name, def, usage) + } +} + // ───────────────────────────────────────────────────────────────────────────── // Persistent Flag Helpers // ───────────────────────────────────────────────────────────────────────────── @@ -262,6 +275,15 @@ func PersistentStringArrayFlag(cmd *Command, ptr *[]string, name, short string, } } +// PersistentStringToStringFlag adds a persistent string-to-string map flag (inherited by subcommands). +func PersistentStringToStringFlag(cmd *Command, ptr *map[string]string, name, short string, def map[string]string, usage string) { + if short != "" { + cmd.PersistentFlags().StringToStringVarP(ptr, name, short, def, usage) + } else { + cmd.PersistentFlags().StringToStringVar(ptr, name, def, usage) + } +} + // ───────────────────────────────────────────────────────────────────────────── // Command Configuration // ───────────────────────────────────────────────────────────────────────────── diff --git a/pkg/cli/command_test.go b/pkg/cli/command_test.go index 5f12665..6767623 100644 --- a/pkg/cli/command_test.go +++ b/pkg/cli/command_test.go @@ -14,13 +14,14 @@ func TestPersistentFlagHelpers_Good(t *testing.T) { parent := NewGroup("parent", "Parent", "") var ( - str string - b bool - i int - i64 int64 - f64 float64 - dur time.Duration - slice []string + str string + b bool + i int + i64 int64 + f64 float64 + dur time.Duration + slice []string + labels map[string]string ) PersistentStringFlag(parent, &str, "name", "n", "default", "Name") @@ -30,6 +31,7 @@ func TestPersistentFlagHelpers_Good(t *testing.T) { PersistentFloat64Flag(parent, &f64, "ratio", "", 3.5, "Ratio") PersistentDurationFlag(parent, &dur, "timeout", "t", 4*time.Second, "Timeout") PersistentStringSliceFlag(parent, &slice, "tag", "", nil, "Tags") + PersistentStringToStringFlag(parent, &labels, "label", "l", nil, "Labels") child := NewCommand("child", "Child", "", func(_ *Command, _ []string) error { assert.Equal(t, "override", str) @@ -39,6 +41,7 @@ func TestPersistentFlagHelpers_Good(t *testing.T) { assert.InDelta(t, 7.25, f64, 1e-9) assert.Equal(t, 15*time.Second, dur) assert.Equal(t, []string{"alpha", "beta"}, slice) + assert.Equal(t, map[string]string{"env": "prod", "team": "platform"}, labels) return nil }) parent.AddCommand(child) @@ -53,6 +56,7 @@ func TestPersistentFlagHelpers_Good(t *testing.T) { "--timeout", "15s", "--tag", "alpha", "--tag", "beta", + "--label", "env=prod,team=platform", }) require.NoError(t, parent.Execute()) @@ -122,4 +126,33 @@ func TestFlagHelpers_Good(t *testing.T) { require.NoError(t, cmd.Execute()) assert.Equal(t, []string{"alpha"}, tags) }) + + t.Run("string-to-string flags parse key value pairs", func(t *testing.T) { + cmd := NewCommand("child", "Child", "", func(_ *Command, _ []string) error { + return nil + }) + + var labels map[string]string + StringToStringFlag(cmd, &labels, "label", "l", nil, "Labels") + cmd.SetArgs([]string{"--label", "env=prod,team=platform"}) + + require.NoError(t, cmd.Execute()) + assert.Equal(t, map[string]string{"env": "prod", "team": "platform"}, labels) + }) + + t.Run("persistent string-to-string flags inherit through subcommands", func(t *testing.T) { + parent := NewGroup("parent", "Parent", "") + + var labels map[string]string + PersistentStringToStringFlag(parent, &labels, "label", "l", nil, "Labels") + + child := NewCommand("child", "Child", "", func(_ *Command, _ []string) error { + assert.Equal(t, map[string]string{"env": "prod", "team": "platform"}, labels) + return nil + }) + parent.AddCommand(child) + parent.SetArgs([]string{"child", "-l", "env=prod,team=platform"}) + + require.NoError(t, parent.Execute()) + }) }