From ddf70557aea7a105647a865a5ddc6ac09955e0fd Mon Sep 17 00:00:00 2001 From: ljluestc Date: Sat, 29 Nov 2025 19:00:20 -0800 Subject: [PATCH] fix tests --- pkg/state/issue_1757_test.go | 204 +++++++++++++++++++++++++++++++++++ pkg/state/state.go | 8 ++ 2 files changed, 212 insertions(+) create mode 100644 pkg/state/issue_1757_test.go diff --git a/pkg/state/issue_1757_test.go b/pkg/state/issue_1757_test.go new file mode 100644 index 00000000..2a13028f --- /dev/null +++ b/pkg/state/issue_1757_test.go @@ -0,0 +1,204 @@ +package state + +import ( + "context" + "os" + "path/filepath" + "testing" + + "github.com/helmfile/vals" + "github.com/helmfile/helmfile/pkg/filesystem" + "github.com/helmfile/helmfile/pkg/helmexec" + "github.com/stretchr/testify/require" +) + +func TestIssue1757(t *testing.T) { + // Create a temporary directory for the test + tmpDir, err := os.MkdirTemp("", "issue1757") + require.NoError(t, err) + defer os.RemoveAll(tmpDir) + + // Create the chart directory structure + chartDir := filepath.Join(tmpDir, "chart") + err = os.MkdirAll(filepath.Join(chartDir, "templates"), 0755) + require.NoError(t, err) + + // Write Chart.yaml + err = os.WriteFile(filepath.Join(chartDir, "Chart.yaml"), []byte(`apiVersion: v2 +type: application +name: test +version: 0.1.0 +`), 0644) + require.NoError(t, err) + + // Write values.yaml (enabled: false to produce empty output) + err = os.WriteFile(filepath.Join(chartDir, "values.yaml"), []byte(`enabled: false +`), 0644) + require.NoError(t, err) + + // Write templates/configmap.yaml + err = os.WriteFile(filepath.Join(chartDir, "templates/configmap.yaml"), []byte(`{{- if .Values.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: test +{{- end }} +`), 0644) + require.NoError(t, err) + + // Setup HelmState + logger := helmexec.NewLogger(os.Stdout, "debug") + fs := filesystem.DefaultFileSystem() + valsRuntime, err := vals.New(vals.Options{CacheSize: 32}) + require.NoError(t, err) + + st := &HelmState{ + basePath: tmpDir, + logger: logger, + fs: fs, + ReleaseSetSpec: ReleaseSetSpec{ + DefaultHelmBinary: "helm", + }, + RenderedValues: map[string]any{}, + valsRuntime: valsRuntime, + } + + // Define the release with transformers + release := &ReleaseSpec{ + Name: "test", + Chart: filepath.Join(tmpDir, "chart"), + Namespace: "default", + Transformers: []any{ + map[string]any{ + "apiVersion": "builtin", + "kind": "LabelTransformer", + "metadata": map[string]any{ + "name": "unused", + }, + "labels": map[string]any{ + "foo": "bar", + }, + "fieldSpecs": []any{ + map[string]any{ + "path": "spec/groups/rules/labels", + "create": true, + }, + }, + }, + }, + } + + // We need a helm executor + runner := helmexec.ShellRunner{ + Logger: logger, + Ctx: context.Background(), + } + helm, err := helmexec.New("helm", helmexec.HelmExecOptions{}, logger, "", "", runner) + require.NoError(t, err) + + // Call PrepareCharts which triggers the chartification process + opts := ChartPrepareOptions{ + OutputDir: tmpDir, + } + + // We need to add the release to the state + st.Releases = []ReleaseSpec{*release} + + _, errs := st.PrepareCharts(helm, tmpDir, 1, "template", opts) + + require.Empty(t, errs, "PrepareCharts should not return errors") +} + +func TestIssue1757_JSONPatches(t *testing.T) { + // Create a temporary directory for the test + tmpDir, err := os.MkdirTemp("", "issue1757_json") + require.NoError(t, err) + defer os.RemoveAll(tmpDir) + + // Create the chart directory structure + chartDir := filepath.Join(tmpDir, "chart") + err = os.MkdirAll(filepath.Join(chartDir, "templates"), 0755) + require.NoError(t, err) + + // Write Chart.yaml + err = os.WriteFile(filepath.Join(chartDir, "Chart.yaml"), []byte(`apiVersion: v2 +type: application +name: test +version: 0.1.0 +`), 0644) + require.NoError(t, err) + + // Write values.yaml (enabled: false to produce empty output) + err = os.WriteFile(filepath.Join(chartDir, "values.yaml"), []byte(`enabled: false +`), 0644) + require.NoError(t, err) + + // Write templates/configmap.yaml + err = os.WriteFile(filepath.Join(chartDir, "templates/configmap.yaml"), []byte(`{{- if .Values.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: test +{{- end }} +`), 0644) + require.NoError(t, err) + + // Setup HelmState + logger := helmexec.NewLogger(os.Stdout, "debug") + fs := filesystem.DefaultFileSystem() + valsRuntime, err := vals.New(vals.Options{CacheSize: 32}) + require.NoError(t, err) + + st := &HelmState{ + basePath: tmpDir, + logger: logger, + fs: fs, + ReleaseSetSpec: ReleaseSetSpec{ + DefaultHelmBinary: "helm", + }, + RenderedValues: map[string]any{}, + valsRuntime: valsRuntime, + } + + // Define the release with jsonPatches + release := &ReleaseSpec{ + Name: "test", + Chart: filepath.Join(tmpDir, "chart"), + Namespace: "default", + JSONPatches: []any{ + map[string]any{ + "target": map[string]any{ + "kind": "ConfigMap", + "name": "test", + }, + "patch": []any{ + map[string]any{ + "op": "add", + "path": "/metadata/labels/foo", + "value": "bar", + }, + }, + }, + }, + } + + // We need a helm executor + runner := helmexec.ShellRunner{ + Logger: logger, + Ctx: context.Background(), + } + helm, err := helmexec.New("helm", helmexec.HelmExecOptions{}, logger, "", "", runner) + require.NoError(t, err) + + // Call PrepareCharts which triggers the chartification process + opts := ChartPrepareOptions{ + OutputDir: tmpDir, + } + + // We need to add the release to the state + st.Releases = []ReleaseSpec{*release} + + _, errs := st.PrepareCharts(helm, tmpDir, 1, "template", opts) + + require.Empty(t, errs, "PrepareCharts should not return errors with JSONPatches") +} diff --git a/pkg/state/state.go b/pkg/state/state.go index 2882617a..50a27e82 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -1430,6 +1430,14 @@ func (st *HelmState) processChartification(chartification *Chartify, release *Re out, err := c.Chartify(release.Name, chartPath, chartify.WithChartifyOpts(chartifyOpts)) if err != nil { + // Work around chartify failing when the rendered chart output is empty but + // jsonPatches / strategicMergePatches / transformers are configured. + // See https://github.com/helmfile/helmfile/issues/1757 + if strings.Contains(err.Error(), `unexpected dir entry "" it must be the abs path to the output directory`) { + st.logger.Debugf("Chartify returned empty output for release %s, treating as no-op chartification", release.Name) + return chartPath, false, nil + } + return "", false, err }