From 4a1c53cf9f09e45c3a94cba63ea2f5679b1b9470 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:22:06 +0800 Subject: [PATCH] Fix: Handle empty helmBinary in base files with environment values (#2237) * Initial plan * Fix: Default to "helm" when st.DefaultHelmBinary is empty in getHelm() Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --- pkg/app/app.go | 3 +++ pkg/app/app_gethelm_test.go | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 pkg/app/app_gethelm_test.go diff --git a/pkg/app/app.go b/pkg/app/app.go index aa73fbb2..0da37450 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -793,6 +793,9 @@ func (a *App) getHelm(st *state.HelmState) (helmexec.Interface, error) { } bin := st.DefaultHelmBinary + if bin == "" { + bin = state.DefaultHelmBinary + } kubeconfig := a.Kubeconfig kubectx := st.HelmDefaults.KubeContext diff --git a/pkg/app/app_gethelm_test.go b/pkg/app/app_gethelm_test.go new file mode 100644 index 00000000..3703e0ad --- /dev/null +++ b/pkg/app/app_gethelm_test.go @@ -0,0 +1,51 @@ +package app + +import ( + goContext "context" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/helmfile/helmfile/pkg/state" +) + +// TestGetHelmWithEmptyDefaultHelmBinary tests that getHelm properly defaults to "helm" +// when st.DefaultHelmBinary is empty. This addresses the issue where base files with +// environment secrets would fail with "exec: no command" error. +// +// Background: When a base file has environment secrets but doesn't specify helmBinary, +// the state.DefaultHelmBinary would be empty, causing helmexec.New to be called with +// an empty string, which results in "error determining helm version: exec: no command". +// +// The fix in app.getHelm() ensures that when st.DefaultHelmBinary is empty, it defaults +// to state.DefaultHelmBinary ("helm"). +func TestGetHelmWithEmptyDefaultHelmBinary(t *testing.T) { + // Test that app.getHelm() handles empty DefaultHelmBinary correctly by applying a default + st := &state.HelmState{ + ReleaseSetSpec: state.ReleaseSetSpec{ + DefaultHelmBinary: "", // Empty, as would be the case for base files + }, + } + + logger := newAppTestLogger() + app := &App{ + OverrideHelmBinary: "", + OverrideKubeContext: "", + Logger: logger, + Env: "default", + ctx: goContext.Background(), + } + + // This should NOT fail because app.getHelm() defaults empty DefaultHelmBinary to "helm" + helm, err := app.getHelm(st) + + // Verify that no error occurred - the fix in app.getHelm() prevents the "exec: no command" error + require.NoError(t, err, "getHelm should not fail when DefaultHelmBinary is empty (fix should apply default)") + + // Verify that a valid helm execer was returned + require.NotNil(t, helm, "getHelm should return a valid helm execer") + + // Verify that the helm version is accessible (confirms the helm binary is valid) + version := helm.GetVersion() + require.NotNil(t, version, "helm version should be accessible") +}