After ApplyOverrides/reformat(), need IDs are already fully-qualified
(matching ReleaseToID format). The nameToID map was doing redundant
name-based lookups that could theoretically select the wrong dependency
when multiple releases share the same name across namespaces (same issue
fixed in collectDirectNeedsOnly in 02a5de3). Reverted to the original
behavior of passing need IDs as-is.
Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com>
Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/7b896c61-ba38-4471-942a-784e79fab298
* feat: Refactor TestRewriteChartDependencies
Signed-off-by: Etienne Champetier <e.champetier@ateme.com>
* fix: keep all chart dependencies key / values
In rewriteChartDependencies we were only parsing name / repository / version,
thus dropping keys like condition / import-values.
This at least fixes the use of condition.
Signed-off-by: Etienne Champetier <e.champetier@ateme.com>
---------
Signed-off-by: Etienne Champetier <e.champetier@ateme.com>
* fix: helmfile fetch fails for kustomization directories
Fixes#2503
When running `helmfile fetch` on a release that points to a local
kustomization directory (without Chart.yaml), the command failed with
"Chart.yaml is missing".
The issue was that the condition `helmfileCommand != "pull"` in
prepareChartForRelease skipped chartification for ALL cases during
fetch, including local kustomization directories that NEED chartify
to convert them to Helm charts.
Solution:
- Added `NeedsChartifyForLocalDir` field to the Chartify struct to
track when chartification is needed because the local directory
is not a Helm chart (no Chart.yaml)
- Modified the condition to skip chartification for "pull" ONLY when
it's not a local directory without Chart.yaml
This preserves the original fix (commit 1f134d93) for remote charts
with transformers while fixing local kustomization directories.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: add integration test for helmfile fetch with kustomization
Add test case for issue #2503 to verify helmfile fetch works correctly
with local kustomization directories (without Chart.yaml).
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
After ApplyOverrides/reformat(), need IDs are already fully-qualified
(matching ReleaseToID format). The previous name-based lookup could
select the wrong dependency when multiple releases share the same name
across namespaces/kubecontexts.
Also adds a cross-namespace test case to verify correct behavior when
releases share names across different namespaces.
Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com>
Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/e8effb99-17de-4b2e-ae14-cc90c2108146
- In withNeeds second withDAG call, set SkipNeeds when needs are already
included (instead of using IncludeNeeds which causes DAG to pull in
transitive deps). This is the key fix for --include-needs only including
direct dependencies.
- In GroupReleasesByDependency, use WithDependencies from opts.IncludeNeeds
only when SelectedReleases is explicitly provided (withDAG path).
When using the Filtered flag path, needs are already handled by
markExcludedReleases.
- Regenerate test snapshots to reflect correct behavior where
--include-needs excludes transitive dependencies.
- Restore diff_test.go and diff_nokubectx_test.go from main for
non-include-needs test cases.
Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com>
Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/170cecc0-7a3e-4326-98d3-4f2bffee1848
The root cause of the CI failure was that GroupReleasesByDependency was changed
to use !r.Filtered instead of opts.SelectedReleases for the DAG plan's Only field.
When no selectors are active (like helmfile destroy), all releases are unfiltered,
causing all releases to be planned for deletion - including uninstalled ones.
Fix: Use opts.SelectedReleases when provided, fall back to Filtered flag otherwise.
Also remove unnecessary SelectedReleases block from PlanReleases since
GroupReleasesByDependency now handles it directly.
Restore test snapshots from main as the behavior should now match.
Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com>
Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/170cecc0-7a3e-4326-98d3-4f2bffee1848
* fix: error on missing secret key when using vals
Add HELMFILE_VALS_FAIL_ON_MISSING_KEY_IN_MAP environment variable
to control whether vals should fail when a referenced key does not
exist in the secret map.
Previously, when a secret reference like ref+vault://path#/nonexistent-key
pointed to a non-existent key, vals would silently return an empty string
without error. This could lead to deployments with missing configuration.
Default behavior remains backward compatible (returns empty string).
Set HELMFILE_VALS_FAIL_ON_MISSING_KEY_IN_MAP=true to enable strict mode.
Fixes#1563
Signed-off-by: yxxhero <aiopsclub@163.com>
* refactor: extract buildValsOptions helper and improve tests
- Extract buildValsOptions() to make vals configuration testable
- Use t.Setenv instead of manual env save/restore in tests
- Test actual vals.Options output including FailOnMissingKeyInMap
Addresses PR review comments on #2496
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: use strconv.ParseBool and make tests hermetic
- Use strconv.ParseBool for FailOnMissingKeyInMap parsing to support
common boolean values like 'TRUE', '1', '0', etc.
- Always set env vars explicitly in tests (even to empty string) to
prevent flaky tests when env vars are set externally
- Add test cases for various boolean formats
Signed-off-by: yxxhero <aiopsclub@163.com>
* docs: add documentation for vals-related environment variables
Add documentation for:
- HELMFILE_AWS_SDK_LOG_LEVEL: configure AWS SDK logging for vals
- HELMFILE_VALS_FAIL_ON_MISSING_KEY_IN_MAP: enable strict mode for secret refs
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: improve error handling and case-insensitive comparison
- buildValsOptions now returns error for invalid boolean values
instead of silently defaulting to false
- Use strings.EqualFold for case-insensitive 'off' comparison
to handle OFF, Off, etc.
- Add test cases for invalid boolean and uppercase OFF
- Update docs to mention case-insensitive and error behavior
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: normalize log level and improve singleton initialization
- Normalize AWS log level 'off' to lowercase for true case-insensitivity
- Replace sync.Once with mutex to allow recovery from config errors
- Update tests to expect normalized 'off' value
- Update docs to clarify when error is raised
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: helmfile list now reflects version from helmfile.lock
The list command now resolves locked dependencies before returning
release information, ensuring the version field reflects the pinned
version from helmfile.lock when present.
Fixes#1953
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: address PR review comments
- Remove redundant maps.Copy in list() - labels already merged by GetReleasesWithLabels()
- Fix default lockfile path to use basePath for multi-file mode
- Update test to expect basePath-joined lockfile path
- Add multi-file test for lockfile resolution in helmfile.d directory
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix more test
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix tests
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: propagate errors instead of panic in list()
When skipCharts=false, errors from list() now properly propagate instead
of causing a crash. Uses a closure variable to capture the error and
propagates it after withPreparedCharts completes.
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix tests
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix tests
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix tests
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
This commit makes the apply logic exit early in the event there are no
changes to releases. I believe this effectively reverts helmfile#522.
Updates relevant snapshots
Clarify conditions under which preapply hooks are triggered to include that they will no longer fire if there is a no-op.
Docs as requested by the maintainer from a copilot request made by them.
Fixes: helmfile#679
Signed-off-by: Thomas Arrow <thomas.arrow@wikimedia.de>
Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com>
When a release with 'installed: false' appears multiple times in the release list
(due to duplicate entries or being included via needs), the isReleaseInstalled
function was being called multiple times for the same release, resulting in
duplicate 'Listing releases' log messages.
This fix adds a deduplication check using a 'checked' map to ensure each release
is only checked once, preventing duplicate helm list calls and log messages.
This fixes the diff-args integration test where 'Listing releases matching
^uninstalled$' appeared twice in stderr output.
Signed-off-by: yxxhero <aiopsclub@163.com>
When running helmfile diff with releases that have 'installed: false',
(flagging them as to-be-uninstalled), the release was being disabled
flag would be included in toRender. Later, these disabled releases were
added again via releasesToUninstall when includeDisabled is true,
causing them to appear twice in the final releases list.
This resulted in duplicate 'Listing releases' log messages and
potentially duplicate helm list calls.
The fix filters out disabled releases from toRender before passing it
to withDAG. This ensures disabled releases are only included once
in the final list (via releasesToUninstall at line 2378-2382).
Fixes the test failure in test/integration/test-cases/diff-args
where 'Listing releases matching ^uninstalled$' appeared twice
instead of once.
Note: diff-live-stderr still shows two messages because that test
was updated separately to match that behavior (with trailing spaces).
The non-live diff should now correctly shows only one message.
Signed-off-by: yxxhero <aiopsclub@163.com>
- Fix collectDirectNeedsOnly to correctly match needs by full ID
- Fix PlanReleases to respect SelectedReleases when provided
- Fix unmarkNeedsDirectOnly to use full release IDs
- Update tests to expect correct behavior for include-needs vs include-transitive-needs
- Add SkipNeeds flag when needs are pre-included in withNeeds
This fixes CI issues in PR #2485
Signed-off-by: yxxhero <aiopsclub@163.com>
The withNeeds function was calling getSelectedReleases with false, false
for includeNeeds and includeTransitiveNeeds, which caused it to ignore
the --include-needs and --include-transitive-needs flags.
This fix:
1. Computes includeNeeds before calling getSelectedReleases
2. Passes the correct flags to getSelectedReleases
3. Sets st.Releases to selectedAndNeededReleases instead of deduplicated
4. Passes IncludeNeeds=false and IncludeTransitiveNeeds=false to PlanReleases
since the needs are already included in selectedReleases
Signed-off-by: yxxhero <aiopsclub@163.com>
- Add IncludeNeeds to diff, template, lint, unittest, sync, apply ChartPrepareOptions
- All ConfigProviders already have DAGConfig embedded which includes IncludeNeeds()
Signed-off-by: yxxhero <aiopsclub@163.com>
- Add IncludeNeeds() to WriteValuesConfigProvider interface
- Implement IncludeNeeds() in WriteValuesImpl
- Update WriteValues function to use IncludeNeeds and IncludeTransitiveNeeds
Signed-off-by: yxxhero <aiopsclub@163.com>
- Add IncludeNeeds() to DepsConfigProvider and ReposConfigProvider
- Update depsConfig in tests
- Use c.IncludeNeeds() in run.go instead of hardcoded false
Signed-off-by: yxxhero <aiopsclub@163.com>
- Add IncludeNeeds() method to DepsConfigProvider interface
- Implement IncludeNeeds() in DepsImpl
- Update depsConfig in tests
- Use c.IncludeNeeds() in run.go instead of hardcoded false
Signed-off-by: yxxhero <aiopsclub@163.com>
Fixes#1003
Previously, --include-needs was incorrectly including transitive
dependencies (dependencies of dependencies). This fix ensures that:
- --include-needs only includes direct needs
- --include-transitive-needs includes both direct and transitive needs
Changes:
- Add separate handling for direct vs transitive needs in state.go
- Add IncludeNeeds field to ChartPrepareOptions
- Add unmarkNeedsDirectOnly() and collectDirectNeedsOnly() functions
- Update ForEachState and related functions to accept both flags
- Fix incorrect usage of c.IncludeNeeds() for IncludeTransitiveNeeds
- Update tests to verify the correct behavior
Signed-off-by: yxxhero <aiopsclub@163.com>
* feat: add --force-conflicts flag support for Helm 4
Add support for Helm 4's --force-conflicts flag which forces server-side
apply changes against conflicts. This flag is mutually exclusive with
--force/--force-replace and only available in Helm 4.
Fixes#2429
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: address review comments on force-conflicts feature
- Fix comment grammar: 'forces' instead of 'force'
- Improve error messages to indicate both sources (releases[] and helmDefaults)
- Add test case for helmDefaults.forceConflicts with Helm 3 (should error)
- Update TestGenerateID expected hashes after adding ForceConflicts field to structs
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: use --force-replace flag for Helm 4 instead of deprecated --force
Helm 4 deprecated the --force flag in favor of --force-replace.
This fix detects the Helm version and uses the appropriate flag:
- Helm 4: --force-replace
- Helm 3: --force
Also fixed a nil pointer panic in appendHideNotesFlags when called
with nil SyncOpts.
Fixes#2476
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix(ci): pin semver to v2.12.0 for Go 1.25 compatibility
semver@latest requires Go 1.26.1 but the project uses Go 1.25.4.
Pinning to v2.12.0 which is compatible with Go 1.25.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: add test cases for force flag from defaults with nil release
Add test cases to cover the scenario where release.Force is nil and
HelmDefaults.Force enables force for both Helm 3 and Helm 4.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: add nil ops test and rename misleading test names
- Add test case for appendHideNotesFlags with ops=nil to prevent
regression
- Rename force-from-default-nil-release-* to
force-from-default-nil-force-* for clarity (release.Force is nil,
not the release itself)
Signed-off-by: yxxhero <aiopsclub@163.com>
* refactor: add explicit parentheses for force condition
Add explicit parentheses around the two disjuncts in the force
condition to make the intended grouping unambiguous and easier
to read.
Signed-off-by: yxxhero <aiopsclub@163.com>
* refactor: check ops nil before Helm version in appendHideNotesFlags
- Swap the order to check ops == nil first to avoid unnecessary
IsVersionAtLeast call
- Restore the "see Helm release" comment for consistency with other
flag helpers
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
PR #2367 introduced CLIOverrides to give --state-values-set element-by-element
array merge semantics. However, nested helmfile values (helmfiles[].values:)
were also routed into CLIOverrides, causing their arrays to merge instead of
replace. This broke the pre-v1.3.0 behavior where passing an array via
helmfiles[].values: would fully replace the child's default array.
Add OverrideValuesAreCLI flag to SubhelmfileEnvironmentSpec so the loader can
distinguish CLI flags from nested helmfile values. CLI values continue using
CLIOverrides (element-by-element merge); nested helmfile values now use Values
(Sparse merge strategy → full array replacement).
Fixes#2451
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
Add support for trackMode: helm-legacy to use Helm v4's --wait=legacy flag,
which maintains compatibility with Helm v3's wait behavior during migration.
Helm v4 changed the default --wait behavior from polling to a watcher-based
approach. This can cause issues with charts that have broken livenessProbe
configurations without startupProbe. The --wait=legacy flag preserves the
Helm v3 polling behavior for smoother migration.
Changes:
- Add TrackModeHelmLegacy constant in pkg/kubedog/options.go
- Use kubedog.TrackMode constants instead of raw strings in helmx.go
- Enhance appendWaitFlags to use --wait=legacy for Helm v4 when trackMode
is helm-legacy
- Add nil check for logger before logging warning
- Add version check with warning when helm-legacy is used with Helm v3
- Update validation in pkg/config to accept helm-legacy track mode
- Update command-line flags in cmd/apply.go and cmd/sync.go
- Add comprehensive documentation in docs/advanced-features.md
- Add thorough test coverage including warning message verification
Behavior:
- Helm v4 + helm-legacy: Uses --wait=legacy
- Helm v3 + helm-legacy: Falls back to --wait with warning
- Helm v4 + helm: Uses --wait (watcher mode)
- Any + kubedog: Skips --wait flag
Fixes#2464
Signed-off-by: yxxhero <aiopsclub@163.com>
Co-authored-by: Copilot <copilot@github.com>
When using jsonPatches or kustomize patches with helmfile, chartify runs
"helm template" internally to render the chart before applying patches.
The lookup() helm function requires cluster access (--dry-run=server).
Previously, --kubeconfig was passed to helm diff and helm upgrade commands,
but not to chartify's internal helm template call. This caused failures
when users specified --kubeconfig flag with a non-default kubeconfig location.
This fix ensures --kubeconfig is passed to chartify's TemplateArgs for
cluster-requiring commands (sync, apply, diff, etc.), alongside the existing
--kube-context and --dry-run=server flags.
Fixes#2444
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: local chart with external dependencies error when repos configured
When helm repo update was run, the code unconditionally set skipRefresh=true
for all builds, causing helm dep build --skip-refresh to fail for local charts
with external dependencies not listed in helmfile.yaml.
Now only non-local charts (precomputed skipRefresh=true) get --skip-refresh,
while local charts preserve their skipRefresh=false to allow refreshing repos
for external dependencies.
Fixes#2431
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: update snapshot tests for local chart refresh behavior
Local charts now run helm repo update during helm dep build to support
external dependencies not listed in helmfile.yaml (fixes#2431).
Signed-off-by: yxxhero <aiopsclub@163.com>
* refactor: remove redundant skipRefresh assignment
The condition 'if didUpdateRepo && r.skipRefresh { r.skipRefresh = true }'
was a no-op since setting true to true has no effect. The precomputed
skipRefresh value from prepareChartForRelease is already correct, so we
simply preserve it without modification.
Signed-off-by: yxxhero <aiopsclub@163.com>
* refactor: only call UpdateRepo when at least one build uses --skip-refresh
Avoid redundant helm repo update when all builds have skipRefresh=false,
as each helm dep build will refresh repos itself in that case.
Co-authored-by: Copilot <copilot@github.com>
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: update release_template_inheritance snapshot for skipRefresh optimization
UpdateRepo is now only called when at least one build uses --skip-refresh,
so local charts without skipRefresh no longer trigger the global repo update.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: add regression test for issue #2431
Add TestIssue2431_LocalChartWithExternalDependency to verify that local
charts with external dependencies on repos NOT in helmfile.yaml work
correctly. The test ensures:
- UpdateRepo is NOT called when all builds have skipRefresh=false
- helm dep build does NOT receive --skip-refresh flag
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: add integration test for issue #2431
Add test case to verify that local charts with repos configured in
helmfile.yaml work correctly. The test ensures that helmfile template
does not fail with 'no cached repository' or 'no repository definition'
errors when:
- helmfile.yaml has non-OCI repos configured
- Local chart is used (which may have external dependencies not in helmfile.yaml)
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: update issue #2431 integration test to match issue scenario
Add external dependency (karma chart from wiremind repo) to local chart's
Chart.yaml, matching the exact scenario described in issue #2431 where:
- helmfile.yaml has repos configured (vector)
- Local chart depends on a repo NOT in helmfile.yaml (wiremind)
Signed-off-by: yxxhero <aiopsclub@163.com>
* revert: remove unit tests and restore e2e snapshot outputs
Remove pkg/state/run_helm_dep_builds_skip_refresh_test.go and restore
chart_need snapshot outputs to original state. The fix is verified by
the integration test for issue #2431.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: remove snapshot outputs to regenerate them
Remove chart_need snapshot outputs so they can be regenerated by tests.
Signed-off-by: yxxhero <aiopsclub@163.com>
* revert: restore release_template_inheritance snapshot output
Signed-off-by: yxxhero <aiopsclub@163.com>
* restore: add back unit tests for skipRefresh behavior
Signed-off-by: yxxhero <aiopsclub@163.com>
* restore: add back chart_need snapshot outputs
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: update snapshot outputs for skipRefresh optimization
- Remove TestIssue2431_LocalChartWithExternalDependency unit test
- Update chart_need outputs: local chart runs helm dep build with repo refresh
- Update release_template_inheritance: no deps so no repo refresh output
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: update test comments and names per review feedback
- Update TestRunHelmDepBuilds_MultipleBuilds comment to remove reference
to removed didUpdateRepo variable
- Rename test case to accurately describe condition being tested
(build with skipRefresh=true instead of misleading 'non-local chart')
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
Co-authored-by: Copilot <copilot@github.com>