Merge remote-tracking branch 'origin/main' into fix-include-needs-transitive-1003

Resolve merge conflicts in pkg/app/app.go:
- WithPreparedCharts rename (withPreparedCharts -> WithPreparedCharts)
- WriteOutput handling for fetch command
- DetailedExitcode handling for sync command
- GetPlannedAndSelectedReleasesWithNeeds new function (pass both includeNeeds params)
- SyncState using GetPlannedAndSelectedReleasesWithNeeds

Also fix ForEachState call signatures in tests to include both bool params.
This commit is contained in:
copilot-swe-agent[bot]
2026-05-27 08:46:23 +00:00
committed by GitHub
133 changed files with 10958 additions and 2933 deletions
@@ -0,0 +1,33 @@
Adding repo myrepo http://localhost:18080/
"myrepo" has been added to your repositories
Building dependency release=foo, chart=$WD/temp1/foo
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "myrepo" chart repository
Update Complete. ⎈Happy Helming!⎈
Saving 1 charts
Downloading raw from repo http://localhost:18080/
Deleting outdated charts
Templating release=foo, chart=$WD/temp1/foo
---
# Source: raw/charts/dep/templates/resources.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: foo-2
namespace: default
data:
bar: BAR
---
# Source: raw/templates/resources.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: foo-1
namespace: default
data:
foo: FOO
@@ -0,0 +1,34 @@
Live output is enabled
Adding repo myrepo http://localhost:18081/
"myrepo" has been added to your repositories
Building dependency release=foo, chart=$WD/temp1/foo
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "myrepo" chart repository
Update Complete. ⎈Happy Helming!⎈
Saving 1 charts
Downloading raw from repo http://localhost:18081/
Deleting outdated charts
Templating release=foo, chart=$WD/temp1/foo
---
# Source: raw/charts/dep/templates/resources.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: foo-2
namespace: default
data:
bar: BAR
---
# Source: raw/templates/resources.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: foo-1
namespace: default
data:
foo: FOO
@@ -0,0 +1,27 @@
Building dependency release=foo, chart=$WD/temp1/foo
Saving 1 charts
Downloading raw from repo oci://localhost:$REGISTRY_PORT/myrepo
Deleting outdated charts
Templating release=foo, chart=$WD/temp1/foo
---
# Source: raw/charts/dep/templates/resources.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: foo-2
namespace: default
data:
bar: BAR
---
# Source: raw/templates/resources.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: foo-1
namespace: default
data:
foo: FOO
@@ -13,6 +13,7 @@ data:
two: TWO
metadata:
name: cm2
---
# Source: raw/templates/resources.yaml
apiVersion: v1
@@ -32,6 +33,7 @@ data:
one: ONE
metadata:
name: cm1
---
# Source: raw/templates/resources.yaml
apiVersion: v1
+8 -1
View File
@@ -27,7 +27,7 @@ export HELM_DATA_HOME="${helm_dir}/data"
export HELM_HOME="${HELM_DATA_HOME}"
export HELM_PLUGINS="${HELM_DATA_HOME}/plugins"
export HELM_CONFIG_HOME="${helm_dir}/config"
HELM_DIFF_VERSION="${HELM_DIFF_VERSION:-3.15.3}"
HELM_DIFF_VERSION="${HELM_DIFF_VERSION:-3.15.7}"
HELM_GIT_VERSION="${HELM_GIT_VERSION:-1.4.1}"
HELM_SECRETS_VERSION="${HELM_SECRETS_VERSION:-4.7.4}"
export GNUPGHOME="${PWD}/${dir}/.gnupg"
@@ -96,8 +96,10 @@ ${kubectl} create namespace ${test_ns} || fail "Could not create namespace ${tes
# TEST CASES----------------------------------------------------------------------------------------------------------
. ${dir}/test-cases/issue-2502-race-condition-local-chart.sh
. ${dir}/test-cases/chart-deps-condition.sh
. ${dir}/test-cases/fetch-forl-local-chart.sh
. ${dir}/test-cases/fetch-write-output.sh
. ${dir}/test-cases/suppress-output-line-regex.sh
. ${dir}/test-cases/chartify-jsonPatches-and-strategicMergePatches.sh
. ${dir}/test-cases/include-template-func.sh
@@ -114,6 +116,8 @@ ${kubectl} create namespace ${test_ns} || fail "Could not create namespace ${tes
. ${dir}/test-cases/yaml-overwrite.sh
. ${dir}/test-cases/chart-needs.sh
. ${dir}/test-cases/postrender.sh
. ${dir}/test-cases/postrender-defaults-args.sh
. ${dir}/test-cases/issue-2515.sh
. ${dir}/test-cases/chartify.sh
. ${dir}/test-cases/deps-mr-1011.sh
. ${dir}/test-cases/deps-kustomization-i-1402.sh
@@ -138,6 +142,9 @@ ${kubectl} create namespace ${test_ns} || fail "Could not create namespace ${tes
. ${dir}/test-cases/issue-2418.sh
. ${dir}/test-cases/issue-2424-sequential-values-paths.sh
. ${dir}/test-cases/issue-2431.sh
. ${dir}/test-cases/issue-2544.sh
. ${dir}/test-cases/issue-2596-local-deps-multiple-files.sh
. ${dir}/test-cases/issue-2599-default-inherit.sh
. ${dir}/test-cases/kubedog-tracking.sh
. ${dir}/test-cases/include-needs-transitive.sh
@@ -0,0 +1,39 @@
fetch_write_output_input_dir="${cases_dir}/fetch-write-output/input"
fetch_write_output_tmp=$(mktemp -d)
case_title="fetch with --write-output for air-gapped environments"
test_start "$case_title"
info "Testing helmfile fetch --write-output with local chart"
output=$(${helmfile} -f "${fetch_write_output_input_dir}/helmfile.yaml.gotmpl" fetch --output-dir "${fetch_write_output_tmp}" --write-output 2>/dev/null) \
|| fail "\"helmfile fetch --write-output\" shouldn't fail"
info "Verifying stdout does not contain non-YAML status messages"
echo "${output}" | grep -q "^Charts will be downloaded to:" && fail "stdout should not contain 'Charts will be downloaded to:' (should be on stderr)" || true
info "Verifying output contains YAML document separator"
echo "${output}" | grep -q "^---" || fail "output should contain YAML document separator"
info "Verifying output contains source helmfile reference"
echo "${output}" | grep -q "# Source:" || fail "output should contain source helmfile reference"
info "Verifying output contains release name"
echo "${output}" | grep -q "name: local-chart" || fail "output should contain release name"
info "Verifying output contains updated chart path pointing to output dir"
echo "${output}" | grep -q "chart:" || fail "output should contain chart field"
info "Verifying chart files exist in output directory"
cat "${fetch_write_output_tmp}/helmfile-tests/local-chart/raw/latest/Chart.yaml" || fail "Chart.yaml should exist in fetched output directory"
info "Verifying the chart path in output matches the actual downloaded location"
chart_path=$(echo "${output}" | grep -E "^[[:space:]]+(-[[:space:]]+)?chart:" | head -1 | sed 's/.*chart: *//' | tr -d '"')
if [ ! -f "${chart_path}/Chart.yaml" ]; then
fail "chart path '${chart_path}' from output should point to a directory containing Chart.yaml"
fi
rm -rf "${fetch_write_output_tmp}"
test_pass "$case_title"
@@ -0,0 +1,4 @@
releases:
- name: local-chart
chart: ../../../charts/raw
namespace: local-chart
@@ -1,5 +1,10 @@
// server.go is a small HTTP server used by the issue-2103 integration test.
// It serves different YAML content based on the "ref" query parameter.
// It is excluded from normal `go test ./...` runs; the integration test builds it
// explicitly via its file path.
//go:build ignore
package main
import (
+36 -18
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Test for issue #2271: lookup function should work with strategicMergePatches
# Test for issue #2271: lookup function should work with strategicMergePatches and jsonPatches
# Without this fix, helm template runs client-side and lookup() returns empty values
issue_2271_input_dir="${cases_dir}/issue-2271/input"
@@ -8,7 +8,7 @@ issue_2271_tmp_dir=$(mktemp -d)
cd "${issue_2271_input_dir}"
test_start "issue-2271: lookup function with strategicMergePatches"
test_start "issue-2271: lookup function with strategicMergePatches and jsonPatches"
# Test 1: Install chart without kustomize patches
info "Installing chart without kustomize patches"
@@ -36,26 +36,44 @@ fi
info "ConfigMap value updated to: $current_value"
assert_lookup_preserved() {
local label="$1"
local helmfile_path="$2"
local output_path="$3"
local code
info "Testing diff with ${label} - lookup should preserve value"
${helmfile} -f "${helmfile_path}" diff > "${output_path}" 2>&1
code=$?
if [ $code -ne 0 ] && [ $code -ne 2 ]; then
cat "${output_path}"
rm -rf "${issue_2271_tmp_dir}"
fail "Unexpected error during diff with ${label}"
fi
# Check if the diff contains the preserved value (not "initial-value")
if grep -q "preserved-value.*test-preserved-value" "${output_path}"; then
info "SUCCESS: lookup function preserved the value with ${label}"
elif grep -q "preserved-value.*initial-value" "${output_path}"; then
cat "${output_path}"
rm -rf "${issue_2271_tmp_dir}"
fail "Issue #2271 regression: lookup function returned empty value with ${label}"
else
# No diff for ConfigMap means value is perfectly preserved
info "SUCCESS: No ConfigMap changes detected for ${label} (value perfectly preserved)"
fi
}
# Test 3: Diff with strategicMergePatches should preserve the lookup value
info "Testing diff with strategicMergePatches - lookup should preserve value"
assert_lookup_preserved "strategicMergePatches" "helmfile.yaml" "${issue_2271_tmp_dir}/test-2271-strategic-diff.txt"
${helmfile} -f helmfile.yaml diff > "${issue_2271_tmp_dir}/test-2271-diff.txt" 2>&1
code=$?
# Check if the diff contains the preserved value (not "initial-value")
if grep -q "preserved-value.*test-preserved-value" "${issue_2271_tmp_dir}/test-2271-diff.txt"; then
info "SUCCESS: lookup function preserved the value with kustomize patches"
elif grep -q "preserved-value.*initial-value" "${issue_2271_tmp_dir}/test-2271-diff.txt"; then
cat "${issue_2271_tmp_dir}/test-2271-diff.txt"
rm -rf "${issue_2271_tmp_dir}"
fail "Issue #2271 regression: lookup function returned empty value with kustomize"
else
# No diff for ConfigMap means value is perfectly preserved
info "SUCCESS: No ConfigMap changes detected (value perfectly preserved)"
fi
# Test 4: Diff with jsonPatches should preserve the lookup value
assert_lookup_preserved "jsonPatches" "helmfile-jsonpatch.yaml" "${issue_2271_tmp_dir}/test-2271-json-diff.txt"
# Cleanup
${helm} uninstall test-release-2271 --namespace default 2>/dev/null || true
rm -rf "${issue_2271_tmp_dir}"
test_pass "issue-2271: lookup function with strategicMergePatches"
test_pass "issue-2271: lookup function with strategicMergePatches and jsonPatches"
@@ -0,0 +1,16 @@
releases:
- name: test-release-2271
namespace: default
chart: ./test-chart
installed: true
jsonPatches:
- target:
group: apps
version: v1
kind: Deployment
name: test-release-2271-app
namespace: default
patch:
- op: add
path: /spec/template/metadata/labels/hello
value: world
@@ -0,0 +1,50 @@
# Integration test for issue #2502: Race condition when multiple releases share a local chart
# https://github.com/helmfile/helmfile/issues/2502
#
# When multiple releases reference the same local chart, concurrent goroutines
# race on rewriting Chart.yaml dependencies, causing:
# "Error: validation: chart.metadata.name is required"
#
# This test verifies the fix works WITHOUT --concurrency 1 workaround.
issue_2502_input_dir="${cases_dir}/issue-2502-race-condition-local-chart/input"
issue_2502_tmp=$(mktemp -d)
actual="${issue_2502_tmp}/actual.yaml"
cleanup_issue_2502() {
if [ -n "${issue_2502_tmp}" ] && [ -d "${issue_2502_tmp}" ]; then
rm -rf "${issue_2502_tmp}"
fi
}
trap cleanup_issue_2502 EXIT
test_start "issue #2502: race condition with shared local chart"
info "Running helmfile template with 5 releases sharing the same local chart (default concurrency)"
# Run WITHOUT --concurrency 1 to test the fix.
# Before the fix, this would intermittently fail with:
# "Error: validation: chart.metadata.name is required"
# Run multiple iterations to increase chance of catching a race.
pass=0
iterations=5
for i in $(seq 1 ${iterations}); do
if ${helmfile} -f ${issue_2502_input_dir}/helmfile.yaml -e test template > ${actual} 2>&1; then
pass=$((pass + 1))
else
cat ${actual}
fail "helmfile template failed on iteration ${i}/${iterations} (race condition on shared local chart)"
fi
done
if [ ${pass} -ne ${iterations} ]; then
fail "Expected ${iterations}/${iterations} passes but got ${pass}/${iterations}"
fi
info "All ${iterations} iterations passed successfully"
cleanup_issue_2502
trap - EXIT
test_pass "issue #2502: race condition with shared local chart"
@@ -0,0 +1,10 @@
dependencies:
- name: raw
repository: file://../../../../../charts/raw
version: 0.0.1
apiVersion: v2
appVersion: "1.0.0"
description: A test chart for race condition reproduction
name: my-chart
type: application
version: 0.1.0
@@ -0,0 +1,9 @@
raw:
templates:
- |
apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
data:
key: value
@@ -0,0 +1,49 @@
environments:
test: {}
---
releases:
- name: app
chart: helm/my-chart
strategicMergePatches:
- apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
data:
key: value
- name: app-2
chart: helm/my-chart
strategicMergePatches:
- apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
data:
key: value
- name: app-3
chart: helm/my-chart
strategicMergePatches:
- apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
data:
key: value
- name: app-4
chart: helm/my-chart
strategicMergePatches:
- apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
data:
key: value
- name: app-5
chart: helm/my-chart
strategicMergePatches:
- apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
data:
key: value
+62
View File
@@ -0,0 +1,62 @@
issue_2515_case_dir="$(cd "${cases_dir}/issue-2515" && pwd)"
issue_2515_tmp=$(mktemp -d)
# Determine the post-renderer argument.
# Helm 3 accepts an executable script; Helm 4 requires a plugin name.
if [ "${HELMFILE_HELM4}" = "1" ]; then
test_start "issue-2515 post-renderer with output-dir-template (Helm 4)"
info "Installing filter post-renderer plugin for Helm 4"
${helm} plugin uninstall filter &>/dev/null || true
${helm} plugin install ${issue_2515_case_dir}/input/helm-plugin-filter ${PLUGIN_INSTALL_FLAGS} || fail "Failed to install filter plugin"
issue_2515_postrenderer_arg="filter"
else
test_start "issue-2515 post-renderer with output-dir-template"
issue_2515_postrenderer_arg="${issue_2515_case_dir}/input/filter.bash"
fi
info "Testing that --post-renderer output is written to files when --output-dir-template is set"
issue_2515_output_dir="${issue_2515_tmp}/output"
${helmfile} -f ${issue_2515_case_dir}/input/helmfile.yaml \
template \
--post-renderer ${issue_2515_postrenderer_arg} \
--output-dir-template "${issue_2515_output_dir}/{{.Release.Name}}" \
&> ${issue_2515_tmp}/log || fail "helmfile template should not fail"
if [ "${HELMFILE_HELM4}" = "1" ]; then
# Helm 4 natively applies --post-renderer to --output-dir output.
# The directory structure may differ from Helm 3 (no guaranteed templates/ subdir),
# so search recursively for any YAML file. Fall back to stdout (log) if no files written.
issue_2515_output_file=$(find "${issue_2515_output_dir}" -maxdepth 5 -type f \( -name '*.yaml' -o -name '*.yml' \) 2>/dev/null | head -n 1)
if [ -z "${issue_2515_output_file}" ]; then
# Helm 4 may write post-rendered output to stdout rather than files
issue_2515_output_file="${issue_2515_tmp}/log"
if ! grep -q "postrendered" "${issue_2515_output_file}"; then
fail "Expected post-rendered YAML (namespace postrendered) in output files under ${issue_2515_output_dir} or stdout. Dir: $(find ${issue_2515_output_dir} 2>/dev/null || echo 'not found'). Log (last 50 lines): $(tail -50 ${issue_2515_output_file})"
fi
fi
else
issue_2515_templates_dir="${issue_2515_output_dir}/issue-2515/templates"
if [ ! -d "${issue_2515_templates_dir}" ]; then
fail "Expected templates directory ${issue_2515_templates_dir} to exist"
fi
issue_2515_output_file=$(find "${issue_2515_templates_dir}" -type f \( -name '*.yaml' -o -name '*.yml' \) | head -n 1)
if [ -z "${issue_2515_output_file}" ]; then
fail "Expected rendered YAML file under ${issue_2515_templates_dir}"
fi
fi
if grep -q "original-cm" "${issue_2515_output_file}"; then
fail "Output should contain post-renderer output (Namespace), not original templates (original-cm). File contents: $(cat ${issue_2515_output_file})"
fi
if ! grep -q "postrendered" "${issue_2515_output_file}"; then
fail "Output should contain post-renderer content (namespace postrendered). File contents: $(cat ${issue_2515_output_file})"
fi
if [ "${HELMFILE_HELM4}" = "1" ]; then
test_pass "issue-2515 post-renderer with output-dir-template (Helm 4)"
else
test_pass "issue-2515 post-renderer with output-dir-template"
fi
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
printf -- "---\napiVersion: v1\nkind: Namespace\nmetadata:\n name: postrendered\n"
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Discard stdin (pre-rendered content) and output a fixed Namespace resource.
# This verifies that the post-renderer output — not the original templates — is
# written to the output directory.
cat > /dev/null
printf -- "---\napiVersion: v1\nkind: Namespace\nmetadata:\n name: postrendered\n"
@@ -0,0 +1,8 @@
apiVersion: v1
type: postrenderer/v1
name: filter
version: 0.1.0
runtime: subprocess
runtimeConfig:
platformCommand:
- command: ${HELM_PLUGIN_DIR}/filter.sh
@@ -0,0 +1,13 @@
releases:
- name: issue-2515
chart: ../../../charts/raw
values:
- templates:
- |
apiVersion: v1
kind: ConfigMap
metadata:
name: original-cm
namespace: {{ .Release.Namespace }}
data:
key: value
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
# Test for issue #2544: subhelmfiles should only be evaluated if their selectors match
# When CLI selectors are provided, subhelmfiles with incompatible selectors are skipped.
issue_2544_input_dir="${cases_dir}/issue-2544/input"
issue_2544_tmp_dir=$(mktemp -d)
cleanup_issue_2544() {
rm -rf "${issue_2544_tmp_dir}"
}
test_start "issue-2544: subhelmfiles skipped when selectors conflict with CLI"
# --- Test 1: -l app=b should only produce output from subhelmfile-b ---------------------------
info "Running helmfile template -l app=b"
${helmfile} -f "${issue_2544_input_dir}/helmfile.yaml" template -l app=b \
> "${issue_2544_tmp_dir}/output-b.txt" 2>&1 || {
cat "${issue_2544_tmp_dir}/output-b.txt"
cleanup_issue_2544
fail "helmfile template -l app=b failed"
}
# Should contain release-b
grep -q "release-b" "${issue_2544_tmp_dir}/output-b.txt" \
|| { cleanup_issue_2544; fail "output should contain release-b (matching selector app=b)"; }
# Should NOT contain release-a or release-c (their subhelmfiles have incompatible selectors)
grep -q "release-a" "${issue_2544_tmp_dir}/output-b.txt" \
&& { cleanup_issue_2544; fail "output should NOT contain release-a (subhelmfile selectors app=a conflict with app=b)"; }
grep -q "release-c" "${issue_2544_tmp_dir}/output-b.txt" \
&& { cleanup_issue_2544; fail "output should NOT contain release-c (subhelmfile selectors app=c conflict with app=b)"; }
info "PASS: -l app=b produces only release-b"
# --- Test 2: no selector should produce all releases -----------------------------------------
info "Running helmfile template without selector"
${helmfile} -f "${issue_2544_input_dir}/helmfile.yaml" template \
> "${issue_2544_tmp_dir}/output-all.txt" 2>&1 || {
cat "${issue_2544_tmp_dir}/output-all.txt"
cleanup_issue_2544
fail "helmfile template without selector failed"
}
grep -q "release-a" "${issue_2544_tmp_dir}/output-all.txt" \
|| { cleanup_issue_2544; fail "output should contain release-a"; }
grep -q "release-b" "${issue_2544_tmp_dir}/output-all.txt" \
|| { cleanup_issue_2544; fail "output should contain release-b"; }
grep -q "release-c" "${issue_2544_tmp_dir}/output-all.txt" \
|| { cleanup_issue_2544; fail "output should contain release-c"; }
info "PASS: no selector produces all releases"
# --- Test 3: -l app=a should skip subhelmfiles with selectors app=b and app=c ---------------
info "Running helmfile template -l app=a"
${helmfile} -f "${issue_2544_input_dir}/helmfile.yaml" template -l app=a \
> "${issue_2544_tmp_dir}/output-a.txt" 2>&1 || {
cat "${issue_2544_tmp_dir}/output-a.txt"
cleanup_issue_2544
fail "helmfile template -l app=a failed"
}
grep -q "release-a" "${issue_2544_tmp_dir}/output-a.txt" \
|| { cleanup_issue_2544; fail "output should contain release-a (matching selector app=a)"; }
grep -q "release-b" "${issue_2544_tmp_dir}/output-a.txt" \
&& { cleanup_issue_2544; fail "output should NOT contain release-b (subhelmfile selectors app=b conflict with app=a)"; }
grep -q "release-c" "${issue_2544_tmp_dir}/output-a.txt" \
&& { cleanup_issue_2544; fail "output should NOT contain release-c (subhelmfile selectors app=c conflict with app=a)"; }
info "PASS: -l app=a produces only release-a"
cleanup_issue_2544
test_pass "issue-2544: subhelmfiles skipped when selectors conflict with CLI"
@@ -0,0 +1,10 @@
helmfiles:
- path: subhelmfile-a.yaml
selectors:
- app=a
- path: subhelmfile-b.yaml
selectors:
- app=b
- path: subhelmfile-c.yaml
selectors:
- app=c
@@ -0,0 +1,15 @@
releases:
- name: release-a
chart: ../../../charts/raw
labels:
app: a
values:
- templates:
- |
apiVersion: v1
kind: ConfigMap
metadata:
name: release-a
namespace: {{ .Release.Namespace }}
data:
group: a
@@ -0,0 +1,15 @@
releases:
- name: release-b
chart: ../../../charts/raw
labels:
app: b
values:
- templates:
- |
apiVersion: v1
kind: ConfigMap
metadata:
name: release-b
namespace: {{ .Release.Namespace }}
data:
group: b
@@ -0,0 +1,15 @@
releases:
- name: release-c
chart: ../../../charts/raw
labels:
app: c
values:
- templates:
- |
apiVersion: v1
kind: ConfigMap
metadata:
name: release-c
namespace: {{ .Release.Namespace }}
data:
group: c
@@ -0,0 +1,49 @@
# Integration test for issue #2596: Local dependencies with multiple release files
# https://github.com/helmfile/helmfile/issues/2596
# Reproduction: https://github.com/vgivanov/helmfile-deps-local-chart
#
# This test uses the exact same structure as the reproduction repo:
# chart/Chart.yaml
# helmfile.d/release1.yaml (chart: ../chart with dependencies)
# helmfile.d/release2.yaml (chart: ../chart without dependencies)
#
# Before the fix, running `helmfile template` from this directory would fail with:
# "failed reading adhoc dependencies: no helm list entry found for repository"
# because the relative dependency chart path "../chart" was not normalized against
# basePath before calling DirectoryExistsAt.
issue_2596_input_dir="${cases_dir}/issue-2596-local-deps-multiple-files/input"
issue_2596_tmp=""
cleanup_issue_2596() {
if [ -n "${issue_2596_tmp}" ] && [ -d "${issue_2596_tmp}" ]; then
rm -rf "${issue_2596_tmp}"
fi
}
trap cleanup_issue_2596 EXIT
issue_2596_tmp=$(mktemp -d)
helmfile_real="$(pwd)/${helmfile}"
test_start "issue #2596: local deps with multiple release files"
info "Testing helmfile template with local chart dependencies across multiple release files"
cd "${issue_2596_input_dir}"
${helmfile_real} template > "${issue_2596_tmp}/output.yaml" 2>&1
result=$?
cd - > /dev/null
if [ $result -ne 0 ]; then
cat "${issue_2596_tmp}/output.yaml"
fail "helmfile template with local chart dependencies should not fail"
fi
info "Local chart dependencies with multiple release files works correctly"
cleanup_issue_2596
trap - EXIT
test_pass "issue #2596: local deps with multiple release files"
@@ -0,0 +1,24 @@
apiVersion: v2
name: chart
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"
@@ -0,0 +1,8 @@
---
releases:
- name: release1
chart: ../chart
version: "*"
dependencies:
- chart: ../chart
version: "*"
@@ -0,0 +1,5 @@
---
releases:
- name: release2
chart: ../chart
version: "*"
@@ -0,0 +1,75 @@
# Issue #2599: Test that defaultInherit applies template inheritance to all releases
# https://github.com/helmfile/helmfile/issues/2599
#
# This test verifies that:
# - defaultInherit as a single string applies the template to all releases
# - Releases without explicit inherit still get the template
# - Releases with explicit inherit + except are not duplicated
# - Non-existent template in defaultInherit produces a clear error
issue_2599_input_dir="${cases_dir}/issue-2599-default-inherit/input"
issue_2599_tmp=""
cleanup_issue_2599() {
if [ -n "${issue_2599_tmp}" ] && [ -d "${issue_2599_tmp}" ]; then
rm -rf "${issue_2599_tmp}"
fi
}
trap cleanup_issue_2599 EXIT
issue_2599_tmp=$(mktemp -d)
test_start "issue 2599 default inherit"
# Test 1: defaultInherit applies template to all releases
info "Running helmfile build with defaultInherit"
${helmfile} -f "${issue_2599_input_dir}/helmfile.yaml" build \
> "${issue_2599_tmp}/output.log" 2>&1 \
|| { cat "${issue_2599_tmp}/output.log"; fail "helmfile build with defaultInherit shouldn't fail"; }
# Verify namespace from template is applied to both releases
grep -q "namespace: default-ns" "${issue_2599_tmp}/output.log" \
|| fail "namespace from default template should be applied"
# Verify both releases are processed
grep -q "app1" "${issue_2599_tmp}/output.log" \
|| fail "release app1 should be in output"
grep -q "app2" "${issue_2599_tmp}/output.log" \
|| fail "release app2 should be in output"
grep -q "^templates:" "${issue_2599_tmp}/output.log" \
|| fail "templates section should be in build output"
# Verify inherited values and labels per release
sed -n '/name: app1/,/name: app2/p' "${issue_2599_tmp}/output.log" > "${issue_2599_tmp}/app1.log"
sed -n '/name: app2/,/^templates:/{/^templates:/!p}' "${issue_2599_tmp}/output.log" > "${issue_2599_tmp}/app2.log"
[ -s "${issue_2599_tmp}/app1.log" ] || fail "failed to extract release app1 section from build output"
[ -s "${issue_2599_tmp}/app2.log" ] || fail "failed to extract release app2 section from build output"
grep -Eq 'managed:[[:space:]]*"?true"?([[:space:]]|$)' "${issue_2599_tmp}/app1.log" \
|| fail "release app1 should inherit managed label from default template"
grep -q "common.yaml" "${issue_2599_tmp}/app1.log" \
|| fail "release app1 should inherit values from common.yaml"
grep -q "common.yaml" "${issue_2599_tmp}/app2.log" \
|| fail "release app2 should inherit values from common.yaml"
if grep -Eq 'managed:[[:space:]]*"?true"?([[:space:]]|$)' "${issue_2599_tmp}/app2.log"; then
fail "release app2 should not inherit managed label due to except"
fi
# Test 2: non-existent template in defaultInherit should fail
info "Running helmfile build with non-existent defaultInherit template"
cat > "${issue_2599_tmp}/bad-helmfile.yaml" <<EOF
defaultInherit: nonexistent
releases:
- name: app1
chart: ${dir}/charts/raw
EOF
${helmfile} -f "${issue_2599_tmp}/bad-helmfile.yaml" build \
> "${issue_2599_tmp}/error.log" 2>&1 \
&& fail "helmfile build with non-existent defaultInherit template should fail"
grep -q "inexistent release template" "${issue_2599_tmp}/error.log" \
|| fail "error message should mention inexistent release template"
test_pass "issue 2599 default inherit"
@@ -0,0 +1 @@
testKey: testValue
@@ -0,0 +1,19 @@
templates:
default:
namespace: default-ns
labels:
managed: "true"
values:
- common.yaml
defaultInherit: default
releases:
- name: app1
chart: ../../../charts/raw
- name: app2
chart: ../../../charts/raw
inherit:
- template: default
except:
- labels
@@ -0,0 +1,25 @@
postrender_defaults_args_case_input_dir="${cases_dir}/postrender-defaults-args/input"
postrender_defaults_args_case_output_dir="${cases_dir}/postrender-defaults-args/output"
# Helm 4 requires post-renderers to be plugins
if [ "${HELMFILE_HELM4}" = "1" ]; then
info "Installing echo-args post-renderer plugin for Helm 4"
${helm} plugin uninstall echo-args &>/dev/null || true
${helm} plugin install ${postrender_defaults_args_case_input_dir}/helm-plugin-echo-args ${PLUGIN_INSTALL_FLAGS} || fail "Failed to install echo-args plugin"
fi
config_file="helmfile.yaml.gotmpl"
postrender_defaults_args_tmp=$(mktemp -d)
test_start "postrender-defaults-args template"
info "Running helmfile template with helmDefaults.postRendererArgs containing {{ .Release.Name }}"
${helmfile} -f ${postrender_defaults_args_case_input_dir}/${config_file} template --concurrency 1 &> ${postrender_defaults_args_tmp}/template.out || fail "\"helmfile template\" shouldn't fail"
info "Verifying that helmDefaults.postRendererArgs were templated with release names"
grep -q "name: rendered-arg-foo" ${postrender_defaults_args_tmp}/template.out || fail "Expected postRendererArg 'foo' for release foo, but not found in output"
grep -q "name: rendered-arg-bar" ${postrender_defaults_args_tmp}/template.out || fail "Expected postRendererArg 'bar' for release bar, but not found in output"
info "Verifying that literal template expression was NOT passed"
grep -q "rendered-arg-{{ .Release.Name }}" ${postrender_defaults_args_tmp}/template.out && fail "Template expression was NOT rendered (found literal {{ .Release.Name }})"
test_pass "postrender-defaults-args template"
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
arg=$1
cat
echo "---"
cat <<EOS
apiVersion: v1
kind: ConfigMap
metadata:
name: rendered-arg-${arg}
data:
arg: ${arg}
EOS
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -e
arg=$2
input=$(cat)
echo "$input"
echo "---"
cat <<EOS
apiVersion: v1
kind: ConfigMap
metadata:
name: rendered-arg-${arg}
data:
arg: ${arg}
EOS
@@ -0,0 +1,10 @@
apiVersion: v1
type: postrenderer/v1
name: echo-args
version: 0.1.0
runtime: subprocess
runtimeConfig:
platformCommand:
- command: ${HELM_PLUGIN_DIR}/echo-args.sh
args:
- ${HELM_POST_RENDERER_ARGS}
@@ -0,0 +1,30 @@
helmDefaults:
postRenderer: {{ if eq (env "HELMFILE_HELM4") "1" }}echo-args{{ else }}./echo-args.bash{{ end }}
postRendererArgs:
- "{{ `{{ .Release.Name }}` }}"
releases:
- name: foo
chart: ../../../charts/raw
values:
- templates:
- |
apiVersion: v1
kind: ConfigMap
metadata:
name: {{`{{ .Release.Name }}`}}-1
namespace: {{`{{ .Release.Namespace }}`}}
data:
foo: FOO
- name: bar
chart: ../../../charts/raw
values:
- templates:
- |
apiVersion: v1
kind: ConfigMap
metadata:
name: {{`{{ .Release.Name }}`}}-2
namespace: {{`{{ .Release.Namespace }}`}}
data:
bar: BAR
@@ -9,6 +9,7 @@ data:
name: cm2
metadata:
name: cm2
---
# Source: raw/templates/resources.yaml
apiVersion: v1
@@ -28,6 +29,7 @@ data:
name: cm1
metadata:
name: cm1
---
# Source: raw/templates/resources.yaml
apiVersion: v1
@@ -10,6 +10,7 @@ data:
name: cm2
metadata:
name: cm2
---
# Source: raw/templates/resources.yaml
apiVersion: v1
@@ -29,6 +30,7 @@ data:
name: cm1
metadata:
name: cm1
---
# Source: raw/templates/resources.yaml
apiVersion: v1