mirror of
https://github.com/helmfile/helmfile.git
synced 2026-10-05 15:51:23 +02:00
feat: support HELMFILE_* env vars for more global flags (#2606)
* feat: support more HELMFILE_* env vars as flag fallbacks
Adds env-var fallbacks for global flags, mirroring the existing
HELMFILE_ENVIRONMENT / HELMFILE_KUBE_CONTEXT pattern:
* --helm-binary -> HELMFILE_HELM_BINARY
* --kustomize-binary -> HELMFILE_KUSTOMIZE_BINARY
* --log-level -> HELMFILE_LOG_LEVEL
* --debug -> HELMFILE_DEBUG (expecting "true" lower case)
* --quiet -> HELMFILE_QUIET (expecting "true" lower case)
* --no-color -> HELMFILE_NO_COLOR (expecting "true" lower case),
additionally honors NO_COLOR per no-color.org
(any non-empty value disables color)
Flag values still take precedence; env vars are consulted only when the
flag is unset. The string-flag default values ("helm", "kustomize",
"info") move into the accessor methods so the env-var fallback can
actually trigger when no flag is passed.
Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de>
* docs: mention new HELMFILE_* env vars in cli.md and templating.md
Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de>
* fix: make Color/NoColor/env interaction consistent
Two issues with the env-aware NoColor() introduced together with
HELMFILE_NO_COLOR / NO_COLOR support:
1. Color() consulted the raw GlobalOptions.NoColor field instead of
NoColor(), so in a TTY with only the env set, Color() fell through
to terminal autodetect and ValidateConfig() spuriously errored with
"--color and --no-color cannot be specified at the same time".
2. NoColor() returned true via env even when --color was explicitly
passed, so `helmfile --color` with NO_COLOR (or HELMFILE_NO_COLOR=true)
in the environment hit the same ValidateConfig() error. A flag should
always win over an env var.
Fix both by routing Color() through NoColor() and giving NoColor() an
explicit --color short-circuit. Regression tests added for both paths.
Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de>
---------
Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de>
This commit is contained in:
+11
-11
@@ -48,6 +48,8 @@ func toCLIError(g *config.GlobalImpl, err error) error {
|
||||
|
||||
// NewRootCmd creates the root command for the CLI.
|
||||
func NewRootCmd(globalConfig *config.GlobalOptions) (*cobra.Command, error) {
|
||||
globalImpl := config.NewGlobalImpl(globalConfig)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "helmfile",
|
||||
Short: globalUsage,
|
||||
@@ -58,11 +60,11 @@ func NewRootCmd(globalConfig *config.GlobalOptions) (*cobra.Command, error) {
|
||||
PersistentPreRunE: func(c *cobra.Command, args []string) error {
|
||||
// Valid levels:
|
||||
// https://github.com/uber-go/zap/blob/7e7e266a8dbce911a49554b945538c5b950196b8/zapcore/level.go#L126
|
||||
logLevel := globalConfig.LogLevel
|
||||
logLevel := globalImpl.LogLevel()
|
||||
switch {
|
||||
case globalConfig.Debug:
|
||||
case globalImpl.Debug():
|
||||
logLevel = "debug"
|
||||
case globalConfig.Quiet:
|
||||
case globalImpl.Quiet():
|
||||
logLevel = "warn"
|
||||
}
|
||||
|
||||
@@ -83,8 +85,6 @@ func NewRootCmd(globalConfig *config.GlobalOptions) (*cobra.Command, error) {
|
||||
|
||||
flags.ParseErrorsAllowlist.UnknownFlags = true
|
||||
|
||||
globalImpl := config.NewGlobalImpl(globalConfig)
|
||||
|
||||
// when set environment HELMFILE_UPGRADE_NOTICE_DISABLED any value, skip upgrade notice.
|
||||
var versionOpts []extension.CobraOption
|
||||
if os.Getenv(envvar.UpgradeNoticeDisabled) == "" {
|
||||
@@ -121,8 +121,8 @@ func NewRootCmd(globalConfig *config.GlobalOptions) (*cobra.Command, error) {
|
||||
}
|
||||
|
||||
func setGlobalOptionsForRootCmd(fs *pflag.FlagSet, globalOptions *config.GlobalOptions) {
|
||||
fs.StringVarP(&globalOptions.HelmBinary, "helm-binary", "b", app.DefaultHelmBinary, "Path to the helm binary")
|
||||
fs.StringVarP(&globalOptions.KustomizeBinary, "kustomize-binary", "k", app.DefaultKustomizeBinary, "Path to the kustomize binary")
|
||||
fs.StringVarP(&globalOptions.HelmBinary, "helm-binary", "b", "", fmt.Sprintf(`Path to the helm binary. Overrides "HELMFILE_HELM_BINARY" OS environment variable when specified (default %q)`, app.DefaultHelmBinary))
|
||||
fs.StringVarP(&globalOptions.KustomizeBinary, "kustomize-binary", "k", "", fmt.Sprintf(`Path to the kustomize binary. Overrides "HELMFILE_KUSTOMIZE_BINARY" OS environment variable when specified (default %q)`, app.DefaultKustomizeBinary))
|
||||
fs.StringVarP(&globalOptions.File, "file", "f", "", "load config from file or directory. defaults to \"`helmfile.yaml`\" or \"helmfile.yaml.gotmpl\" or \"helmfile.d\" (means \"helmfile.d/*.yaml\" or \"helmfile.d/*.yaml.gotmpl\") in this preference. Specify - to load the config from the standard input.")
|
||||
fs.StringVarP(&globalOptions.Environment, "environment", "e", "", `specify the environment name. Overrides "HELMFILE_ENVIRONMENT" OS environment variable when specified. defaults to "default"`)
|
||||
fs.StringArrayVar(&globalOptions.StateValuesSet, "state-values-set", nil, "set state values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2). Used to override .Values within the helmfile template (not values template).")
|
||||
@@ -134,13 +134,13 @@ func setGlobalOptionsForRootCmd(fs *pflag.FlagSet, globalOptions *config.GlobalO
|
||||
fs.BoolVar(&globalOptions.DisableForceUpdate, "disable-force-update", false, `do not force helm repos to update when executing "helm repo add" (Helm 3 only)`)
|
||||
fs.BoolVar(&globalOptions.EnforcePluginVerification, "enforce-plugin-verification", false, `fail plugin installation if verification is not supported (for security purposes)`)
|
||||
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.BoolVarP(&globalOptions.Quiet, "quiet", "q", false, `Silence output. Equivalent to log-level warn. Overrides "HELMFILE_QUIET" OS environment variable when specified`)
|
||||
fs.StringVar(&globalOptions.Kubeconfig, "kubeconfig", "", "Use a particular kubeconfig file")
|
||||
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.Debug, "debug", false, `Enable verbose output for Helm and set log-level to debug, this disables --quiet/-q effect. Overrides "HELMFILE_DEBUG" OS environment variable when specified`)
|
||||
fs.BoolVar(&globalOptions.Color, "color", false, "Output with color")
|
||||
fs.BoolVar(&globalOptions.NoColor, "no-color", false, "Output without color")
|
||||
fs.StringVar(&globalOptions.LogLevel, "log-level", "info", "Set log level, default info")
|
||||
fs.BoolVar(&globalOptions.NoColor, "no-color", false, `Output without color. Overrides "HELMFILE_NO_COLOR" and "NO_COLOR" OS environment variables when specified`)
|
||||
fs.StringVar(&globalOptions.LogLevel, "log-level", "", `Set log level. Overrides "HELMFILE_LOG_LEVEL" OS environment variable when specified (default "info")`)
|
||||
fs.StringVarP(&globalOptions.Namespace, "namespace", "n", "", `Set namespace. Overrides "HELMFILE_NAMESPACE" OS environment variable when specified. Uses the namespace set in the context by default, and is available in templates as {{ .Namespace }}`)
|
||||
fs.StringVarP(&globalOptions.Chart, "chart", "c", "", "Set chart. Uses the chart set in release by default, and is available in template as {{ .Chart }}")
|
||||
fs.StringArrayVarP(&globalOptions.Selector, "selector", "l", nil, `Only run using the releases that match labels. Labels can take the form of foo=bar or foo!=bar.
|
||||
|
||||
+6
-6
@@ -40,21 +40,21 @@ Flags:
|
||||
--allow-no-matching-release Do not exit with an error code if the provided selector has no matching releases.
|
||||
-c, --chart string Set chart. Uses the chart set in release by default, and is available in template as {{ .Chart }}
|
||||
--color Output with color
|
||||
--debug Enable verbose output for Helm and set log-level to debug, this disables --quiet/-q effect
|
||||
--debug Enable verbose output for Helm and set log-level to debug, this disables --quiet/-q effect. Overrides "HELMFILE_DEBUG" OS environment variable when specified
|
||||
--disable-force-update do not force helm repos to update when executing "helm repo add"
|
||||
--enable-live-output Show live output from the Helm binary Stdout/Stderr into Helmfile own Stdout/Stderr.
|
||||
It only applies for the Helm CLI commands, Stdout/Stderr for Hooks are still displayed only when it's execution finishes.
|
||||
-e, --environment string specify the environment name. Overrides "HELMFILE_ENVIRONMENT" OS environment variable when specified. defaults to "default"
|
||||
-f, --file helmfile.yaml load config from file or directory. defaults to "helmfile.yaml" or "helmfile.yaml.gotmpl" or "helmfile.d" (means "helmfile.d/*.yaml" or "helmfile.d/*.yaml.gotmpl") in this preference. Specify - to load the config from the standard input.
|
||||
-b, --helm-binary string Path to the helm binary (default "helm")
|
||||
-b, --helm-binary string Path to the helm binary. Overrides "HELMFILE_HELM_BINARY" OS environment variable when specified (default "helm")
|
||||
-h, --help help for helmfile
|
||||
-i, --interactive Request confirmation before attempting to modify clusters
|
||||
--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")
|
||||
-k, --kustomize-binary string Path to the kustomize binary. Overrides "HELMFILE_KUSTOMIZE_BINARY" OS environment variable when specified (default "kustomize")
|
||||
--log-level string Set log level. Overrides "HELMFILE_LOG_LEVEL" OS environment variable when specified (default "info")
|
||||
-n, --namespace string Set namespace. Overrides "HELMFILE_NAMESPACE" OS environment variable when specified. Uses the namespace set in the context by default, and is available in templates as {{ .Namespace }}
|
||||
--no-color Output without color
|
||||
-q, --quiet Silence output. Equivalent to log-level warn
|
||||
--no-color Output without color. Overrides "HELMFILE_NO_COLOR" and "NO_COLOR" OS environment variables when specified
|
||||
-q, --quiet Silence output. Equivalent to log-level warn. Overrides "HELMFILE_QUIET" OS environment variable when specified
|
||||
-l, --selector stringArray Only run using the releases that match labels. Labels can take the form of foo=bar or foo!=bar.
|
||||
A release must match all labels in a group in order to be used. Multiple groups can be specified at once.
|
||||
"--selector tier=frontend,tier!=proxy --selector tier=backend" will match all frontend, non-proxy releases AND all backend releases.
|
||||
|
||||
@@ -68,6 +68,12 @@ Helmfile uses some OS environment variables to override default behaviour:
|
||||
* `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_NAMESPACE` - specify the namespace, it has lower priority than CLI argument `--namespace`
|
||||
* `HELMFILE_HELM_BINARY` - specify the path to the helm binary, it has lower priority than CLI argument `--helm-binary`
|
||||
* `HELMFILE_KUSTOMIZE_BINARY` - specify the path to the kustomize binary, it has lower priority than CLI argument `--kustomize-binary`
|
||||
* `HELMFILE_LOG_LEVEL` - specify the log level, it has lower priority than CLI argument `--log-level`
|
||||
* `HELMFILE_DEBUG` - enable debug output, expecting `true` lower case. The same as `--debug` CLI flag
|
||||
* `HELMFILE_QUIET` - silence output (equivalent to log-level warn), expecting `true` lower case. The same as `--quiet`/`-q` CLI flag
|
||||
* `HELMFILE_NO_COLOR` - disable colored output, expecting `true` lower case. The same as `--no-color` CLI flag. `NO_COLOR` (any non-empty value, per [no-color.org](https://no-color.org/)) is also honored
|
||||
* `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.
|
||||
|
||||
+67
-5
@@ -109,12 +109,63 @@ func (g *GlobalImpl) SetSet(set map[string]any) {
|
||||
|
||||
// HelmBinary returns the path to the Helm binary.
|
||||
func (g *GlobalImpl) HelmBinary() string {
|
||||
return g.GlobalOptions.HelmBinary
|
||||
var helmBinary string
|
||||
|
||||
switch {
|
||||
case g.GlobalOptions.HelmBinary != "":
|
||||
helmBinary = g.GlobalOptions.HelmBinary
|
||||
case os.Getenv("HELMFILE_HELM_BINARY") != "":
|
||||
helmBinary = os.Getenv("HELMFILE_HELM_BINARY")
|
||||
default:
|
||||
helmBinary = state.DefaultHelmBinary
|
||||
}
|
||||
return helmBinary
|
||||
}
|
||||
|
||||
// KustomizeBinary returns the path to the Kustomize binary.
|
||||
func (g *GlobalImpl) KustomizeBinary() string {
|
||||
return g.GlobalOptions.KustomizeBinary
|
||||
var kustomizeBinary string
|
||||
|
||||
switch {
|
||||
case g.GlobalOptions.KustomizeBinary != "":
|
||||
kustomizeBinary = g.GlobalOptions.KustomizeBinary
|
||||
case os.Getenv("HELMFILE_KUSTOMIZE_BINARY") != "":
|
||||
kustomizeBinary = os.Getenv("HELMFILE_KUSTOMIZE_BINARY")
|
||||
default:
|
||||
kustomizeBinary = state.DefaultKustomizeBinary
|
||||
}
|
||||
return kustomizeBinary
|
||||
}
|
||||
|
||||
// LogLevel returns the log level to use.
|
||||
func (g *GlobalImpl) LogLevel() string {
|
||||
var logLevel string
|
||||
|
||||
switch {
|
||||
case g.GlobalOptions.LogLevel != "":
|
||||
logLevel = g.GlobalOptions.LogLevel
|
||||
case os.Getenv("HELMFILE_LOG_LEVEL") != "":
|
||||
logLevel = os.Getenv("HELMFILE_LOG_LEVEL")
|
||||
default:
|
||||
logLevel = "info"
|
||||
}
|
||||
return logLevel
|
||||
}
|
||||
|
||||
// Debug returns whether debug output is enabled.
|
||||
func (g *GlobalImpl) Debug() bool {
|
||||
if g.GlobalOptions.Debug {
|
||||
return true
|
||||
}
|
||||
return os.Getenv(envvar.Debug) == "true"
|
||||
}
|
||||
|
||||
// Quiet returns whether quiet output is enabled.
|
||||
func (g *GlobalImpl) Quiet() bool {
|
||||
if g.GlobalOptions.Quiet {
|
||||
return true
|
||||
}
|
||||
return os.Getenv(envvar.Quiet) == "true"
|
||||
}
|
||||
|
||||
// Kubeconfig returns the path to the kubeconfig file to use.
|
||||
@@ -242,7 +293,7 @@ func (g *GlobalImpl) Color() bool {
|
||||
return c
|
||||
}
|
||||
|
||||
if g.GlobalOptions.NoColor {
|
||||
if g.NoColor() {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -259,7 +310,18 @@ func (g *GlobalImpl) Color() bool {
|
||||
|
||||
// NoColor returns the no color flag
|
||||
func (g *GlobalImpl) NoColor() bool {
|
||||
return g.GlobalOptions.NoColor
|
||||
if g.GlobalOptions.NoColor {
|
||||
return true
|
||||
}
|
||||
// Explicit --color short-circuits env-derived no-color: a flag must win over an env var.
|
||||
if g.GlobalOptions.Color {
|
||||
return false
|
||||
}
|
||||
if os.Getenv(envvar.NoColor) == "true" {
|
||||
return true
|
||||
}
|
||||
// Honor the de-facto https://no-color.org/ standard: any non-empty value disables color.
|
||||
return os.Getenv("NO_COLOR") != ""
|
||||
}
|
||||
|
||||
// Env returns the environment to use.
|
||||
@@ -296,7 +358,7 @@ func (g *GlobalImpl) Interactive() bool {
|
||||
// Args returns the args to use for helm
|
||||
func (g *GlobalImpl) Args() string {
|
||||
args := g.GlobalOptions.Args
|
||||
enableHelmDebug := g.Debug
|
||||
enableHelmDebug := g.Debug()
|
||||
|
||||
if enableHelmDebug {
|
||||
args = fmt.Sprintf("%s %s", args, "--debug")
|
||||
|
||||
@@ -119,3 +119,304 @@ func TestNamespace(t *testing.T) {
|
||||
}
|
||||
os.Unsetenv(envvar.Namespace)
|
||||
}
|
||||
|
||||
// TestHelmBinary tests the helm-binary flag and HELMFILE_HELM_BINARY env var fallback
|
||||
func TestHelmBinary(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts GlobalOptions
|
||||
env string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "",
|
||||
expected: "helm",
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "envset",
|
||||
expected: "envset",
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{HelmBinary: "flagset"},
|
||||
env: "",
|
||||
expected: "flagset",
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{HelmBinary: "flagset"},
|
||||
env: "envset",
|
||||
expected: "flagset",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
os.Setenv(envvar.HelmBinary, test.env)
|
||||
received := NewGlobalImpl(&test.opts).HelmBinary()
|
||||
require.Equalf(t, test.expected, received, "HelmBinary expected %s, received %s", test.expected, received)
|
||||
}
|
||||
os.Unsetenv(envvar.HelmBinary)
|
||||
}
|
||||
|
||||
// TestKustomizeBinary tests the kustomize-binary flag and HELMFILE_KUSTOMIZE_BINARY env var fallback
|
||||
func TestKustomizeBinary(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts GlobalOptions
|
||||
env string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "",
|
||||
expected: "kustomize",
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "envset",
|
||||
expected: "envset",
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{KustomizeBinary: "flagset"},
|
||||
env: "",
|
||||
expected: "flagset",
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{KustomizeBinary: "flagset"},
|
||||
env: "envset",
|
||||
expected: "flagset",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
os.Setenv(envvar.KustomizeBinary, test.env)
|
||||
received := NewGlobalImpl(&test.opts).KustomizeBinary()
|
||||
require.Equalf(t, test.expected, received, "KustomizeBinary expected %s, received %s", test.expected, received)
|
||||
}
|
||||
os.Unsetenv(envvar.KustomizeBinary)
|
||||
}
|
||||
|
||||
// TestLogLevel tests the log-level flag and HELMFILE_LOG_LEVEL env var fallback
|
||||
func TestLogLevel(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts GlobalOptions
|
||||
env string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "",
|
||||
expected: "info",
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "envset",
|
||||
expected: "envset",
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{LogLevel: "flagset"},
|
||||
env: "",
|
||||
expected: "flagset",
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{LogLevel: "flagset"},
|
||||
env: "envset",
|
||||
expected: "flagset",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
os.Setenv(envvar.LogLevel, test.env)
|
||||
received := NewGlobalImpl(&test.opts).LogLevel()
|
||||
require.Equalf(t, test.expected, received, "LogLevel expected %s, received %s", test.expected, received)
|
||||
}
|
||||
os.Unsetenv(envvar.LogLevel)
|
||||
}
|
||||
|
||||
// TestDebug tests the debug flag and HELMFILE_DEBUG env var fallback
|
||||
func TestDebug(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts GlobalOptions
|
||||
env string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "true",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "anything",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{Debug: true},
|
||||
env: "",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{Debug: true},
|
||||
env: "true",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
os.Setenv(envvar.Debug, test.env)
|
||||
received := NewGlobalImpl(&test.opts).Debug()
|
||||
require.Equalf(t, test.expected, received, "Debug expected %t, received %t", test.expected, received)
|
||||
}
|
||||
os.Unsetenv(envvar.Debug)
|
||||
}
|
||||
|
||||
// TestQuiet tests the quiet flag and HELMFILE_QUIET env var fallback
|
||||
func TestQuiet(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts GlobalOptions
|
||||
env string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "true",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
env: "anything",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{Quiet: true},
|
||||
env: "",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{Quiet: true},
|
||||
env: "true",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
os.Setenv(envvar.Quiet, test.env)
|
||||
received := NewGlobalImpl(&test.opts).Quiet()
|
||||
require.Equalf(t, test.expected, received, "Quiet expected %t, received %t", test.expected, received)
|
||||
}
|
||||
os.Unsetenv(envvar.Quiet)
|
||||
}
|
||||
|
||||
// TestNoColor tests the no-color flag, HELMFILE_NO_COLOR and NO_COLOR env var fallbacks
|
||||
func TestNoColor(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts GlobalOptions
|
||||
helmfileEnv string
|
||||
standardEnv string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
helmfileEnv: "",
|
||||
standardEnv: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
helmfileEnv: "true",
|
||||
standardEnv: "",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
helmfileEnv: "anything",
|
||||
standardEnv: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
helmfileEnv: "",
|
||||
standardEnv: "1",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{},
|
||||
helmfileEnv: "",
|
||||
standardEnv: "anything",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
opts: GlobalOptions{NoColor: true},
|
||||
helmfileEnv: "",
|
||||
standardEnv: "",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
os.Setenv(envvar.NoColor, test.helmfileEnv)
|
||||
os.Setenv("NO_COLOR", test.standardEnv)
|
||||
received := NewGlobalImpl(&test.opts).NoColor()
|
||||
require.Equalf(t, test.expected, received, "NoColor expected %t, received %t", test.expected, received)
|
||||
}
|
||||
os.Unsetenv(envvar.NoColor)
|
||||
os.Unsetenv("NO_COLOR")
|
||||
}
|
||||
|
||||
// TestColorRespectsNoColorEnv guards against ValidateConfig() firing when
|
||||
// HELMFILE_NO_COLOR / NO_COLOR is set without an explicit --color/--no-color flag.
|
||||
// Color() must consult NoColor() (which is env-aware) before falling back to TTY autodetect.
|
||||
func TestColorRespectsNoColorEnv(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
helmfileEnv string
|
||||
standardEnv string
|
||||
}{
|
||||
{name: "HELMFILE_NO_COLOR=true", helmfileEnv: "true"},
|
||||
{name: "NO_COLOR set", standardEnv: "1"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Setenv(envvar.NoColor, test.helmfileEnv)
|
||||
t.Setenv("NO_COLOR", test.standardEnv)
|
||||
g := NewGlobalImpl(&GlobalOptions{})
|
||||
require.True(t, g.NoColor(), "NoColor() should be true when env is set")
|
||||
require.False(t, g.Color(), "Color() should be false when NoColor() is true via env")
|
||||
require.NoError(t, g.ValidateConfig(), "ValidateConfig() should not error from env-only no-color")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestColorFlagOverridesNoColorEnv guards against ValidateConfig() firing when
|
||||
// --color is explicitly passed but HELMFILE_NO_COLOR / NO_COLOR is set in the
|
||||
// environment. The flag must win over the env var.
|
||||
func TestColorFlagOverridesNoColorEnv(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
helmfileEnv string
|
||||
standardEnv string
|
||||
}{
|
||||
{name: "HELMFILE_NO_COLOR=true", helmfileEnv: "true"},
|
||||
{name: "NO_COLOR set", standardEnv: "1"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Setenv(envvar.NoColor, test.helmfileEnv)
|
||||
t.Setenv("NO_COLOR", test.standardEnv)
|
||||
g := NewGlobalImpl(&GlobalOptions{Color: true})
|
||||
require.True(t, g.Color(), "Color() should be true when --color is set")
|
||||
require.False(t, g.NoColor(), "NoColor() should be false when --color is set, even if env says otherwise")
|
||||
require.NoError(t, g.ValidateConfig(), "ValidateConfig() should not error when --color overrides env no-color")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,12 @@ const (
|
||||
Environment = "HELMFILE_ENVIRONMENT"
|
||||
KubeContext = "HELMFILE_KUBE_CONTEXT"
|
||||
Namespace = "HELMFILE_NAMESPACE"
|
||||
HelmBinary = "HELMFILE_HELM_BINARY"
|
||||
KustomizeBinary = "HELMFILE_KUSTOMIZE_BINARY"
|
||||
LogLevel = "HELMFILE_LOG_LEVEL"
|
||||
Debug = "HELMFILE_DEBUG"
|
||||
Quiet = "HELMFILE_QUIET"
|
||||
NoColor = "HELMFILE_NO_COLOR"
|
||||
FilePath = "HELMFILE_FILE_PATH"
|
||||
TempDir = "HELMFILE_TEMPDIR"
|
||||
UpgradeNoticeDisabled = "HELMFILE_UPGRADE_NOTICE_DISABLED"
|
||||
|
||||
Reference in New Issue
Block a user