From c15cbb096aee1b30256464e0a40249a096cdf36a Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Tue, 19 May 2026 14:43:28 +0200 Subject: [PATCH] feat: support HELMFILE_KUBE_CONTEXT env var for default kube context (#2593) * feat: support HELMFILE_KUBE_CONTEXT env var for default kube context Mirrors the existing HELMFILE_ENVIRONMENT pattern: the --kube-context CLI flag takes precedence, falling back to HELMFILE_KUBE_CONTEXT when unset. Refs #1213. Signed-off-by: Dominik Schmidt * docs: mention HELMFILE_KUBE_CONTEXT in cli.md and templating.md Signed-off-by: Dominik Schmidt --------- Signed-off-by: Dominik Schmidt --- cmd/root.go | 2 +- docs/cli.md | 2 +- docs/templating.md | 1 + pkg/config/global.go | 12 +++++++++++- pkg/config/global_test.go | 37 +++++++++++++++++++++++++++++++++++++ pkg/envvar/const.go | 1 + 6 files changed, 52 insertions(+), 3 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 40876dbc..eda150de 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -136,7 +136,7 @@ func setGlobalOptionsForRootCmd(fs *pflag.FlagSet, globalOptions *config.GlobalO fs.BoolVar(&globalOptions.HelmOCIPlainHTTP, "oci-plain-http", false, `use plain HTTP for OCI registries (required for local/insecure registries in Helm 4)`) fs.BoolVarP(&globalOptions.Quiet, "quiet", "q", false, "Silence output. Equivalent to log-level warn") fs.StringVar(&globalOptions.Kubeconfig, "kubeconfig", "", "Use a particular kubeconfig file") - fs.StringVar(&globalOptions.KubeContext, "kube-context", "", "Set kubectl context. Uses current context by default") + fs.StringVar(&globalOptions.KubeContext, "kube-context", "", `Set kubectl context. Overrides "HELMFILE_KUBE_CONTEXT" OS environment variable when specified. Uses current kubectl context by default`) fs.BoolVar(&globalOptions.Debug, "debug", false, "Enable verbose output for Helm and set log-level to debug, this disables --quiet/-q effect") fs.BoolVar(&globalOptions.Color, "color", false, "Output with color") fs.BoolVar(&globalOptions.NoColor, "no-color", false, "Output without color") diff --git a/docs/cli.md b/docs/cli.md index cc264720..cbde76a3 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -49,7 +49,7 @@ Flags: -b, --helm-binary string Path to the helm binary (default "helm") -h, --help help for helmfile -i, --interactive Request confirmation before attempting to modify clusters - --kube-context string Set kubectl context. Uses current context by default + --kube-context string Set kubectl context. Overrides "HELMFILE_KUBE_CONTEXT" OS environment variable when specified. Uses current kubectl context by default -k, --kustomize-binary string Path to the kustomize binary (default "kustomize") --log-level string Set log level, default info (default "info") -n, --namespace string Set namespace. Uses the namespace set in the context by default, and is available in templates as {{ .Namespace }} diff --git a/docs/templating.md b/docs/templating.md index d994c8f1..9a596a27 100644 --- a/docs/templating.md +++ b/docs/templating.md @@ -66,6 +66,7 @@ Helmfile uses some OS environment variables to override default behaviour: * `HELMFILE_USE_HELM_STATUS_TO_CHECK_RELEASE_EXISTENCE` - expecting non-empty value to use `helm status` to check release existence, instead of `helm list` which is the default behaviour * `HELMFILE_EXPERIMENTAL` - enable experimental features, expecting `true` lower case * `HELMFILE_ENVIRONMENT` - specify [Helmfile environment](environments.md), it has lower priority than CLI argument `--environment` +* `HELMFILE_KUBE_CONTEXT` - specify the kubectl context, it has lower priority than CLI argument `--kube-context` * `HELMFILE_TEMPDIR` - specify directory to store temporary files * `HELMFILE_UPGRADE_NOTICE_DISABLED` - expecting any non-empty value to skip the check for the latest version of Helmfile in [helmfile version](cli.md#version) * `HELMFILE_GO_YAML_V3` - use *go.yaml.in/yaml/v3* instead of *go.yaml.in/yaml/v2*. It's `false` by default in Helmfile v0.x, and `true` in Helmfile v1.x. diff --git a/pkg/config/global.go b/pkg/config/global.go index f17ea2d9..8811ff37 100644 --- a/pkg/config/global.go +++ b/pkg/config/global.go @@ -124,7 +124,17 @@ func (g *GlobalImpl) Kubeconfig() string { // KubeContext returns the name of the kubectl context to use. func (g *GlobalImpl) KubeContext() string { - return g.GlobalOptions.KubeContext + var kubeContext string + + switch { + case g.GlobalOptions.KubeContext != "": + kubeContext = g.GlobalOptions.KubeContext + case os.Getenv("HELMFILE_KUBE_CONTEXT") != "": + kubeContext = os.Getenv("HELMFILE_KUBE_CONTEXT") + default: + kubeContext = "" + } + return kubeContext } // Namespace returns the namespace to use. diff --git a/pkg/config/global_test.go b/pkg/config/global_test.go index d59e6ca8..b77751dc 100644 --- a/pkg/config/global_test.go +++ b/pkg/config/global_test.go @@ -45,3 +45,40 @@ func TestFileOrDir(t *testing.T) { } os.Unsetenv(envvar.FilePath) } + +// TestKubeContext tests the kube-context flag and HELMFILE_KUBE_CONTEXT env var fallback +func TestKubeContext(t *testing.T) { + tests := []struct { + opts GlobalOptions + env string + expected string + }{ + { + opts: GlobalOptions{}, + env: "", + expected: "", + }, + { + opts: GlobalOptions{}, + env: "envset", + expected: "envset", + }, + { + opts: GlobalOptions{KubeContext: "flagset"}, + env: "", + expected: "flagset", + }, + { + opts: GlobalOptions{KubeContext: "flagset"}, + env: "envset", + expected: "flagset", + }, + } + + for _, test := range tests { + os.Setenv(envvar.KubeContext, test.env) + received := NewGlobalImpl(&test.opts).KubeContext() + require.Equalf(t, test.expected, received, "KubeContext expected %s, received %s", test.expected, received) + } + os.Unsetenv(envvar.KubeContext) +} diff --git a/pkg/envvar/const.go b/pkg/envvar/const.go index cd4d52bc..f220e505 100644 --- a/pkg/envvar/const.go +++ b/pkg/envvar/const.go @@ -9,6 +9,7 @@ const ( DisableRunnerUniqueID = "HELMFILE_DISABLE_RUNNER_UNIQUE_ID" Experimental = "HELMFILE_EXPERIMENTAL" // environment variable for experimental features, expecting "true" lower case Environment = "HELMFILE_ENVIRONMENT" + KubeContext = "HELMFILE_KUBE_CONTEXT" FilePath = "HELMFILE_FILE_PATH" TempDir = "HELMFILE_TEMPDIR" UpgradeNoticeDisabled = "HELMFILE_UPGRADE_NOTICE_DISABLED"