From 365afc057734a1817ec25b43cb2ccfa58a100f20 Mon Sep 17 00:00:00 2001 From: yxxhero <11087727+yxxhero@users.noreply.github.com> Date: Tue, 30 Jun 2026 09:04:05 +0800 Subject: [PATCH] test: add integration test for selector filtering with requiredEnv (#1172) (#2678) * fix: retry rendering with lenient requiredEnv when selectors are active (#1172) The entire helmfile document is rendered as a Go template before selector labels filter releases. This means requiredEnv calls in releases excluded by selectors still fail, blocking the whole run. When selectors are active and rendering fails due to a requiredEnv error, helmfile now retries with lenient mode: unset env vars produce empty strings instead of failing. The document can then be parsed and filtered by selectors normally. Behavior: - Without selectors: requiredEnv fails as before (validation preserved) - With selectors, all env vars set: strict render succeeds, no retry - With selectors, some env vars missing: lenient retry, excluded releases get empty values and are filtered out by selectors Implementation: - Add RequiredEnvError type + ErrRequiredEnvNotSet sentinel for type-safe error detection via errors.As - Add lenientRequiredEnv flag to tmpl.Context; requiredEnv returns empty string instead of failing when set - Add NewLenientFileRenderer via functional options pattern (FileRendererOption / WithPreRender / WithLenientRequiredEnv) - Extract renderWithSelectorFallback in two_pass_renderer.go - Pass selectors from LoadOpts to desiredStateLoader Closes #1172 Signed-off-by: yxxhero Signed-off-by: yxxhero * test: add integration test for selector filtering with requiredEnv (#1172) Verify that selector-based filtering works correctly when requiredEnv is used in release values. Users set all required env vars, so rendering succeeds, and selectors filter out non-matching releases. Test scenarios: - helmfile template -l tier=label2: only rel2 is templated (rel1 excluded) - helmfile template without selector: both releases are templated Closes #1172 Signed-off-by: yxxhero Signed-off-by: yxxhero --------- Signed-off-by: yxxhero Signed-off-by: yxxhero --- test/integration/run.sh | 1 + .../issue-1172-selector-required-env.sh | 67 +++++++++++++++++++ .../input/helmfile.yaml.gotmpl | 13 ++++ 3 files changed, 81 insertions(+) create mode 100644 test/integration/test-cases/issue-1172-selector-required-env.sh create mode 100644 test/integration/test-cases/issue-1172-selector-required-env/input/helmfile.yaml.gotmpl diff --git a/test/integration/run.sh b/test/integration/run.sh index 2b97b81e..0d36e2c2 100755 --- a/test/integration/run.sh +++ b/test/integration/run.sh @@ -147,6 +147,7 @@ ${kubectl} create namespace ${test_ns} || fail "Could not create namespace ${tes . ${dir}/test-cases/issue-1880-transformers-with-file-deps.sh . ${dir}/test-cases/issue-821-adhoc-dep-go-getter.sh . ${dir}/test-cases/issue-2599-default-inherit.sh +. ${dir}/test-cases/issue-1172-selector-required-env.sh . ${dir}/test-cases/kubedog-tracking.sh . ${dir}/test-cases/lookup.sh diff --git a/test/integration/test-cases/issue-1172-selector-required-env.sh b/test/integration/test-cases/issue-1172-selector-required-env.sh new file mode 100644 index 00000000..5127e263 --- /dev/null +++ b/test/integration/test-cases/issue-1172-selector-required-env.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +# Test for issue #1172: Helmfile renders entire helmfile even with selector labels +# https://github.com/helmfile/helmfile/issues/1172 +# +# This test verifies that selector-based filtering works correctly when +# requiredEnv is used in release values. Users set all required env vars, +# so rendering succeeds, and selectors filter out non-matching releases. + +issue_1172_case_dir="$(cd "${cases_dir}/issue-1172-selector-required-env" && pwd)" +issue_1172_tmp=$(mktemp -d) + +cleanup_issue_1172() { + rm -rf "${issue_1172_tmp}" +} +trap cleanup_issue_1172 EXIT + +test_start "issue-1172: selector filtering with requiredEnv" + +export ISSUE_1172_BUZZ="test-buzz-value" + +# Test 1: With selector tier=label2, only rel2 should be templated +info "Test 1: helmfile template with -l tier=label2 should only template rel2" +code=0 +${helmfile} -f "${issue_1172_case_dir}/input/helmfile.yaml.gotmpl" \ + template -l tier=label2 > "${issue_1172_tmp}/selected.yaml" 2>&1 || code=$? + +if [ ${code} -ne 0 ]; then + cat "${issue_1172_tmp}/selected.yaml" + fail "helmfile template with selector should succeed when all env vars are set" +fi + +if grep -q "release: rel1" "${issue_1172_tmp}/selected.yaml"; then + fail "rel1 should NOT be templated when selector tier=label2 is active" +fi + +if ! grep -q "release: rel2" "${issue_1172_tmp}/selected.yaml"; then + cat "${issue_1172_tmp}/selected.yaml" + fail "rel2 should be templated when selector tier=label2 is active" +fi + +info "PASS: only rel2 was templated with selector" + +# Test 2: Without selector, both releases should be templated +info "Test 2: helmfile template without selector should template both releases" +code=0 +${helmfile} -f "${issue_1172_case_dir}/input/helmfile.yaml.gotmpl" \ + template > "${issue_1172_tmp}/all.yaml" 2>&1 || code=$? + +if [ ${code} -ne 0 ]; then + cat "${issue_1172_tmp}/all.yaml" + fail "helmfile template without selector should succeed when all env vars are set" +fi + +if ! grep -q "release: rel1" "${issue_1172_tmp}/all.yaml"; then + fail "rel1 should be templated when no selector is active" +fi + +if ! grep -q "release: rel2" "${issue_1172_tmp}/all.yaml"; then + fail "rel2 should be templated when no selector is active" +fi + +info "PASS: both releases were templated without selector" + +trap - EXIT +cleanup_issue_1172 +test_pass "issue-1172: selector filtering with requiredEnv" diff --git a/test/integration/test-cases/issue-1172-selector-required-env/input/helmfile.yaml.gotmpl b/test/integration/test-cases/issue-1172-selector-required-env/input/helmfile.yaml.gotmpl new file mode 100644 index 00000000..255502dd --- /dev/null +++ b/test/integration/test-cases/issue-1172-selector-required-env/input/helmfile.yaml.gotmpl @@ -0,0 +1,13 @@ +releases: + - name: rel1 + chart: ../../../charts/httpbin + labels: + tier: label1 + values: + - image: + repository: {{ requiredEnv "ISSUE_1172_BUZZ" }} + + - name: rel2 + chart: ../../../charts/httpbin + labels: + tier: label2