Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kubectl-switch for openSUSE:Factory checked in at 2025-10-13 15:35:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kubectl-switch (Old) and /work/SRC/openSUSE:Factory/.kubectl-switch.new.18484 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kubectl-switch" Mon Oct 13 15:35:40 2025 rev:8 rq:1311029 version:2.3.0 Changes: -------- --- /work/SRC/openSUSE:Factory/kubectl-switch/kubectl-switch.changes 2025-09-15 19:55:43.486202649 +0200 +++ /work/SRC/openSUSE:Factory/.kubectl-switch.new.18484/kubectl-switch.changes 2025-10-13 15:37:00.873448887 +0200 @@ -1,0 +2,70 @@ +Mon Oct 13 06:53:03 UTC 2025 - Johannes Kastl <[email protected]> + +- Update to version 2.3.0: + * New Features + - use viper for configuration management (#213) (c173c57) + * Documentation + - update defaults in config section (1339ef9) + * CI/CD + - add PR metadata workflow for title validation and labeling + (034c01b) + - merge all lint jobs in a single workflow (5480be7) + - remove label-sync (da92db2) + +------------------------------------------------------------------- +Mon Oct 13 06:44:34 UTC 2025 - Johannes Kastl <[email protected]> + +- Update to version 2.2.17: + * Bug Fixes + - remove file extension check. we assume all files in the + kubeconfig_dir are kubeconfigs (3b56de5) + * CI/CD + - github-action: Update github/codeql-action ( v3.30.7 → + v4.30.7 ) (#210) (ab77e20) + - github-action: update renovatebot/github-action ( v43.0.15 → + v43.0.16 ) (7d54339) + - github-action: update github/codeql-action ( v3.30.6 → + v3.30.7 ) (75fe234) + - github-action: update jdx/mise-action ( v3.3.0 → v3.3.1 ) + (c951441) + - github-action: update renovatebot/github-action ( v43.0.14 → + v43.0.15 ) (66731bc) + - github-action: update jdx/mise-action ( v3.2.0 → v3.3.0 ) + (9ee7740) + - github-action: update github/codeql-action ( v3.30.5 → + v3.30.6 ) (c678380) + - github-action: update docker/login-action ( v3.5.0 → v3.6.0 ) + (b78b245) + - github-action: update renovatebot/github-action ( v43.0.13 → + v43.0.14 ) (26acafa) + - github-action: update github/codeql-action ( v3.30.4 → + v3.30.5 ) (d9c5ef5) + - github-action: update github/codeql-action ( v3.30.3 → + v3.30.4 ) (a457268) + - github-action: update renovatebot/github-action ( v43.0.12 → + v43.0.13 ) (568adf2) + - github-action: update renovatebot/github-action ( v43.0.11 → + v43.0.12 ) (b09e93d) + - github-action: update actions/create-github-app-token ( + v2.1.2 → v2.1.4 ) (2d27a35) + - github-action: update actions/create-github-app-token ( + v2.1.1 → v2.1.2 ) (f31c63a) + * Chores + - cleanup spaghetti (#211) (e6e647e) + - mise: update go ( 1.25.1 → 1.25.2 ) (41bdb64) + - mise: update aqua:goreleaser/goreleaser ( 2.12.4 → 2.12.5 ) + (ba65d9e) + - mise: update aqua:goreleaser/goreleaser ( 2.12.3 → 2.12.4 ) + (471f138) + - mise: Update npm:@commitlint/cli ( 19.8.1 → 20.0.0 ) (#209) + (48acdbe) + - mise: update aqua:goreleaser/goreleaser ( 2.12.2 → 2.12.3 ) + (4954cf9) + - mise: update aqua:golangci/golangci-lint ( 2.4.0 → 2.5.0 ) + (350b550) + - mise: update aqua:goreleaser/goreleaser ( 2.12.1 → 2.12.2 ) + (0e46b49) + - mise: update aqua:goreleaser/goreleaser ( 2.12.0 → 2.12.1 ) + (8ed7db6) + +------------------------------------------------------------------- Old: ---- kubectl-switch-2.2.16.obscpio New: ---- kubectl-switch-2.3.0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kubectl-switch.spec ++++++ --- /var/tmp/diff_new_pack.JWGj7P/_old 2025-10-13 15:37:01.625480497 +0200 +++ /var/tmp/diff_new_pack.JWGj7P/_new 2025-10-13 15:37:01.641481169 +0200 @@ -17,7 +17,7 @@ Name: kubectl-switch -Version: 2.2.16 +Version: 2.3.0 Release: 0 Summary: Simple tool to help manage multiple kubeconfig files License: MIT @@ -84,6 +84,8 @@ # Install the binary. install -D -m 0755 %{name} %{buildroot}/%{_bindir}/%{name} +mkdir -p /home/abuild/.kube/configs + # create the bash completion file mkdir -p %{buildroot}%{_datarootdir}/bash-completion/completions/ %{buildroot}/%{_bindir}/%{name} completion bash > %{buildroot}%{_datarootdir}/bash-completion/completions/%{name} ++++++ _service ++++++ --- /var/tmp/diff_new_pack.JWGj7P/_old 2025-10-13 15:37:02.021497142 +0200 +++ /var/tmp/diff_new_pack.JWGj7P/_new 2025-10-13 15:37:02.085499833 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/mirceanton/kubectl-switch</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v2.2.16</param> + <param name="revision">v2.3.0</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.JWGj7P/_old 2025-10-13 15:37:02.489516815 +0200 +++ /var/tmp/diff_new_pack.JWGj7P/_new 2025-10-13 15:37:02.529518496 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/mirceanton/kubectl-switch</param> - <param name="changesrevision">6bb6ac390fbf54d2f17de8dea1de44928fe632bf</param></service></servicedata> + <param name="changesrevision">1339ef9aaa2e74313d2f67988d4ac6ec08de852a</param></service></servicedata> (No newline at EOF) ++++++ kubectl-switch-2.2.16.obscpio -> kubectl-switch-2.3.0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/.envrc new/kubectl-switch-2.3.0/.envrc --- old/kubectl-switch-2.2.16/.envrc 1970-01-01 01:00:00.000000000 +0100 +++ new/kubectl-switch-2.3.0/.envrc 2025-10-13 00:17:55.000000000 +0200 @@ -0,0 +1,4 @@ +export KUBECONFIG_DIR="./test/configs/" +export KUBECONFIG="./test/config" +export LOG_LEVEL="error" +export LOG_FORMAT="text" \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/.mise.toml new/kubectl-switch-2.3.0/.mise.toml --- old/kubectl-switch-2.2.16/.mise.toml 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/.mise.toml 2025-10-13 00:17:55.000000000 +0200 @@ -2,9 +2,9 @@ # ================================================================================================= # Project Tools -> pinned versions # ================================================================================================= -go = "1.25.1" -"aqua:golangci/golangci-lint" = "2.4.0" -"aqua:goreleaser/goreleaser" = "2.12.0" +go = "1.25.2" +"aqua:golangci/golangci-lint" = "2.5.0" +"aqua:goreleaser/goreleaser" = "2.12.5" "aqua:kubernetes/kubectl" = "1.33.1" @@ -14,10 +14,27 @@ "aqua:kubernetes/minikube" = "latest" "aqua:helm/helm" = "latest" "aqua:derailed/k9s" = "latest" +direnv = "latest" # ================================================================================================= # CI Tools # ================================================================================================= -"npm:@commitlint/cli" = "19" +"npm:@commitlint/cli" = "20" "aqua:rhysd/actionlint" = "1" +"shellcheck" = "0.11" + +# ================================================================================================= +# TASKS -> GO +# ================================================================================================= +[tasks."release"] +description = "Run goreleaser in snapshot mode." +run = "goreleaser release --snapshot --clean" + +[tasks."lint"] +description = "Run golangci-lint in fix mode." +run = "golangci-lint run --fix" + +[tasks."test"] +description = "Run e2e tests." +run = "bash scripts/test.sh" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/README.md new/kubectl-switch-2.3.0/README.md --- old/kubectl-switch-2.2.16/README.md 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/README.md 2025-10-13 00:17:55.000000000 +0200 @@ -6,15 +6,9 @@ ## Features -- **Multiple kubeconfig files**: Manage multiple kubeconfig files with one or more contexts each, all present in a single directory. You don't have to generate a global kubeconfig to hold all of your contexts -- **Context Switching**: Easily switch between different Kubernetes contexts from multiple config files. -- **Namespace Switching**: Quickly change the current namespace in the active context. -- **Previous Config**: Switch back to the previous configuration with `kubectl switch -`. -- **Non-Interactive Mode**: Specify the desired context or namespace directly as an argument. -- **Interactive Mode**: Run the program with no arguments to get an interactive list of available namespaces or contexts to choose from. -- **Persistent Configuration**: Changes persist across different shell sessions. -- **Shell Completions**: Provides tab completion for available contexts and namespaces. -- **Non-destructive**: `kubectl-switch` will never edit those. It will only work with copies of them. +- **Multiple kubeconfig files**: Manage multiple kubeconfig files in a single directory without merging them +- **Context & namespace switching**: Switch between contexts and namespaces from multiple config files +- **Interactive & non-interactive modes**: Select from a list or specify directly as an argument (with tab completion support!) ## Why `kubectl-switch`? @@ -48,29 +42,29 @@ 1. Download the appropriate binary for your system and extract the archive. 2. Make the extracted binary executable: - ```bash - chmod +x kubectl-switch - ``` + ```bash + chmod +x kubectl-switch + ``` 3. Move the binary to a directory in your PATH: - ```bash - mv kubectl-switch /usr/local/bin/kubectl-switch - ``` + ```bash + mv kubectl-switch /usr/local/bin/kubectl-switch + ``` ### Install via Homebrew 1. Add the tap - ```bash - brew tap mirceanton/taps - ``` + ```bash + brew tap mirceanton/taps + ``` 2. Install `kubectl-switch` - ```bash - brew install kubectl-switch - ``` + ```bash + brew install kubectl-switch + ``` ### Running via Docker @@ -92,22 +86,22 @@ 1. Clone the repository: - ```bash - git clone https://github.com/mirceanton/kubectl-switch - cd kubectl-switch - ``` + ```bash + git clone https://github.com/mirceanton/kubectl-switch + cd kubectl-switch + ``` 2. Build the tool: - ```bash - go build -o kubectl-switch - ``` + ```bash + go build -o kubectl-switch + ``` 3. Move the binary to your PATH: - ```bash - mv kubectl-switch /usr/local/bin/kubectl-switch - ``` + ```bash + mv kubectl-switch /usr/local/bin/kubectl-switch + ``` ## Usage @@ -155,12 +149,16 @@ ## Configuration -You can configure `kubectl-switch` using environment variables or CLI flags: +`kubectl-switch` uses Viper for configuration management, allowing you to configure the tool via command-line flags or environment variables, with flags taking precedence. -| Environment Variable | CLI Flag | Description | Default Value | -| :--------------------: | :---------------: | :----------------------------------------------: | :--------------------------: | -| `KUBECONFIG_DIR` | `--kubeconfig-dir` | Directory containing your kubeconfig files. | None | -| `KUBECONFIG` | N/A | Path where the active kubeconfig will be stored. | `~/.kube/config` | +### Configuration Options + +| Option | Flag | Environment Variable | Default | Description | +| -------------------- | ------------------ | -------------------- | ------------------ | ----------------------------------------------------------------- | +| Kubeconfig Directory | `--kubeconfig-dir` | `KUBECONFIG_DIR` | `~/.kube/configs/` | Directory containing your kubeconfig files | +| Kubeconfig | `--kubeconfig` | `KUBECONFIG` | `~/.kube/config` | Path to the currently active kubeconfig file. | +| Log Level | `--log-level` | `LOG_LEVEL` | `info` | Logging verbosity (trace, debug, info, warn, error, fatal, panic) | +| Log Format | `--log-format` | `LOG_FORMAT` | `text` | Log output format (text, json) | ## Shell Completion diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/cmd/context.go new/kubectl-switch-2.3.0/cmd/context.go --- old/kubectl-switch-2.2.16/cmd/context.go 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/cmd/context.go 2025-10-13 00:17:55.000000000 +0200 @@ -2,13 +2,10 @@ import ( "github.com/AlecAivazis/survey/v2" - "github.com/mirceanton/kubectl-switch/v2/pkg/kubeconfig" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) -var contextManager = kubeconfig.NewContextManager(manager) - var contextCmd = &cobra.Command{ Use: "context", Aliases: []string{"ctx"}, @@ -16,42 +13,25 @@ ValidArgsFunction: getContextCompletions, Args: cobra.MaximumNArgs(1), Run: func(cmd *cobra.Command, args []string) { - // Validate and get the config directory - validConfigDir, err := contextManager.ValidateConfigDir(configDir) - if err != nil { - log.Fatal(err) - } - - // Get all contexts from kubeconfig files - contextMap, contextNames, err := contextManager.GetContextsFromDir(validConfigDir) - if err != nil { - log.Fatalf("Failed to read kubeconfig files: %v", err) + contextNames := configManager.GetAllContexts() + if len(contextNames) == 0 { + log.Fatal("No kubernetes contexts found in the provided directory") } - if len(contextMap) == 0 { - log.Fatal("No kubernetes contexts found in the provided directory: ", validConfigDir) - } - - // Determine the target context var selectedContext string if len(args) == 1 { selectedContext = args[0] - if _, exists := contextMap[selectedContext]; !exists { - log.Fatalf("Context '%s' not found", selectedContext) - } } else { prompt := &survey.Select{ Message: "Choose a context:", Options: contextNames, } - err = survey.AskOne(prompt, &selectedContext) - if err != nil { + if err := survey.AskOne(prompt, &selectedContext); err != nil { log.Fatalf("Failed to get user input: %v", err) } } - // Switch to the selected context - if err := contextManager.SwitchContext(contextMap[selectedContext], selectedContext); err != nil { + if err := configManager.SwitchToContext(selectedContext); err != nil { log.Fatalf("Failed to switch context: %v", err) } @@ -63,18 +43,6 @@ rootCmd.AddCommand(contextCmd) } -// getContextCompletions provides bash completion for available contexts func getContextCompletions(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - configDirFlag, _ := cmd.Flags().GetString("kubeconfig-dir") - validConfigDir, err := contextManager.ValidateConfigDir(configDirFlag) - if err != nil { - return nil, cobra.ShellCompDirectiveNoFileComp - } - - _, contextNames, err := contextManager.GetContextsFromDir(validConfigDir) - if err != nil { - return nil, cobra.ShellCompDirectiveNoFileComp - } - - return contextNames, cobra.ShellCompDirectiveNoFileComp + return configManager.GetAllContexts(), cobra.ShellCompDirectiveNoFileComp } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/cmd/namespace.go new/kubectl-switch-2.3.0/cmd/namespace.go --- old/kubectl-switch-2.2.16/cmd/namespace.go 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/cmd/namespace.go 2025-10-13 00:17:55.000000000 +0200 @@ -2,13 +2,10 @@ import ( "github.com/AlecAivazis/survey/v2" - "github.com/mirceanton/kubectl-switch/v2/pkg/kubeconfig" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) -var namespaceManager = kubeconfig.NewNamespaceManager(manager) - var namespaceCmd = &cobra.Command{ Use: "namespace", Aliases: []string{"ns"}, @@ -16,13 +13,11 @@ Args: cobra.MaximumNArgs(1), ValidArgsFunction: getNamespaceCompletions, Run: func(cmd *cobra.Command, args []string) { - // Get all namespaces from the current context - namespaceNames, err := namespaceManager.GetNamespaces() - if err != nil { - log.Fatalf("Error listing namespaces: %v", err) + namespaceNames := configManager.GetAllNamespaces() + if len(namespaceNames) == 0 { + log.Fatal("No kubernetes namespaces found in the current cluster") } - // Determine the target namespace var selectedNamespace string if len(args) == 1 { selectedNamespace = args[0] @@ -31,14 +26,12 @@ Message: "Choose a namespace:", Options: namespaceNames, } - err = survey.AskOne(prompt, &selectedNamespace) - if err != nil { + if err := survey.AskOne(prompt, &selectedNamespace); err != nil { log.Fatalf("Failed to get user input: %v", err) } } - // Switch to the selected namespace - if err := namespaceManager.SwitchNamespace(selectedNamespace); err != nil { + if err := configManager.SwitchToNamespace(selectedNamespace); err != nil { log.Fatalf("Failed to switch namespace: %v", err) } @@ -50,12 +43,6 @@ rootCmd.AddCommand(namespaceCmd) } -// getNamespaceCompletions provides bash completion for available namespaces func getNamespaceCompletions(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - namespaceNames, err := namespaceManager.GetNamespaces() - if err != nil { - return nil, cobra.ShellCompDirectiveNoFileComp - } - - return namespaceNames, cobra.ShellCompDirectiveNoFileComp + return configManager.GetAllNamespaces(), cobra.ShellCompDirectiveNoFileComp } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/cmd/root.go new/kubectl-switch-2.3.0/cmd/root.go --- old/kubectl-switch-2.2.16/cmd/root.go 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/cmd/root.go 2025-10-13 00:17:55.000000000 +0200 @@ -3,15 +3,16 @@ import ( "os" - "github.com/mirceanton/kubectl-switch/v2/pkg/kubeconfig" + "github.com/mirceanton/kubectl-switch/v2/internal/config" + "github.com/mirceanton/kubectl-switch/v2/internal/manager" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/spf13/viper" ) var ( - configDir string // Global flag for the kubeconfig directory - version string // The version of the tool, set at build time - manager = kubeconfig.NewManager() + version string + configManager *manager.Manager ) var rootCmd = &cobra.Command{ @@ -22,15 +23,28 @@ Short: "A tool to switch Kubernetes contexts", Long: `kubectl-switch is a CLI tool to switch Kubernetes contexts from multiple kubeconfig files.`, Version: version, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + // Load configuration + cfg, err := config.Load() + if err != nil { + return err + } + + // Set up logging + log.SetLevel(cfg.LogLevel) + log.SetFormatter(cfg.LogFormat) + + // Create manager with config + configManager, err = manager.NewManager(cfg.Kubeconfig, cfg.KubeconfigDir) + if err != nil { + return err + } + return nil + }, RunE: func(cmd *cobra.Command, args []string) error { - // Check if the "-" argument is provided to switch to the previous config if len(args) == 1 && args[0] == "-" { - if err := manager.SwitchToPrevious(); err != nil { - if err == kubeconfig.ErrNoPreviousConfig { - log.Fatal("No previous configuration found") - } else { - log.Fatalf("Failed to switch to previous config: %v", err) - } + if err := configManager.Restore(); err != nil { + log.Fatalf("Failed to switch to previous config: %v", err) } return nil } @@ -39,12 +53,37 @@ } func Execute() { - err := rootCmd.Execute() - if err != nil { + if err := rootCmd.Execute(); err != nil { os.Exit(1) } } func init() { - rootCmd.PersistentFlags().StringVarP(&configDir, "kubeconfig-dir", "", "", "Directory containing kubeconfig files") + // Initialize Viper + cobra.OnInitialize(config.Init) + + // Bind flags to Viper + rootCmd.PersistentFlags().String("kubeconfig-dir", "", "Directory containing kubeconfig files (env: KUBECONFIG_DIR)") + err := viper.BindPFlag("kubeconfig-dir", rootCmd.PersistentFlags().Lookup("kubeconfig-dir")) + if err != nil { + log.Fatalf("Failed to bind flag: %v", err) + } + + rootCmd.PersistentFlags().String("kubeconfig", "", "Currently active kubeconfig file (env: KUBECONFIG)") + err = viper.BindPFlag("kubeconfig", rootCmd.PersistentFlags().Lookup("kubeconfig")) + if err != nil { + log.Fatalf("Failed to bind flag: %v", err) + } + + rootCmd.PersistentFlags().String("log-level", "info", "Log level (trace, debug, info, warn, error, fatal, panic) (env: LOG_LEVEL)") + err = viper.BindPFlag("log-level", rootCmd.PersistentFlags().Lookup("log-level")) + if err != nil { + log.Fatalf("Failed to bind flag: %v", err) + } + + rootCmd.PersistentFlags().String("log-format", "text", "Log format (text, json) (env: LOG_FORMAT)") + err = viper.BindPFlag("log-format", rootCmd.PersistentFlags().Lookup("log-format")) + if err != nil { + log.Fatalf("Failed to bind flag: %v", err) + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/go.mod new/kubectl-switch-2.3.0/go.mod --- old/kubectl-switch-2.2.16/go.mod 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/go.mod 2025-10-13 00:17:55.000000000 +0200 @@ -9,6 +9,7 @@ github.com/AlecAivazis/survey/v2 v2.3.7 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.10.1 + github.com/spf13/viper v1.21.0 k8s.io/apimachinery v0.34.1 k8s.io/client-go v0.34.1 ) @@ -16,14 +17,15 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic-models v0.7.0 // indirect - github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -36,8 +38,14 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/spf13/pflag v1.0.9 // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect @@ -45,7 +53,7 @@ golang.org/x/oauth2 v0.27.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/text v0.28.0 // indirect golang.org/x/time v0.9.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect @@ -57,7 +65,6 @@ k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/go.sum new/kubectl-switch-2.3.0/go.sum --- old/kubectl-switch-2.2.16/go.sum 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/go.sum 2025-10-13 00:17:55.000000000 +0200 @@ -10,12 +10,12 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= @@ -30,13 +30,12 @@ github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= -github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -78,7 +77,6 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= @@ -88,6 +86,8 @@ github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -95,20 +95,23 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/cobra v1.10.0 h1:a5/WeUlSDCvV5a45ljW2ZFtV0bTDpkfSAj3uqB6Sc+0= -github.com/spf13/cobra v1.10.0/go.mod h1:9dhySC7dnTtEiqzmqfkLj47BslqLCUPMXjG2lj/NgoE= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.8 h1:/v546uKZ4gFGHpyXvV6CNKDeJBu4l5PRvxwQvdWrc0I= -github.com/spf13/pflag v1.0.8/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -120,8 +123,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -173,8 +178,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -182,8 +187,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -200,64 +205,23 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw= -k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw= -k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY= -k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs= -k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= -k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= -k8s.io/api v0.33.4 h1:oTzrFVNPXBjMu0IlpA2eDDIU49jsuEorGHB4cvKupkk= -k8s.io/api v0.33.4/go.mod h1:VHQZ4cuxQ9sCUMESJV5+Fe8bGnqAARZ08tSTdHWfeAc= -k8s.io/api v0.34.0 h1:L+JtP2wDbEYPUeNGbeSa/5GwFtIA662EmT2YSLOkAVE= -k8s.io/api v0.34.0/go.mod h1:YzgkIzOOlhl9uwWCZNqpw6RJy9L2FK4dlJeayUoydug= k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM= k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk= -k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4= -k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY= -k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= -k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/apimachinery v0.33.4 h1:SOf/JW33TP0eppJMkIgQ+L6atlDiP/090oaX0y9pd9s= -k8s.io/apimachinery v0.33.4/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/apimachinery v0.34.0 h1:eR1WO5fo0HyoQZt1wdISpFDffnWOvFLOOeJ7MgIv4z0= -k8s.io/apimachinery v0.34.0/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4= k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4= -k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA= -k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E= -k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo= -k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA= -k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg= -k8s.io/client-go v0.33.4 h1:TNH+CSu8EmXfitntjUPwaKVPN0AYMbc9F1bBS8/ABpw= -k8s.io/client-go v0.33.4/go.mod h1:LsA0+hBG2DPwovjd931L/AoaezMPX9CmBgyVyBZmbCY= -k8s.io/client-go v0.34.0 h1:YoWv5r7bsBfb0Hs2jh8SOvFbKzzxyNo0nSb0zC19KZo= -k8s.io/client-go v0.34.0/go.mod h1:ozgMnEKXkRjeMvBZdV1AijMHLTh3pbACPvK7zFR+QQY= k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= -k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA= k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= -sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/internal/config/config.go new/kubectl-switch-2.3.0/internal/config/config.go --- old/kubectl-switch-2.2.16/internal/config/config.go 1970-01-01 01:00:00.000000000 +0100 +++ new/kubectl-switch-2.3.0/internal/config/config.go 2025-10-13 00:17:55.000000000 +0200 @@ -0,0 +1,146 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + + "github.com/spf13/viper" +) + +// Config holds all configuration for the application +type Config struct { + KubeconfigDir string + Kubeconfig string + LogLevel log.Level + LogFormat log.Formatter +} + +const ( + // Configuration keys + keyKubeconfigDir = "kubeconfig-dir" + keyKubeconfig = "kubeconfig" + keyLogLevel = "log-level" + keyLogFormat = "log-format" + + // Default values + defaultLogLevel = "info" + defaultLogFormat = "text" +) + +var ( + defaultKubeconfigDir = filepath.Join(os.Getenv("HOME"), ".kube", "configs/") + defaultKubeconfig = filepath.Join(os.Getenv("HOME"), ".kube", "config") +) + +// Init initializes Viper configuration +func Init() { + // Enable reading from environment variables + viper.AutomaticEnv() + + // Replace hyphens with underscores in env vars + // This allows --kubeconfig-dir to map to KUBECONFIG_DIR + viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + + // Set default values + viper.SetDefault(keyKubeconfigDir, defaultKubeconfigDir) + viper.SetDefault(keyKubeconfig, defaultKubeconfig) + viper.SetDefault(keyLogLevel, defaultLogLevel) + viper.SetDefault(keyLogFormat, defaultLogFormat) +} + +// Load returns the current configuration +func Load() (*Config, error) { + cfg := &Config{} + + // Parse log level + levelStr := viper.GetString(keyLogLevel) + level, err := log.ParseLevel(levelStr) + if err != nil { + return nil, fmt.Errorf("invalid log level: %s", levelStr) + } + cfg.LogLevel = level + + // Parse log format + formatStr := viper.GetString(keyLogFormat) + switch strings.ToLower(formatStr) { + case "json": + cfg.LogFormat = &log.JSONFormatter{} + case "text": + cfg.LogFormat = &log.TextFormatter{FullTimestamp: true} + default: + return nil, fmt.Errorf("invalid log format: %s", formatStr) + } + + // Expand and validate kubeconfig dir path + cfg.KubeconfigDir, err = expandPath(viper.GetString(keyKubeconfigDir)) + if err != nil { + return nil, fmt.Errorf("failed to expand kubeconfig directory path: %w", err) + } + if err := cfg.validateKubeconfigDir(); err != nil { + return nil, err + } + + // Expand and validate kubeconfig dir path + cfg.Kubeconfig, err = expandPath(viper.GetString(keyKubeconfig)) + if err != nil { + return nil, fmt.Errorf("failed to expand kubeconfig path: %w", err) + } + if err := cfg.validateKubeconfig(); err != nil { + log.Warnf("Kubeconfig file validation failed: %v", err) + log.Warn("You can still switch contexts, but namespace operations will not be available") + } + + return cfg, nil +} + +// validateKubeconfigDir validates that the kubeconfig directory exists and is a directory +func (c *Config) validateKubeconfigDir() error { + info, err := os.Stat(c.KubeconfigDir) + if err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("kubeconfig directory does not exist: %s", c.KubeconfigDir) + } + return fmt.Errorf("failed to stat kubeconfig directory: %w", err) + } + + if !info.IsDir() { + return fmt.Errorf("kubeconfig directory path is not a directory: %s", c.KubeconfigDir) + } + + return nil +} + +// validateKubeconfig validates that the kubeconfig file exists and is a file +func (c *Config) validateKubeconfig() error { + info, err := os.Stat(c.Kubeconfig) + if err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("kubeconfig file does not exist: %s", c.Kubeconfig) + } + return fmt.Errorf("failed to stat kubeconfig file: %w", err) + } + + if info.IsDir() { + return fmt.Errorf("kubeconfig path is a directory, expected a file: %s", c.Kubeconfig) + } + + return nil +} + +// expandPath expands a path starting with ~/ to the full home directory path. +func expandPath(path string) (string, error) { + if !strings.HasPrefix(path, "~/") { + return path, nil + } + + homeDir, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("failed to get home directory: %w", err) + } + + return filepath.Join(homeDir, path[2:]), nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/internal/manager/manager.go new/kubectl-switch-2.3.0/internal/manager/manager.go --- old/kubectl-switch-2.2.16/internal/manager/manager.go 1970-01-01 01:00:00.000000000 +0100 +++ new/kubectl-switch-2.3.0/internal/manager/manager.go 2025-10-13 00:17:55.000000000 +0200 @@ -0,0 +1,216 @@ +package manager + +import ( + "context" + "fmt" + "os" + "path/filepath" + + log "github.com/sirupsen/logrus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" +) + +// Manager handles kubeconfig file operations and Kubernetes context switching. +type Manager struct { + kubeconfigPath string + backupPath string + kubeconfigDir string + contextMap map[string]string + contextNames []string + namespaceNames []string +} + +// NewManager creates a new kubeconfig Manager instance. +// It takes the validated configuration paths and loads available contexts. +func NewManager(kubeconfigPath, kubeconfigDir string) (*Manager, error) { + m := &Manager{ + kubeconfigPath: kubeconfigPath, + kubeconfigDir: kubeconfigDir, + backupPath: kubeconfigPath + ".previous", + } + + // Load available contexts from the config directory + if err := m.loadContexts(); err != nil { + return nil, fmt.Errorf("failed to load contexts: %w", err) + } + + // Load available namespaces from the current cluster + // This may fail if no kubeconfig is active, which is OK + if err := m.loadNamespaces(); err != nil { + log.Warnf("Failed to load namespaces: %v", err) + log.Warn("Namespace operations will not be available until a valid context is selected") + m.namespaceNames = []string{} // Initialize to empty slice + } + + return m, nil +} + +// GetAllContexts returns the available context names. +func (m *Manager) GetAllContexts() []string { + return m.contextNames +} + +// GetAllNamespaces retrieves all namespaces from the current Kubernetes cluster. +func (m *Manager) GetAllNamespaces() []string { + return m.namespaceNames +} + +// SwitchToContext switches to the specified Kubernetes context. +func (m *Manager) SwitchToContext(contextName string) error { + // Find the kubeconfig file containing the desired context + contextFilePath, exists := m.contextMap[contextName] + if !exists { + return fmt.Errorf("context '%s' not found", contextName) + } + + // Load the kubeconfig file containing the desired context + kubeconfig, err := clientcmd.LoadFromFile(contextFilePath) + if err != nil { + return fmt.Errorf("failed to load kubeconfig from %s: %w", contextFilePath, err) + } + + // Update the current context in the loaded kubeconfig + kubeconfig.CurrentContext = contextName + + // Backup current config + if err := m.backup(); err != nil { + log.Warnf("Failed to save current configuration as previous: %v", err) + } + + // Write updated kubeconfig back to the main kubeconfig file + if err := clientcmd.WriteToFile(*kubeconfig, m.kubeconfigPath); err != nil { + return fmt.Errorf("failed to write kubeconfig: %w", err) + } + + return nil +} + +// SwitchToNamespace switches the namespace for the current context. +func (m *Manager) SwitchToNamespace(namespace string) error { + // Parse current kubeconfig + kubeconfig, err := clientcmd.LoadFromFile(m.kubeconfigPath) + if err != nil { + return fmt.Errorf("failed to load current kubeconfig: %w", err) + } + + // Update namespace for current context + kubeconfig.Contexts[kubeconfig.CurrentContext].Namespace = namespace + + // Backup current config + if err := m.backup(); err != nil { + log.Warnf("Failed to save current configuration as previous: %v", err) + } + + // Write updated kubeconfig back to file + if err := clientcmd.WriteToFile(*kubeconfig, m.kubeconfigPath); err != nil { + return fmt.Errorf("failed to write kubeconfig: %w", err) + } + + return nil +} + +// Restore swaps the current kubeconfig with the previous backup. +func (m *Manager) Restore() error { + // Read current kubeconfig + currentConfig, err := os.ReadFile(m.kubeconfigPath) + if err != nil { + return fmt.Errorf("failed to read current config: %w", err) + } + + // Read backup kubeconfig + prevConfig, err := os.ReadFile(m.backupPath) + if err != nil { + return fmt.Errorf("failed to read previous config: %w", err) + } + + // Swap the files + if err := os.WriteFile(m.kubeconfigPath, prevConfig, 0o600); err != nil { + return fmt.Errorf("failed to write current config: %w", err) + } + if err := os.WriteFile(m.backupPath, currentConfig, 0o600); err != nil { + return fmt.Errorf("failed to write previous config: %w", err) + } + + return nil +} + +// ================================================================================================ +// Helper functions +// ================================================================================================ + +// backup backs up the current kubeconfig to config.previous. +func (m *Manager) backup() error { + data, err := os.ReadFile(m.kubeconfigPath) + if err != nil { + return fmt.Errorf("failed to read current kubeconfig: %w", err) + } + + if err := os.WriteFile(m.backupPath, data, 0o600); err != nil { + return fmt.Errorf("failed to write previous kubeconfig: %w", err) + } + + return nil +} + +// loadContexts scans the config directory for kubeconfig files and loads all available contexts. +func (m *Manager) loadContexts() error { + m.contextMap = make(map[string]string) + m.contextNames = nil + + files, err := os.ReadDir(m.kubeconfigDir) + if err != nil { + return fmt.Errorf("failed to read config directory: %w", err) + } + + for _, file := range files { + if file.IsDir() { + continue + } + + path := filepath.Join(m.kubeconfigDir, file.Name()) + kubeconfig, err := clientcmd.LoadFromFile(path) + if err != nil { + log.WithField("file", file.Name()).Warnf("Failed to parse kubeconfig file: %v", err) + continue + } + + for contextName := range kubeconfig.Contexts { + if existingPath, exists := m.contextMap[contextName]; exists { + log.Warnf("Duplicate context name '%s' found in files:\n - %s\n - %s", + contextName, existingPath, path) + continue + } + m.contextMap[contextName] = path + m.contextNames = append(m.contextNames, contextName) + } + } + + return nil +} + +// loadNamespaces loads all namespaces from the current Kubernetes cluster. +func (m *Manager) loadNamespaces() error { + config, err := clientcmd.BuildConfigFromFlags("", m.kubeconfigPath) + if err != nil { + return fmt.Errorf("failed to build config: %w", err) + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + return fmt.Errorf("failed to create clientset: %w", err) + } + + namespaces, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("failed to list namespaces: %w", err) + } + + m.namespaceNames = make([]string, 0, len(namespaces.Items)) + for _, ns := range namespaces.Items { + m.namespaceNames = append(m.namespaceNames, ns.Name) + } + + return nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/pkg/kubeconfig/context.go new/kubectl-switch-2.3.0/pkg/kubeconfig/context.go --- old/kubectl-switch-2.2.16/pkg/kubeconfig/context.go 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/pkg/kubeconfig/context.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,78 +0,0 @@ -package kubeconfig - -import ( - "os" - "path/filepath" - "strings" -) - -// ContextManager handles operations related to Kubernetes contexts -type ContextManager struct { - kubeconfigManager *Manager -} - -// NewContextManager creates a new context manager -func NewContextManager(km *Manager) *ContextManager { - return &ContextManager{ - kubeconfigManager: km, - } -} - -// GetContextsFromDir gets all contexts from kubeconfig files in a directory -func (cm *ContextManager) GetContextsFromDir(configDir string) (map[string]string, []string, error) { - // Handle ~/ in path - if strings.HasPrefix(configDir, "~/") { - homeDir, err := os.UserHomeDir() - if err != nil { - return nil, nil, err - } - configDir = filepath.Join(homeDir, configDir[2:]) - } - - return cm.kubeconfigManager.GetContextsFromDir(configDir) -} - -// SwitchContext switches to the specified context -func (cm *ContextManager) SwitchContext(contextFilePath string, contextName string) error { - // Ensure the destination directory exists - if err := cm.kubeconfigManager.EnsureDir(); err != nil { - return err - } - - // Switch to the selected context - if err := cm.kubeconfigManager.SwitchContext(contextFilePath, contextName); err != nil { - return err - } - - return nil -} - -// ValidateConfigDir ensures the kubeconfig directory is valid and available -func (cm *ContextManager) ValidateConfigDir(configDir string) (string, error) { - if configDir == "" { - configDir = os.Getenv("KUBECONFIG_DIR") - if configDir == "" { - return "", ErrNoConfigDir - } - } - - // Handle ~/ in path - if strings.HasPrefix(configDir, "~/") { - homeDir, err := os.UserHomeDir() - if err != nil { - return "", err - } - configDir = filepath.Join(homeDir, configDir[2:]) - } - - // Check if the directory exists - info, err := os.Stat(configDir) - if err != nil { - return "", err - } - if !info.IsDir() { - return "", ErrNotADirectory - } - - return configDir, nil -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/pkg/kubeconfig/errors.go new/kubectl-switch-2.3.0/pkg/kubeconfig/errors.go --- old/kubectl-switch-2.2.16/pkg/kubeconfig/errors.go 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/pkg/kubeconfig/errors.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,12 +0,0 @@ -package kubeconfig - -import ( - "errors" -) - -// Common errors for kubeconfig operations -var ( - ErrNoConfigDir = errors.New("kubeconfig directory not provided, please provide the directory containing kubeconfig files via the --config-dir flag or KUBECONFIG_DIR environment variable") - ErrNotADirectory = errors.New("the provided path is not a directory") - ErrNoPreviousConfig = errors.New("no previous configuration found") -) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/pkg/kubeconfig/kubeconfig.go new/kubectl-switch-2.3.0/pkg/kubeconfig/kubeconfig.go --- old/kubectl-switch-2.2.16/pkg/kubeconfig/kubeconfig.go 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/pkg/kubeconfig/kubeconfig.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,185 +0,0 @@ -package kubeconfig - -import ( - "os" - "path/filepath" - - log "github.com/sirupsen/logrus" - "k8s.io/client-go/tools/clientcmd" -) - -// Manager handles operations related to kubeconfig files -type Manager struct{} - -// NewManager creates a new kubeconfig manager -func NewManager() *Manager { - return &Manager{} -} - -// GetPath returns the path to the current kubeconfig file -func (m *Manager) GetPath() string { - path := os.Getenv("KUBECONFIG") - if path == "" { - homeDir, err := os.UserHomeDir() - if err != nil { - log.Fatalf("Failed to determine home directory: %v", err) - } - path = filepath.Join(homeDir, ".kube", "config") - } - return path -} - -// GetPreviousPath returns the path to the previous kubeconfig file -func (m *Manager) GetPreviousPath() string { - return filepath.Join(filepath.Dir(m.GetPath()), "config.previous") -} - -// SaveCurrent backs up the current kubeconfig file -func (m *Manager) SaveCurrent() error { - kubeconfigPath := m.GetPath() - if _, err := os.Stat(kubeconfigPath); os.IsNotExist(err) { - return err - } - - prevPath := m.GetPreviousPath() - data, err := os.ReadFile(kubeconfigPath) - if err != nil { - return err - } - - return os.WriteFile(prevPath, data, 0o600) -} - -// SwitchToPrevious switches back to the previous Kubernetes config -func (m *Manager) SwitchToPrevious() error { - kubeconfigPath := m.GetPath() - prevPath := m.GetPreviousPath() - - // Check if previous config exists - if _, err := os.Stat(prevPath); os.IsNotExist(err) { - return ErrNoPreviousConfig - } - - // Swap the current and previous configs - tempPath := filepath.Join(filepath.Dir(kubeconfigPath), "config.temp") - - // Read current config - currentConfig, err := os.ReadFile(kubeconfigPath) - if err != nil { - return err - } - - // Read previous config - prevConfig, err := os.ReadFile(prevPath) - if err != nil { - return err - } - - // Write current to temp - if err := os.WriteFile(tempPath, currentConfig, 0o600); err != nil { - return err - } - - // Write previous to current - if err := os.WriteFile(kubeconfigPath, prevConfig, 0o600); err != nil { - return err - } - - // Write temp to previous - if err := os.WriteFile(prevPath, currentConfig, 0o600); err != nil { - return err - } - - // Remove temp file - if err := os.Remove(tempPath); err != nil { - log.Warnf("Failed to remove temporary file: %v", err) - } - - return nil -} - -// EnsureDir ensures that the directory for the kubeconfig file exists -func (m *Manager) EnsureDir() error { - destDir := filepath.Dir(m.GetPath()) - return os.MkdirAll(destDir, 0o755) -} - -// GetContextsFromDir gets all contexts from kubeconfig files in a directory -func (m *Manager) GetContextsFromDir(configDir string) (map[string]string, []string, error) { - contextMap := make(map[string]string) - var contextNames []string - - files, err := os.ReadDir(configDir) - if err != nil { - return nil, nil, err - } - - for _, file := range files { - if file.IsDir() { - continue - } - - ext := filepath.Ext(file.Name()) - if ext != ".yaml" && ext != ".yml" { - continue - } - - path := filepath.Join(configDir, file.Name()) - kubeconfig, err := clientcmd.LoadFromFile(path) - if err != nil { - log.WithFields(log.Fields{"file": file.Name()}).Warnf("Failed to parse kubeconfig file: %v", err) - continue - } - - for contextName := range kubeconfig.Contexts { - if _, exists := contextMap[contextName]; exists { - log.Warnf("Duplicate context name '%s' found in files:\n- %s\n- %s", contextName, contextMap[contextName], path) - continue - } - contextMap[contextName] = path - contextNames = append(contextNames, contextName) - } - } - - return contextMap, contextNames, nil -} - -// SwitchContext switches to the specified context -func (m *Manager) SwitchContext(contextFilePath string, contextName string) error { - // Save the current config as the previous config - if err := m.SaveCurrent(); err != nil { - log.Warnf("Failed to save current configuration as previous: %v", err) - } - - // Load the kubeconfig file for the selected context - kubeconfig, err := clientcmd.LoadFromFile(contextFilePath) - if err != nil { - return err - } - - // Update the current context - kubeconfig.CurrentContext = contextName - - // Write the updated kubeconfig back to the file - return clientcmd.WriteToFile(*kubeconfig, m.GetPath()) -} - -// SwitchNamespace switches the namespace in the current context -func (m *Manager) SwitchNamespace(namespace string) error { - // Save the current config as the previous config - if err := m.SaveCurrent(); err != nil { - log.Warnf("Failed to save current configuration as previous: %v", err) - } - - // Load the kubeconfig file - kubeconfig, err := clientcmd.LoadFromFile(m.GetPath()) - if err != nil { - return err - } - - // Update the namespace in the current context - kubeconfig.Contexts[kubeconfig.CurrentContext].Namespace = namespace - - // Write the updated kubeconfig back to the file - return clientcmd.WriteToFile(*kubeconfig, m.GetPath()) -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/pkg/kubeconfig/namespace.go new/kubectl-switch-2.3.0/pkg/kubeconfig/namespace.go --- old/kubectl-switch-2.2.16/pkg/kubeconfig/namespace.go 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/pkg/kubeconfig/namespace.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,56 +0,0 @@ -package kubeconfig - -import ( - "context" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" -) - -// NamespaceManager handles operations related to Kubernetes namespaces -type NamespaceManager struct { - kubeconfigManager *Manager -} - -// NewNamespaceManager creates a new namespace manager -func NewNamespaceManager(km *Manager) *NamespaceManager { - return &NamespaceManager{ - kubeconfigManager: km, - } -} - -// GetNamespaces gets all namespaces from the current context -func (nm *NamespaceManager) GetNamespaces() ([]string, error) { - kubeconfigPath := nm.kubeconfigManager.GetPath() - - // Build the Kubernetes client configuration - config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath) - if err != nil { - return nil, err - } - - // Create the Kubernetes clientset - clientset, err := kubernetes.NewForConfig(config) - if err != nil { - return nil, err - } - - // Get all namespaces - var namespaceNames []string - namespaces, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return nil, err - } - - for _, ns := range namespaces.Items { - namespaceNames = append(namespaceNames, ns.Name) - } - - return namespaceNames, nil -} - -// SwitchNamespace switches the namespace in the current context -func (nm *NamespaceManager) SwitchNamespace(namespace string) error { - return nm.kubeconfigManager.SwitchNamespace(namespace) -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kubectl-switch-2.2.16/scripts/test.sh new/kubectl-switch-2.3.0/scripts/test.sh --- old/kubectl-switch-2.2.16/scripts/test.sh 2025-09-13 20:04:28.000000000 +0200 +++ new/kubectl-switch-2.3.0/scripts/test.sh 2025-10-13 00:17:55.000000000 +0200 @@ -2,27 +2,10 @@ set -e # Create config directory if it doesn't exist -export KUBECONFIG_DIR="./configs/" +export KUBECONFIG="./test/config" +export KUBECONFIG_DIR="./test/configs/" mkdir -p $KUBECONFIG_DIR -cleanup() { - echo "Performing cleanup..." - - # Stop and delete minikube clusters - echo "Stopping and deleting test-cluster-1..." - KUBECONFIG=./configs/cluster1.yaml minikube stop -p test-cluster-1 || true - KUBECONFIG=./configs/cluster1.yaml minikube delete -p test-cluster-1 || true - - echo "Stopping and deleting test-cluster-2..." - KUBECONFIG=./configs/cluster2.yaml minikube stop -p test-cluster-2 || true - KUBECONFIG=./configs/cluster2.yaml minikube delete -p test-cluster-2 || true - - # Remove config directory - echo "Removing configs directory..." - rm -rf ./configs/ - - echo "Cleanup completed." -} setup() { echo "Performing setup..." @@ -33,13 +16,34 @@ # Set up Kubernetes clusters echo "Setting up test clusters..." - KUBECONFIG=./configs/cluster1.yaml minikube start -p test-cluster-1 & - KUBECONFIG=./configs/cluster2.yaml minikube start -p test-cluster-2 & + KUBECONFIG=$KUBECONFIG_DIR/cluster1.yaml minikube start -p test-cluster-1 & + KUBECONFIG=$KUBECONFIG_DIR/cluster2.yaml minikube start -p test-cluster-2 & wait echo "Setup completed." } +cleanup() { + echo "Performing cleanup..." + + # Stop and delete minikube clusters + echo "Stopping and deleting test-cluster-1..." + KUBECONFIG=$KUBECONFIG_DIR/cluster1.yaml minikube stop -p test-cluster-1 || true + KUBECONFIG=$KUBECONFIG_DIR/cluster1.yaml minikube delete -p test-cluster-1 || true + + echo "Stopping and deleting test-cluster-2..." + KUBECONFIG=$KUBECONFIG_DIR/cluster2.yaml minikube stop -p test-cluster-2 || true + KUBECONFIG=$KUBECONFIG_DIR/cluster2.yaml minikube delete -p test-cluster-2 || true + + # Remove config directory + echo "Removing test directory..." + rm -rf tests/ + rm kubectl-switch + + echo "Cleanup completed." +} + + run_tests() { echo "Running tests..." ++++++ kubectl-switch.obsinfo ++++++ --- /var/tmp/diff_new_pack.JWGj7P/_old 2025-10-13 15:37:03.645565406 +0200 +++ /var/tmp/diff_new_pack.JWGj7P/_new 2025-10-13 15:37:03.709568096 +0200 @@ -1,5 +1,5 @@ name: kubectl-switch -version: 2.2.16 -mtime: 1757786668 -commit: 6bb6ac390fbf54d2f17de8dea1de44928fe632bf +version: 2.3.0 +mtime: 1760307475 +commit: 1339ef9aaa2e74313d2f67988d4ac6ec08de852a ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/kubectl-switch/vendor.tar.gz /work/SRC/openSUSE:Factory/.kubectl-switch.new.18484/vendor.tar.gz differ: char 13, line 1
