Generated with Changesmith based on git history and release tags.
Covers v1.4.1 to v1.4.0 to v1.3.2 to v1.3.1.
Signed-off-by: MrPhil (Philip Ludington) <mrphil@mrphilgames.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>
* Add IP Network to supported HCL Functions
This patch adds CIDR functions from the `go-cty-funcs` package to
supported HCL functions
Signed-off-by: Oleh Neichev <oleg.neichev@gmail.com>
* Test HCL CIDR Functions
Signed-off-by: Oleh Neichev <oleg.neichev@gmail.com>
---------
Signed-off-by: Oleh Neichev <oleg.neichev@gmail.com>
* fix: use absolute baseDir in sequential helmfiles for correct values path resolution (#2424)
PR #2410 introduced a regression where a relative directory was passed as
baseDir instead of an absolute one, causing values and secrets file paths
to resolve incorrectly when using --sequential-helmfiles with helmfile.d/.
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
* fix: mirror reporter's bases/templates/inherit setup in issue-2424 integration test
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
---------
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
When no repositories are defined in helmfile.yaml, local charts with
external dependencies need to refresh the repo cache. Previously, we
always passed --skip-refresh to helm dep build, which broke this case.
Now --skip-refresh is only passed when we actually ran helm repo update,
meaning repos are configured AND no skip refresh flags are set. This
preserves the precomputed skipRefresh value from prepareChartForRelease
which accounts for CLI flags, helmDefaults.skipRefresh, and release.skipRefresh.
Fixes#2417
Signed-off-by: yxxhero <aiopsclub@163.com>
When using only OCI repositories, helmfile would attempt to run
'helm repo update' which fails with 'no repositories found' error.
OCI repositories don't need 'helm repo update' as they use
'helm registry login' instead.
This fix adds a HasNonOCIRepositories() helper function and uses it
to determine whether to run 'helm repo update'.
Fixes#2418
Signed-off-by: yxxhero <aiopsclub@163.com>
* feat: allow for HCL values override
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* fix: ensure overriden HCL expression uses range from latest defined block vars
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: implement HCL cty values override tests
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* docs: better describe new behavior
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* fix: add extra parenthesis for better readability
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: implement variable override in decodeGraph() function, AFTER interpolation, providing back access to hv.* and local.* accessors
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: implement better HCL test to override values using local.* and hv.* accessors and pre-processing function calls
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: remove deprecated hclParseError() function (and test)
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: don't let HCL override with null value win
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: proper test condition on HCL map type merge (and tests)
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: more accurate HCL test error statement
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: ensure HCL DAG graph collects dependencies from ALL definitions to ensure proper evaluation order even if only earlier definitions have dependencies
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: verify HCL mixed-types merges are correctly supported
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* docs: improved environment values precedence section with HCL override support
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: HCL test spell-check, linter failure
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: implement HCL override e2e tests
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* fix: correct hcl_loader test error message
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* fix: ensure correct cty type is returned in case of object/map hcl merge
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* fix: ensure hcl locals from a previous definition/file do not leak into this evaluation when merging
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* fix: correct e2e hcl_override test; missing line in output string comparison
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* docs: spell-check on HCL doc
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
* chore: update comment for accuracy in HCL read routine
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
---------
Signed-off-by: Benjamin Zores <benjamin.zores@gmail.com>
Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com>
fix: helmDefaults.skipRefresh ignored in runHelmDepBuilds (#2269)
`runHelmDepBuilds()` only checked the CLI flag (`opts.SkipRefresh`) when
deciding whether to run `helm repo update` before building dependencies.
This meant that setting `helmDefaults.skipRefresh: true` in helmfile.yaml
had no effect on the repo update call inside dep builds.
Add `!st.HelmDefaults.SkipRefresh` to the guard condition so that
`helmDefaults.skipRefresh: true` is respected alongside the CLI flag.
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
* fix: eliminate os.Chdir in sequential helmfiles to fix relative path resolution
The sequential code path used within() → os.Chdir() to change the
process-wide working directory when processing helmfile.d files.
This broke relative environment variable paths (e.g. KUBECONFIG=kubeconfig.yaml)
because they resolved from the wrong directory after chdir.
Replace the chdir-based approach with the same baseDir parameter pattern
used by the parallel code path, passing explicit directory context through
loadDesiredStateFromYamlWithBaseDir() instead of mutating global process state.
Closes#2409
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
* fix: restore within() for single-file sequential to preserve chart path format
The previous approach used baseDir for all sequential processing, which
changed chart path format in output (e.g. from "../../../../charts/raw"
to "test/integration/charts/raw"). This broke integration tests that
compare chart paths in expected output.
Now the sequential branch uses two strategies:
- Single file: use os.Chdir via within() to preserve backward-compatible
relative chart paths in output
- Multiple files with --sequential-helmfiles: use baseDir parameter to
avoid os.Chdir, fixing relative env var paths like KUBECONFIG (#2409)
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
* fix: revert e2e snapshot outputs to match within() behavior
The previous commit restored within() for single-file sequential
processing, which produces relative chart paths (e.g. ../../charts/raw)
and filename-only FilePath. Revert the e2e snapshot expected outputs
to match main branch since single-file behavior is now identical.
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
* fix: restructure integration test for multi-file sequential processing
- Point -f at helmfile.d/ directly (not parent dir) so findDesiredStateFiles
discovers the yaml files
- Add second helmfile to trigger baseDir path (len > 1)
- Inline environment config to avoid base file relative path issues
- Verify both releases appear in output instead of comparing with parallel
(which may differ in ordering)
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
* fix: reduce cognitive complexity and improve accuracy of sequential helmfiles
Replace inline visitSubHelmfiles closure with calls to the existing
processNestedHelmfiles() method, matching the parallel path. This
eliminates duplicated nested logic and reduces gocognit complexity
below the CI threshold of 110. Also fixes help text and docs to
accurately describe that single-file processing still uses within(),
and adds kubeContext verification to the integration test.
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
* test: validate kubeContext resolution in sequential helmfiles integration test
Restructure the integration test to replicate the exact user scenario
from issue #2409:
- Multiple files in helmfile.d/ using bases: with relative paths
(../bases/) for environments and defaults
- Environment values set kubeContext via .Environment.Values
- helmDefaults.kubeContext rendered from gotmpl
- Local chart references (../../../../charts/raw) from helmfile.d/
- Run diff against the minikube cluster to exercise kubeContext
resolution, which would fail with "context does not exist" if
os.Chdir() broke relative path resolution
- Also verify template output for both releases and relative values
file (values/common.yaml) resolution
Fix normalizeChart() in util.go to be idempotent — skip re-prefixing
when the chart path already starts with basePath. This prevents
double-prefixing of local chart paths (e.g. helmfile.d/test/.../raw)
when normalizeChart is called multiple times (once during chart
preparation and again during diff/sync).
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
---------
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
* fix: helmBinary setting ignored in multi-document YAML files
The helmBinary setting in helmfile.yaml was being ignored when using
multi-document YAML files (files with --- separators).
Root Cause:
When processing multi-document YAML files, the load() function splits
the file into parts and processes each part separately. Each part was
calling applyDefaultsAndOverrides() which would set an empty helmBinary
to the default 'helm'. When merging parts, the default value from a
later part would override the correct value from an earlier part.
Fix:
- Added a new applyDefaults parameter to ParseAndLoad() to control when
defaults are applied
- Modified rawLoad() to pass applyDefaults=false when processing
individual parts
- Added a call to ApplyDefaultsAndOverrides() after all parts are merged
to apply defaults once on the final merged state
- Exported ApplyDefaultsAndOverrides() method for use by the app package
Fixes: #2319
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: update comment per PR review
Change 're-apply' to 'apply' since defaults are never applied during
part processing (applyDefaults=false is passed), so this is the first
and only time defaults are applied to the merged state.
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: clarify applyDefaults logic in test LoadFile callbacks
Add explicit applyDefaults variable with comment explaining why it
equals evaluateBases: base files shouldn't apply defaults, only the
main file should after all parts/bases are merged.
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: address PR review comments
- Remove applyDefaults parameter from rawLoad() since it's always false
- Add regression test for multi-document YAML with helmBinary (issue #2319)
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: add integration test for helmBinary in multi-document YAML
Add TestHelmBinaryPreservedInMultiDocumentYAML that exercises the full
loadDesiredStateFromYaml path to ensure helmBinary from the first
document is preserved when merging multi-document YAML files.
This is a regression test at the load() orchestration level for issue #2319.
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: support XDG-style multiple paths in HELM_PLUGINS
Use filepath.SplitList to properly handle XDG-style paths with multiple
directories (e.g., HELM_PLUGINS=/path/one:/path/two) when looking up
plugin versions. Previously, the code only scanned a single directory.
Fixes#2411
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: address PR review comments for XDG plugins path support
- Track and return first non-IsNotExist error from os.ReadDir
- Skip empty path elements from filepath.SplitList
- Use os.PathListSeparator for cross-platform test compatibility
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
toCLIError() panics on unhandled error types (e.g. helmexec.ExitError
from a failed helm plugin install). On Windows, plugin install hooks
often fail due to missing 'sh', causing helmfile init to crash even
when the plugin binary was placed correctly.
- Add helmexec.ExitError case to toCLIError and replace panic in the
default case with a graceful error return
- After AddPlugin/UpdatePlugin errors, verify whether the plugin is
actually present before failing; log a warning and continue if so
Fixes#1983
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
Adds a new `helmfile unittest` command that integrates the helm-unittest
plugin, allowing users to define unit test paths per release and run them
via helmfile.
Closes#2376
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
* feat: support .Environment.* in --output-dir-template
This commit adds support for accessing environment values in the --output-dir-template flag.
Previously, users could only access .OutputDir, .State.*, and .Release.* in the template.
Now .Environment.* is also available, allowing users to use environment values in the
output directory path.
Example usage:
helmfile template -e test-1 --output-dir-template='{{ .OutputDir }}/{{ .Environment.cluster.name }}/{{ .Environment.Name }}/{{ .Release.Name }}'
This produces output like: ./gitops/my-test-cluster/test-1/release-name/
Changes:
- Add Environment field to GenerateOutputDir template data
- Add Environment field to generateChartPath template data (now a method on HelmState)
- Update help text for --output-dir-template flag in template and fetch commands
- Add test cases for Environment in template
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: address PR review comments for --output-dir-template
- Clarify .Environment.Name, .Environment.KubeContext, .Environment.Values.* in help text
- Update generateChartPath comment to reflect broader usage (fetch, pull, OCI)
- Add tests for GenerateOutputDir with Environment fields
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: address additional PR review comments
- Move HelmState setup outside test loop to reduce duplication
- Document Environment field (.Name, .KubeContext, .Values) in template data structs
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: skip cache refresh for shared cache paths to prevent race conditions
When multiple helmfile processes run in parallel (e.g., as ArgoCD plugin),
they share the same OCI chart cache in ~/.cache/helmfile. One process could
delete and re-download (refresh) a cached chart while another process was
still using it, causing "path not found" errors.
This fix:
- Adds isSharedCachePath() helper to detect shared cache paths
- Skips chart deletion/refresh for paths in the shared cache directory
- Users can force refresh by running `helmfile cache cleanup` first
Fixes#2387
Signed-off-by: yxxhero <aiopsclub@163.com>
* docs: document OCI chart caching behavior and multi-process safety
Add documentation for:
- OCI chart cache location and behavior
- How to force cache refresh with `helmfile cache cleanup`
- Multi-process safety when using shared cache
- Cache management commands (info, cleanup)
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: address review comments for shared cache handling
- Return error instead of chartActionDownload for corrupted shared cache
- Change refresh skip log from Debugf to Infof for user visibility
- Add t.Helper() to createTestLogger test helper
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: handle symlinks and add debug logging in isSharedCachePath
- Use filepath.EvalSymlinks to resolve symlinks before path comparison
- Add debug logging when filepath.Abs fails
- Add test case for symlink to shared cache directory
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: address copilot review comments
- Include underlying error in corrupted cache error message
- Add cleanup for test directories created in shared cache
- Clarify --skip-refresh flag documentation
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: handle edge case when chartPath equals sharedCacheDir
- isSharedCachePath now returns true for exact match with cache dir
- Add test case for exact match with shared cache directory
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: add integration test for acquireChartLock shared cache behavior
Add TestAcquireChartLockSharedCacheSkipRefresh to verify that
acquireChartLock returns chartActionUseCached instead of
chartActionRefresh when the chart exists in the shared cache,
even when refresh is requested. This tests the core fix for
the race condition issue #2387.
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: include query params in HTTP getter cache key (#2103)
When helmfile caches remote HTTP files fetched via the "normal" getter
(plain https:// URLs without a git:: prefix), the cache key did not
include query parameters. This caused URLs that differ only in query
params (e.g. ?ref=commit1 vs ?ref=commit2) to share the same cache
directory, silently returning the wrong file version.
The root cause was in Fetch() where the "normal" getter branch
overwrote the cache key with only scheme + host, discarding query
params that were correctly computed earlier.
Fix: extract the query-params suffix into a reusable variable and
apply it in both the default and "normal" getter cache key paths.
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
* Update pkg/remote/remote.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
* Update pkg/remote/remote_test.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
---------
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
fix: support OCI chart digest syntax in chart URLs and version fields
Helm supports pinning OCI chart images by digest (@sha256:...), version
tag (:version), or both (:version@sha256:digest) since helm/helm#12690.
Helmfile failed to parse these formats, incorrectly constructing helm
commands and losing version/digest information embedded in chart URLs.
Root causes:
- resolveOciChart() used last ":" to find version tag, but sha256:abc
contains ":", so digest URLs were split incorrectly
- getOCIQualifiedChartName() included :version and @digest in chartName
with no parsing of either source
- appendChartVersionFlags() passed release.Version verbatim to --version
flag, including any digest suffix
- ChartPull() discarded the tag from resolveOciChart but did not
preserve digest in the URL
This commit adds parseOCIChartRef() and parseVersionDigest() utilities,
then updates the OCI chart handling pipeline so that:
- Digests are preserved in the chart URL passed to helm pull
- Version tags are extracted cleanly for the --version flag
- Both chart URL and version field are parsed for version/digest info
Fixes#2097
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>
Add filepath.IsAbs guard to IsRemote and Parse to prevent Windows drive
letter paths (e.g., C:\path) from being misinterpreted as remote URLs
by go-getter's url.Parse, which prepends file:// to drive letter paths.
Fixes#2384
Signed-off-by: Aditya Menon <amenon@canarytechnologies.com>