diff --git a/CHANGELOG.md b/CHANGELOG.md index 29532ad..0d0f92f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- [#215](https://github.com/deviceinsight/kafkactl/pull/215) Add `--context` option to set command's context ## 5.3.0 - 2024-08-14 ### Added diff --git a/cmd/config/useContext.go b/cmd/config/useContext.go index 887bbaf..c524100 100644 --- a/cmd/config/useContext.go +++ b/cmd/config/useContext.go @@ -1,10 +1,7 @@ package config import ( - "sort" - "github.com/deviceinsight/kafkactl/v5/internal/global" - "github.com/deviceinsight/kafkactl/v5/internal/output" "github.com/pkg/errors" @@ -42,15 +39,7 @@ func newUseContextCmd() *cobra.Command { return nil, cobra.ShellCompDirectiveNoFileComp } - contextMap := viper.GetStringMap("contexts") - contexts := make([]string, 0, len(contextMap)) - for k := range contextMap { - contexts = append(contexts, k) - } - - sort.Strings(contexts) - - return contexts, cobra.ShellCompDirectiveNoFileComp + return global.ListAvailableContexts(), cobra.ShellCompDirectiveNoFileComp }, } diff --git a/cmd/root.go b/cmd/root.go index 15c402c..5d23cba 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -54,6 +54,14 @@ func NewKafkactlCommand(streams output.IOStreams) *cobra.Command { rootCmd.PersistentFlags().StringVarP(&globalFlags.ConfigFile, "config-file", "C", "", fmt.Sprintf("config file. default locations: %v", globalConfig.DefaultPaths())) rootCmd.PersistentFlags().BoolVarP(&globalFlags.Verbose, "verbose", "V", false, "verbose output") + rootCmd.PersistentFlags().StringVar(&globalFlags.Context, "context", "", "The name of the context to use") + + err := rootCmd.RegisterFlagCompletionFunc("context", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { + return global.ListAvailableContexts(), cobra.ShellCompDirectiveNoFileComp + }) + if err != nil { + panic(err) + } k8s.KafkaCtlVersion = Version diff --git a/cmd/root_test.go b/cmd/root_test.go index 47cf35c..aa5c310 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -3,8 +3,11 @@ package cmd_test import ( "fmt" "os" + "strings" "testing" + "github.com/deviceinsight/kafkactl/v5/internal/output" + "github.com/deviceinsight/kafkactl/v5/internal/global" "github.com/deviceinsight/kafkactl/v5/internal/testutil" @@ -125,3 +128,53 @@ func TestEnvironmentVariableLoadingAliases(t *testing.T) { testutil.AssertEquals(t, "WaitForAll", viper.GetString("contexts.default.producer.requiredAcks")) testutil.AssertEquals(t, "1234", viper.GetString("contexts.default.producer.maxMessageBytes")) } + +func TestContextFlag(t *testing.T) { + + testutil.StartUnitTest(t) + + kafkaCtl := testutil.CreateKafkaCtlCommand() + + if _, err := kafkaCtl.Execute("version", "--context", "sasl-user"); err != nil { + t.Fatalf("failed to execute command: %v", err) + } + + testutil.AssertEquals(t, "sasl-user", global.GetCurrentContext()) +} + +func TestContextFlagProvidesUnknownContext(t *testing.T) { + + testutil.StartUnitTest(t) + + kafkaCtl := testutil.CreateKafkaCtlCommand() + + if _, err := kafkaCtl.Execute("version", "--context", "unknown-context"); err != nil { + t.Fatalf("failed to execute command: %v", err) + } + + var failError error + + output.Fail = func(err error) { + failError = err + } + + global.GetCurrentContext() + + testutil.AssertErrorContains(t, "not a valid context: unknown-context", failError) +} + +func TestContextFlagAutoCompletion(t *testing.T) { + + testutil.StartUnitTest(t) + + kafkaCtl := testutil.CreateKafkaCtlCommand() + kafkaCtl.Verbose = false + + if _, err := kafkaCtl.Execute("__complete", "--context", ""); err != nil { + t.Fatalf("failed to execute command: %v", err) + } + + outputLines := strings.Split(strings.TrimSpace(kafkaCtl.GetStdOut()), "\n") + + testutil.AssertArraysEquals(t, []string{"default", "k8s-mock", "no-avro", "sasl-admin", "sasl-user"}, outputLines[:len(outputLines)-1]) +} diff --git a/internal/global/config.go b/internal/global/config.go index e7f77cd..3f3270e 100644 --- a/internal/global/config.go +++ b/internal/global/config.go @@ -2,9 +2,11 @@ package global import ( "errors" + "fmt" "os" "path/filepath" "runtime" + "sort" "strings" "github.com/deviceinsight/kafkactl/v5/internal/output" @@ -13,6 +15,7 @@ import ( type Flags struct { ConfigFile string + Context string Verbose bool } @@ -51,7 +54,30 @@ func GetFlags() Flags { return configInstance.flags } +func ListAvailableContexts() []string { + + var contexts []string + for k := range viper.GetStringMap("contexts") { + contexts = append(contexts, k) + } + + sort.Strings(contexts) + return contexts +} + func GetCurrentContext() string { + var context = configInstance.Flags().Context + if context != "" { + contexts := viper.GetStringMap("contexts") + + // check if it is an existing context + if _, ok := contexts[context]; !ok { + output.Fail(fmt.Errorf("not a valid context: %s", context)) + } + + return context + } + return configInstance.currentContext() }