mirror of
https://github.com/helmfile/helmfile.git
synced 2026-09-30 13:27:18 +02:00
v1.5.4
501
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a94fdf4194 |
feat: add support for helm 4 --server-side upgrade flag (#2641)
* feat: add support for helm 4 --server-side upgrade flag Add support for the helm 4 upgrade flag --server-side which accepts "true", "false", or "auto" (default "auto"). This allows users to explicitly control server-side apply behavior, which is needed for releases originally installed with Helm 3 and being managed with Helm 4. The flag can be configured via: - CLI: --server-side flag on sync, apply, and diff commands - helmDefaults.serverSide in helmfile.yaml - releases[].serverSide per-release override Precedence: release-level > CLI flag > helmDefaults. Errors are returned when serverSide is set but running Helm 3, or when an invalid value is provided. Closes #2640 Signed-off-by: yxxhero <aiopsclub@163.com> * test: update TestGenerateID expected hashes for new ServerSide field Adding ServerSide *string to ReleaseSpec changes spew's %#v output and shifts the FNV hash used by generateValuesID. Update the hard-coded want values to the new deterministic hashes. Signed-off-by: yxxhero <aiopsclub@163.com> --------- Signed-off-by: yxxhero <aiopsclub@163.com> |
||
|
|
047fdcd17d |
build(deps): bump helm-diff to v3.15.9 (#2642)
Update helm-diff plugin version from v3.15.8 to v3.15.9 across Dockerfiles, recommended version constant, CI matrix, and integration test default. Signed-off-by: yxxhero <aiopsclub@163.com> |
||
|
|
6cf02956c2 |
Add App.WithFileSystem (#2638)
Signed-off-by: toyamagu-2021 <toyamagu2021@gmail.com> |
||
|
|
655399a03b |
Bump Helm support to 4.2.1 and 3.21.1 (#2635)
* chore: bump helm release pins * chore: align helm module metadata * chore: finalize helm patch bumps * fix: add --plain-http flag for Helm 3.21+ OCI push in tests Helm 3.21.1 introduced stricter security checks that reject HTTP scheme downgrades when pushing to OCI registries, with the error: "blob upload Location downgrades scheme from https" Previously only Helm 4 required --plain-http for HTTP-only OCI registries. Now Helm 3.21+ also requires this flag. Add a new requiresPlainHTTPForOCI() helper that returns true for both Helm 4.x and Helm 3.21+, and use it in execHelmPush() instead of isHelm4(). * fix: safe fallback in requiresPlainHTTPForOCI when version detection fails Default to true (require --plain-http) when helm version detection fails, since any Helm version that supports helm push also supports the --plain-http flag. This avoids the inconsistent HELMFILE_HELM4 env var fallback which only covered Helm 4. * fix: update snapshot tests for Helm 4.2.1 OCI pull output Helm 4.2.1 now outputs additional 'Pulled:' and 'Digest: sha256:...' lines after each OCI chart pull. The SHA256 digest is non-deterministic because helm packages include build timestamps, so normalize it with a regex placeholder. - Add ociDigestRegex to normalize non-deterministic OCI digest values - Create output-helm4.yaml for 5 tests that lacked Helm 4 snapshots - Update output-helm4.yaml for oci_need and postrenderer to include the new Pulled/Digest lines from Helm dependency pull operations * fix: update ociDigestRegex to match empty digest in Helm 4.2.1 OCI pull output Helm 4.2.1 outputs "Digest: sha256:" (empty hash) when pulling OCI charts. The regex required at least one hex char ([0-9a-f]+), so it did not match and the digest was not normalized to $DIGEST in snapshot tests. Also fix the replacement string: Go regex ReplaceAllString interprets $DIGEST as a capture group reference (resolving to empty). Use $$DIGEST to produce a literal $DIGEST in the output. Signed-off-by: yxxhero <aiopsclub@163.com> --------- Signed-off-by: yxxhero <aiopsclub@163.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: yxxhero <aiopsclub@163.com> |
||
|
|
27382a27af |
Bump helm-diff to v3.15.8 across runtime defaults and execution environments (#2624)
chore: bump helm-diff to v3.15.8 Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
1fb47ec16d |
fix: remove naked return by returning expected values (#2617)
Signed-off-by: Niklas Ott <niklas.ott@unwired.at> |
||
|
|
2a1574b383 |
feat: show diff preview when sync --interactive is used (#2603)
* feat: show diff preview when sync --interactive is used Signed-off-by: vomba <hani.harzallah@elastisys.com> |
||
|
|
781d28a47a |
feat: add defaultInherit for automatic release template inheritance (#2600)
* feat: add defaultInherit for automatic release template inheritance Add a top-level defaultInherit field to helmfile.yaml that automatically applies template inheritance to all releases without requiring explicit inherit on each release. The field accepts a single template name as a string or a list of template names. Releases that already explicitly inherit from the same template are not duplicated. Fixes #2599 Signed-off-by: yxxhero <aiopsclub@163.com> * style: fix gci formatting in app_template_test.go Signed-off-by: yxxhero <aiopsclub@163.com> * fix: correct relative chart path in integration test Signed-off-by: yxxhero <aiopsclub@163.com> * fix: use absolute chart path in bad-helmfile test Signed-off-by: yxxhero <aiopsclub@163.com> * fix: use clean chart path in bad-helmfile test Signed-off-by: yxxhero <aiopsclub@163.com> * fix: use dir variable for chart path Signed-off-by: yxxhero <aiopsclub@163.com> * test: fix flaky defaultInherit integration assertions Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/d0884e8e-8b1b-456d-8250-dec1566b8a37 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: tighten defaultInherit integration assertions Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/d0884e8e-8b1b-456d-8250-dec1566b8a37 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: harden release block parsing in issue-2599 case Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/d0884e8e-8b1b-456d-8250-dec1566b8a37 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: make issue-2599 assertions format-tolerant Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/d0884e8e-8b1b-456d-8250-dec1566b8a37 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: fix section extraction and regex matching in issue-2599 case Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/d0884e8e-8b1b-456d-8250-dec1566b8a37 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: sanitize defaultInherit values and dedupe applied templates Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/85a8e815-3701-4b48-a28d-6bb2d50a3b40 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * chore: address validation feedback on defaultInherit fixes Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/85a8e815-3701-4b48-a28d-6bb2d50a3b40 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: sanitize releaseInherit entries in applyDefaultInherit; add cleanup trap and quote vars in integration test Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/1fbf62d5-7ce2-42e5-898b-30151c0c1ef9 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * refactor: combine releaseInherit loops in applyDefaultInherit to avoid double TrimSpace; clarify test comment Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/1fbf62d5-7ce2-42e5-898b-30151c0c1ef9 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: align default inherit tests with yaml wrapper and assertions Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/3ea9b8e4-633f-43c4-899f-e063ec576486 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: address review feedback on defaultInherit tests Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/3ea9b8e4-633f-43c4-899f-e063ec576486 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: fix issue-2599 integration script helmfile invocation Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/9452bb65-7086-459f-b5ae-0b00c1e021eb Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --------- Signed-off-by: yxxhero <aiopsclub@163.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
7ffd4a21ac |
Bump Helm support to 3.21.0 and 4.2.0 (#2588)
* chore: bump pinned helm versions Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/b1cfacaa-52d2-46c8-9fc7-67beaca43df0 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: align kubernetes module pins for helm bump Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/b1cfacaa-52d2-46c8-9fc7-67beaca43df0 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * docs: clarify helm and k8s version pins Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/b1cfacaa-52d2-46c8-9fc7-67beaca43df0 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: update helm 4 snapshot outputs Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/b430f041-d8fb-407f-af06-070f2d0e9293 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: update helm 4 postrender integration fixture Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/fea792b4-b24c-43a9-a391-1fd52e59f843 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: update helm 4 postrender template fixture Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/7ca16c9d-e398-46ce-849b-6299214b2b60 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> |
||
|
|
997051bba4 |
chore: Emit "cleanup" events later to match the behavior in "apply" (#2522)
This changes the behaviour of the cleanup event during sync to be triggered right before the function exits and matches the behaviour of apply Signed-off-by: Niklas Ott <niklas.ott@unwired.at> Co-authored-by: Raphael Luba <raphael@leanbyte.com> |
||
|
|
5027e6aa5e |
chore: Deduplicate preparation code of sync and apply (#2523)
This commit deduplicates the preparation logic for sync and apply by moving it to a common function. Signed-off-by: Niklas Ott <niklas.ott@unwired.at> Co-authored-by: Raphael Luba <raphael@leanbyte.com> |
||
|
|
897400d64f |
Expose internal apis (#2520)
* feat: expose WithPreparedCharts and SyncRun This exposes the previously internal functions withPreparedCharts and sync to be used by tooling built on top of helmfile Co-authored-by: Raphael Luba <raphael@leanbyte.com> Signed-off-by: Niklas Ott <niklas.ott@unwired.at> * feat: expose Helm interface and HelmState This adds a function to get the current HelmState Co-authored-by: Raphael Luba <raphael@leanbyte.com> Signed-off-by: Niklas Ott <niklas.ott@unwired.at> * feat: return an error instead of panicking on multiple calls on WithPreparedCharts Signed-off-by: Niklas Ott <niklas.ott@unwired.at> --------- Signed-off-by: Niklas Ott <niklas.ott@unwired.at> Co-authored-by: Raphael Luba <raphael@leanbyte.com> |
||
|
|
0139304d97 |
feat(state): add mergeStrategy: fallback for first-file-wins env values (#2578)
* feat(state): add mergeStrategy field to EnvironmentSpec Introduces a per-environment mergeStrategy with valid values "override" (default, current behavior) and "fallback". This commit only adds the field, the constants, and a parse-time validator; the loader still ignores the value, so behavior is unchanged. Subsequent commits thread the value through the values loader and implement the fallback semantics. Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de> * refactor(state): thread mergeStrategy through values loader Adds a mergeStrategy string parameter to LoadEnvironmentValues, loadValuesEntries, and mapMerge so the value can flow from EnvironmentSpec down to the merge call site. Behavior is unchanged in this commit; mapMerge ignores the strategy and the next commit implements the fallback semantics. Top-level state.DefaultValues and the --state-values-file/-set loaders are passed an empty strategy ("") since they have no per-environment spec to consult and stay on the default override behavior. Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de> * feat(state): implement fallback merge strategy Adds a hand-rolled fallbackDeepMerge that, unlike mergo, preserves keys present in the destination even when their value is the zero value (false, 0, "", nil, empty list/map). mapMerge dispatches to it when mergeStrategy == "fallback"; "override" and the empty default keep using mergo with WithOverride so existing behaviour is unchanged. Validation lives at the entry of LoadEnvironmentValues so a single chokepoint guards the field. Invalid values produce an error naming both the offending value and the valid options. Tests cover: first-file-wins precedence, gap filling, deep nested merge, three-file chains, explicit zero-value preservation (the case naïve mergo gets wrong), explicit nil preservation, inline map entries, override regression, default-equals-override equivalence, and invalid-strategy errors. Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de> * feat(state): expose prior-file values in fallback template context Under mergeStrategy: fallback, .gotmpl values files can now reference values from earlier files in the same `values:` list via .Values (e.g. `service.domain: "service.{{ .Values.cluster.domain }}"`). The accumulated result is layered under env.GetMergedValues so env defaults, env values, and CLI overrides still win on overlap. Override mode keeps the historical template context — unchanged — so this is strictly opt-in via the mergeStrategy field. Together with the precedence flip from the previous commit, this lets users replace the brittle two-stage `merged-values.yaml.gotmpl` workaround with native helmfile syntax. Tests cover the headline cross-file template reference case and pin the override-mode contract that prior-file values stay invisible. Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de> * docs: document mergeStrategy and fallback semantics Adds a new section to values-and-merging.md describing the override vs fallback strategies, the explicit-zero-value preservation guarantee, and the cross-file template reference behavior. Adds a brief pointer to environments.md so users land on the new field from the environment values discussion. Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de> * refactor(state): reuse maputil.MergeMaps for fallback merge Replaces the hand-rolled fallbackDeepMerge with a single call to maputil.MergeMaps, swapping its arguments so the accumulated dest wins over the new src file. Same first-file-wins semantic, fewer lines, and the fallback path now inherits the same slice merge strategies the rest of helmfile already uses. The one observable behavior shift is for explicit nil values: under fallback, nil in an earlier file no longer 'wins' over a non-nil value in a later file — instead it falls through (matching MergeMaps' rule that nil from the override side only fills missing keys). This is internally consistent: nil-overwrites is an mergo.WithOverride quirk that lives only in the override path. The renamed test NilFallsThroughToFallback pins the new behavior with a comment referencing the contrast with override mode (Issue1154). Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de> --------- Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de> |
||
|
|
420cc3ba9c |
fix: add trackFailOnError option to control kubedog exit code (#2576)
* fix: add trackFailOnError option to control kubedog exit code behavior When kubedog release tracking fails (e.g. pod ImagePullBackOff), helmfile exits with code 0 instead of a non-zero exit code. Add a trackFailOnError configuration option (default: false) that when set to true, propagates kubedog tracking failures to the exit code. The option is available as: - Per-release YAML: trackFailOnError: true - CLI flag: --track-fail-on-error (sync and apply commands) Extract trackReleaseIfEnabled helper to consolidate kubedog tracking logic from two duplicated call sites into a single maintainable method. Fixes #2507 Signed-off-by: yxxhero <aiopsclub@163.com> * fix: add //go:build ignore to server.go to fix go test CI failure The test/integration/test-cases/issue-2103/input/server.go is a package main helper binary used by the issue-2103 integration test. When go test -coverprofile runs on this package, it fails with "go: no such tool covdata" in the CI environment. Adding //go:build ignore excludes the file from go list ./... (and therefore from PKGS in the Makefile), while still allowing the integration test to build it explicitly via file path: go build -o server ./path/to/server.go Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/8a7000af-72b7-48f8-8a82-24813b5df341 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: update TestGenerateID expected hashes after adding TrackFailOnError field Adding TrackFailOnError *bool to ReleaseSpec changed the spew serialization of the struct, which changed the FNV-32a hash values produced by generateValuesID. Update temp_test.go with the new expected hash strings. Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/caa86cd9-73d1-4894-b745-fd70c0811fd6 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --------- Signed-off-by: yxxhero <aiopsclub@163.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
902c5ced17 |
feat: add 'create' subcommand to scaffold helmfile deployment projects (#2574)
* feat: add 'create' subcommand to scaffold helmfile deployment projects Add 'helmfile create [NAME]' command that generates a best-practice helmfile project structure with: - helmfile.yaml with commented examples (helmDefaults, repositories, environments, releases) - environments/default.yaml for environment-specific values - values/.gitkeep placeholder for release values Supports --output-dir/-o for custom output path and --force to overwrite existing files. Validates project name to prevent path traversal. Signed-off-by: yxxhero <aiopsclub@163.com> * fix: add overwrite protection for all scaffold files and unit tests for create command - pkg/app/create.go: extract writeFileIfNotExists helper that respects the --force flag; all three scaffold files (helmfile.yaml, environments/default.yaml, values/.gitkeep) now refuse to overwrite without --force - pkg/config/create.go: ValidateConfig now checks all three scaffold paths and reports every already-existing file in a single error before proceeding, instead of only checking helmfile.yaml - pkg/app/create_test.go: add unit tests covering new directory, current directory, per-file overwrite rejection without --force, and full overwrite with --force Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/eb6d9e4b-0f72-4e26-b841-e1e39a2b2e83 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: remove redundant absDir from ValidateConfig error message Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/eb6d9e4b-0f72-4e26-b841-e1e39a2b2e83 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: address create command review feedback - cmd/create.go: add config.NewCLIConfigImpl() call for consistency with other subcommands; update --force flag help text to list all overwritten files - pkg/config/create.go: delegate to c.GlobalImpl.ValidateConfig() at end of ValidateConfig() for global option validation (--color/--no-color) - pkg/config/create_test.go: add unit tests for CreateImpl.ValidateConfig() covering path separator rejection, '..' rejection, existing-file detection per-file and with --force, and global color conflict delegation Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/6327d657-5888-4b94-85fb-def80c0a193f Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: clarify test helper name and comment in create_test.go Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/6327d657-5888-4b94-85fb-def80c0a193f Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: atomic preflight check in App.Create before any writes Refactor Create to collect all conflicting scaffold paths up front before writing anything. When --force is not set and any scaffold file already exists, the command returns a single error listing all conflicts without touching the filesystem. Also removes the now-unnecessary writeFileIfNotExists helper and adds a test (TestCreate_PreflightAtomicOnLaterConflict) verifying that a conflict on a later file (e.g. environments/default.yaml) prevents even the first file (helmfile.yaml) from being created. Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/aae6f2e6-7f9e-42b8-afa3-78edd3215127 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: handle non-IsNotExist Stat errors in preflight check; add whitespace name test; fix gci formatting - pkg/app/create.go: treat os.Stat errors that are NOT os.IsNotExist as hard errors in the preflight scan, surfacing permission/IO issues before any writes happen; remove trailing blank line that caused gci failure - pkg/config/create.go: same non-IsNotExist error handling in ValidateConfig - pkg/config/create_test.go: add TestCreateImpl_ValidateConfig_WhitespaceOnlyName covering the " " (whitespace-only) name rejection branch Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/d6574f56-f46d-46f7-99d9-e0b0b897b3b5 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * refactor: eliminate duplicated scaffold existence check; use O_EXCL for TOCTOU protection - pkg/config/create.go: remove file-existence check from ValidateConfig (duplicate of App.Create's preflight); ValidateConfig now only validates the project name and delegates to GlobalImpl.ValidateConfig. Remove unused os/path/filepath imports. - pkg/app/create.go: add writeScaffoldFile helper that uses O_CREATE|O_EXCL when force=false, so a file appearing between the preflight check and the actual write is caught rather than silently overwritten (TOCTOU protection). - pkg/config/create_test.go: remove four file-existence tests that tested the now-deleted ValidateConfig logic; file-conflict coverage remains in pkg/app/create_test.go. Simplify ValidName and GlobalColorConflict tests. Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/82f82e72-934f-416c-8662-5060e92284fa Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: wrap O_EXCL error with --force hint; add writeScaffoldFile unit tests - pkg/app/create.go: wrap os.IsExist error from writeScaffoldFile with a message that names the conflicting file and suggests --force, so the user gets actionable output even in the TOCTOU case - pkg/app/create_test.go: add TestWriteScaffoldFile_CreatesNewFile, TestWriteScaffoldFile_ExistingFileNoForce, and TestWriteScaffoldFile_ExistingFileWithForce to cover the helper directly Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/82f82e72-934f-416c-8662-5060e92284fa Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: wrap App.Create errors in *app.Error; reject '.' as project name; add '.' name test - pkg/app/create.go: wrap all App.Create fmt.Errorf returns with appError("", ...) so toCLIError produces a clean user-friendly message instead of "unexpected error: *fmt.wrapError: ..." - pkg/config/create.go: reject "." as a NAME alongside ".." to prevent accidentally scaffolding into the current directory via a named argument - pkg/config/create_test.go: add TestCreateImpl_ValidateConfig_NameDot Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/6d64508e-2d66-47e9-a02a-7669a2f481b7 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: drop unused outputDir param from test helper to fix unparam lint error Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/11cd65e9-c5ef-4195-9375-bc929169616b Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: drop unused force param from test helper to fix unparam lint error Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/0e1bdac5-708f-4615-ae6d-e22fc1e921f2 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --------- Signed-off-by: yxxhero <aiopsclub@163.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
08a22772f7 |
feat: add --write-output flag to helmfile fetch for air-gapped environments (#2572)
* feat: add --write-output flag to helmfile fetch for air-gapped environments Add --write-output flag to helmfile fetch that outputs a modified helmfile.yaml with chart references updated to point to downloaded local chart paths. Combined with --output-dir, this enables preparing all charts for deployment in air-gapped environments. Usage: helmfile fetch --output-dir ./charts --write-output > helmfile-airgapped.yaml Fixes #2571 Signed-off-by: yxxhero <yxxhero@users.noreply.github.com> Signed-off-by: yxxhero <aiopsclub@163.com> * fix: update fetch-write-output integration test grep to match YAML list item chart field Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/d00f71ab-d40d-4220-9b11-97674597685f Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: send status messages to stderr and enforce sequential processing in --write-output mode Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/d338e24c-4f6f-4a59-a319-4b975e0efdcb Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: restore SequentialHelmfiles after Fetch and use %s for YAML string formatting Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/cfa9f3f4-c72f-4760-9c51-88bc6f30add2 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: add test for SequentialHelmfiles restore after Fetch with --write-output Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/cfa9f3f4-c72f-4760-9c51-88bc6f30add2 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: disable live output on --write-output and fix shell quoting/portability in integration test Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/b0eb0d3d-493b-4d77-b8eb-2a5c0ce70d86 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: use unquoted ${helmfile} variable to allow word splitting for EXTRA_HELMFILE_FLAGS Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/d025a111-f7d0-439e-bf14-5508c40d0b51 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: restore helm.EnableLiveOutput after Fetch --write-output via defer Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/ddb8c5fc-ebd1-4f09-9474-5da58938a219 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test: strengthen enableLiveOutput restore assertion with non-trivial initial value Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/d1d0ba9e-5c97-48e1-b761-8bdee391efb2 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * feat: restrict --write-output to a single helmfile state file with clear error Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/f608a0d0-7f52-4e3f-9fac-ab966bd01efb Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * refactor: apply code review suggestions for variable and test naming Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/f608a0d0-7f52-4e3f-9fac-ab966bd01efb Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: replace naked return with explicit return ok, errs to fix nakedret lint error Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/4b060131-a977-44b0-98f7-42bc108ae8e8 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: buffer YAML output and update --write-output flag description Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/50c6ad2e-125c-43c1-b9c3-37fe1686a8eb Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: shorten --write-output flag description, move detail to Long help Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/50c6ad2e-125c-43c1-b9c3-37fe1686a8eb Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --------- Signed-off-by: yxxhero <yxxhero@users.noreply.github.com> Signed-off-by: yxxhero <aiopsclub@163.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
a8e8b67086 |
fix: use --post-renderer-args=VALUE format to prevent Helm flag parsing failure (#2570)
* fix: use --post-renderer-args=VALUE format to prevent Helm flag parsing failure When postRendererArgs contains values like short flags (e.g. -v), passing --post-renderer-args and the value as separate arguments causes Helm to interpret the value as its own flag. Using the --post-renderer-args=VALUE format unambiguously binds the value to the flag. Fixes #2563 Signed-off-by: yxxhero <aiopsclub@163.com> * fix: update hasFlagWithValue doc/errors and add -v short-flag test cases - Update hasFlagWithValue doc comment to describe both '--flag value' and '--flag=value' forms - Update t.Errorf messages in app_test.go to reflect both accepted formats - Add 'post-renderer-args-short-flag-value' test case (-v) to both TestHelmState_flagsForUpgrade and TestHelmState_flagsForTemplate to verify --post-renderer-args=-v emission (core regression from #2563) Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/dd95f046-358b-4867-9069-9432c1b5318e Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --------- Signed-off-by: yxxhero <aiopsclub@163.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
10deabb142 |
Honor skipSchemaValidation during chartification when forceNamespace is set (#2550)
* fix(state): honor skipSchemaValidation in chartify template args Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/a695cbff-c37a-403a-9658-09f4fdaa65d0 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * test(state): harden chartify skip-schema flag detection Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/a695cbff-c37a-403a-9658-09f4fdaa65d0 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix(state): propagate cli skip-schema-validation to chartify Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/70ebf027-0ab5-4bdb-a4b4-5a77c822ee95 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> |
||
|
|
5368ab8d95 |
fix: skip subhelmfiles when selectors conflict with CLI selectors (#2545)
* fix: skip subhelmfiles when selectors conflict with CLI selectors (#2544) When CLI selectors are provided (e.g. -l name=b), subhelmfiles whose explicit selectors are provably incompatible are now skipped entirely, avoiding unnecessary YAML loading and template rendering. Two selector sets are incompatible when every pair has a positive label conflict: same key with different values (e.g. name=b vs name=a). Negative labels are not compared. Fixes #2544 Signed-off-by: yxxhero <aiopsclub@163.com> * fix: address PR review comments - use CLI selectors, fix doc comment, add malformed selector test Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/1f1c33ce-e50d-4781-85b8-d606b5d4ca54 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * fix: add debug logging, unit tests, docs, and fix integration test for subhelmfile selector skip - Add debug log when skipping subhelmfile due to selector conflict - Add TestSubhelmfileSelectorsConflict with 11 cases for direct unit coverage - Document the selector-based subhelmfile skip optimization in docs/index.md - Fix integration test: use 'app' label key instead of reserved 'name' key (GetReleasesWithLabels overwrites labels["name"] with the release name) Signed-off-by: yxxhero <aiopsclub@163.com> * refactor: avoid map allocation in positiveLabelsCompatibleWith Compare positive label slices directly instead of allocating a map per comparison, as label counts are typically small (1-3 entries). Addresses Copilot review comment on PR #2545. Signed-off-by: yxxhero <aiopsclub@163.com> * docs: clarify subhelmfile selector docs per Copilot review feedback Reword the first two bullets to avoid the contradiction between 'CLI selectors are ignored' and the new skip optimization. Signed-off-by: yxxhero <aiopsclub@163.com> * fix: address Copilot review comments round 3 - Log parse errors from SelectorsAreCompatible at debug level instead of silently discarding them - Hoist regex compilation to package-level vars in ParseLabels to avoid repeated compilation per selector - Replace EXIT traps with explicit cleanup calls in integration test to avoid interfering with the parent runner's trap Signed-off-by: yxxhero <aiopsclub@163.com> --------- Signed-off-by: yxxhero <aiopsclub@163.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> |
||
|
|
c57134cda7 |
Fix helmfile init failing to update outdated helm plugins with Helm v4 (#2554)
* Initial plan * Fix helmfile init not updating outdated helm plugins with Helm v4 - UpdatePlugin now handles secrets plugin with Helm 4 by using the split plugin architecture (uninstall old + install via installHelmSecretsV4) - UpdatePlugin falls back to uninstall + reinstall when helm plugin update fails (e.g., with Helm 4 or tarball-installed plugins) - Fix string-based semver comparison for helm-secrets version check in both AddPlugin and UpdatePlugin using proper semver comparison - Add helmSecretsRequiresSplitInstall helper for reuse and correctness - Add tests for update failure fallback scenarios Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/533f1b1c-dda6-4934-af27-051e4eaa9927 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * Address reviewer feedback: preserve update error context and add version assertions in tests - exec.go: include original update error in fallback log message; wrap both errors (update + reinstall) when reinstall also fails so callers get full context - init_test.go: add semver import and GetPluginVersion assertions after CheckHelmPlugins to verify plugins are at required versions on disk Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/c784db7d-7d4c-40a0-97f0-a31eb8901cd6 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * Address second round of reviewer feedback - exec.go: rename UpdatePlugin parameter path→repo for clarity - exec.go: fix uninstallPlugin to only emit INFO log when err == nil - exec_test.go: add Test_helmSecretsRequiresSplitInstall table-driven tests covering v4.6.9, v4.7.0, v4.8.0, v4.10.0, pre-release, invalid and empty - exec_test.go: add Test_UpdatePlugin_Helm4SecretsUsesUninstallReinstall verifying that Helm 4 + secrets uses uninstall+reinstall (not plugin update) Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/cbd3f8c9-ec7d-4500-b168-cb1c2f7c87bc Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * Add len(args) >= 3 guards in test mock for plugin update/uninstall cases Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/ea0f5afc-d52d-473b-b759-853a8f841a26 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * Return early with combined error when uninstall fails in UpdatePlugin fallback Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/bb9a675c-309d-4b06-83d4-a6fe078dce64 Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> |
||
|
|
c584c0e07f |
fix: helmDefaults.postRendererArgs not passed to helm commands (#2510)
* fix: helmDefaults.postRendererArgs not passed to helm commands (#2508)
The commit
|
||
|
|
6faa477290 |
fix: update state values files handling to replace arrays instead of merging (#2537)
* feat: update state values handling to replace arrays instead of merging Signed-off-by: Vojta Polak <vojta.polak@gmail.com> * test: non-shallow copy of OverrideCLISetValues in DeepCopy + test Signed-off-by: Vojta Polak <vojta.polak@gmail.com> * fix: update error message for empty CalleePath in Load function Signed-off-by: Vojta Polak <vojta.polak@gmail.com> --------- Signed-off-by: Vojta Polak <vojta.polak@gmail.com> |
||
|
|
de1c14c3f2 |
chore: rename variables to match in apply and sync (#2521)
This commit only renames some variables to match other places in the code, so the variable names are less confusing, it does not add or change any functionality Signed-off-by: Niklas Ott <niklas.ott@unwired.at> Co-authored-by: Raphael Luba <raphael@leanbyte.com> |
||
|
|
c70b20ad7a |
feat: add an arg that passing description to helm upgrade command (#2497)
* feat: add an arg that passing description to `helm upgrade` command fix: github actions Signed-off-by: swimablefish <swimablefish@gmail.com> * fix: lint and test failed Signed-off-by: swimablefish <swimablefish@gmail.com> * feat: encapsulation Signed-off-by: swimablefish <swimablefish@gmail.com> * feat: add version gate Signed-off-by: swimablefish <swimablefish@gmail.com> * feat: rephrase Signed-off-by: swimablefish <swimablefish@gmail.com> --------- Signed-off-by: swimablefish <swimablefish@gmail.com> |
||
|
|
e72315a876 |
build: update helm-diff to v3.15.3 (#2498)
Signed-off-by: yxxhero <aiopsclub@163.com> |
||
|
|
5c67cbcd6a |
fix: pass --timeout flag through to helm for sync and apply (#2495)
* fix: propagate timeout flag Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com> * test: add test for propagating timeout flag Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com> * feat: add timeout flag to apply command Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com> * test: add test for timeout flag for helmfile apply Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com> * fix: improve description of timeout flag Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com> --------- Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com> |
||
|
|
43b426892e |
fix: cleanup hooks not receiving error signal (#2475)
* fix: cleanup hooks not receiving error signal Closes #1041 Signed-off-by: yxxhero <11087727+yxxhero@users.noreply.github.com> Signed-off-by: yxxhero <aiopsclub@163.com> * Add tests for cleanup hooks error propagation 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> * fix tests Signed-off-by: yxxhero <aiopsclub@163.com> --------- Signed-off-by: yxxhero <11087727+yxxhero@users.noreply.github.com> Signed-off-by: yxxhero <aiopsclub@163.com> |
||
|
|
df01afbbeb |
fix: helmfile list now reflects version from helmfile.lock (#2486)
* 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> |
||
|
|
06d0994b84 |
Fix interactive apply asks in no change situation (#945)
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> |
||
|
|
c375b48550 |
fix: nested helmfile values should replace arrays, not merge element-by-element (#2458)
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> |
||
|
|
6e21671228 |
feat: kubedog integration with unified resource handling (#2383)
* feat: add kubedog-based resource tracking integration Add kubedog tracking as an alternative to Helm's --wait flag with: - Real-time deployment progress tracking - Container log streaming - Fine-grained resource filtering (trackKinds/skipKinds/trackResources) Features: - New pkg/resource package for unified manifest parsing and filtering - New pkg/kubedog package wrapping kubedog library - CLI flags: --track-mode, --track-timeout, --track-logs - Helmfile YAML support for trackMode, trackTimeout, trackLogs, trackKinds, skipKinds, trackResources - Case-insensitive kind matching for filtering - Multi-context support with proper kubeconfig/kubeContext handling Tracking supports: Deployment, StatefulSet, DaemonSet, Job Resource filtering priority (highest to lowest): 1. trackResources - explicit resource whitelist 2. skipKinds - blacklist specific kinds 3. trackKinds - whitelist specific kinds Integration: - Disable Helm --wait when using kubedog tracking - Track after successful Helm sync/apply - Respect release.Namespace as fallback for resources without namespace - Use getKubeContext() for correct cluster targeting Tests: - Unit tests for resource filtering and kubedog options - Integration test with httpbin chart - E2E snapshot tests for YAML serialization - Documentation in docs/advanced-features.md Signed-off-by: yxxhero <aiopsclub@163.com> * fix: address PR #2383 review comments (round 4) 1. resource/filter.go: Skip empty whitelist entries in matchWhitelist - At least one field (kind/name/namespace) must be specified - Prevents matching all resources with empty TrackResources entries 2. config/apply.go: Add ValidateConfig for track-mode validation - Validate --track-mode must be 'helm' or 'kubedog' - Reject invalid values like --track-mode foo 3. config/sync.go: Add ValidateConfig for track-mode validation - Same validation as apply command - Ensures consistent behavior across commands Signed-off-by: yxxhero <aiopsclub@163.com> --------- Signed-off-by: yxxhero <aiopsclub@163.com> |
||
|
|
2be73dd21d |
build: update helm-diff to v3.15.1 (#2442)
Signed-off-by: yxxhero <aiopsclub@163.com> |
||
|
|
69bed171ab |
fix: use absolute baseDir in sequential helmfiles for correct values path resolution (#2425)
* 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> |
||
|
|
abfe73fa6f |
fix: helmDefaults.skipRefresh ignored in runHelmDepBuilds (#2415)
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> |
||
|
|
c63947483c |
fix: eliminate os.Chdir in sequential helmfiles to fix relative path resolution (#2410)
* 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> |
||
|
|
ca8fc293e9 |
fix: helmBinary setting ignored in multi-document YAML files (#2414)
* 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> |
||
|
|
3dab01c16f |
fix: prevent panic in helmfile init on plugin install errors (#2401)
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> |
||
|
|
0129681222 |
feat: add helmfile unittest command for helm-unittest integration (#2400)
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> |
||
|
|
e555ade4c0 |
feat: upgrade Helm version to v3.20.0 and v4.1.0 (#2373)
* feat: upgrade Helm version to v3.20.0 and v4.1.0 This commit updates the recommended Helm version from v3.19.5/v4.0.5 to v3.20.0/v4.1.0 across all workflows, Dockerfiles, and application constants. Changes: - Update CI matrix to test with Helm v3.20.0 and v4.1.0 - Update .github/workflows/Makefile HELM_VERSION to v4.1.0 - Update Dockerfiles with new version and SHA256 checksums - Update pkg/app/init.go HelmRecommendedVersion to v4.1.0 - Update go.mod helm.sh/helm/v3 to v3.20.0 and helm.sh/helm/v4 to v4.1.0 Signed-off-by: yxxhero <aiopsclub@163.com> * fix: remove source field from e2e test helm plugin configs Signed-off-by: yxxhero <aiopsclub@163.com> * fix: remove source field from integration test helm plugin config Signed-off-by: yxxhero <aiopsclub@163.com> --------- Signed-off-by: yxxhero <aiopsclub@163.com> |
||
|
|
693637d88b |
fix: update Helm version to v4.0.5 across workflows and configurations (#2368)
Signed-off-by: yxxhero <aiopsclub@163.com> |
||
|
|
70645e0622 |
fix: array merge regression - layer arrays now replace defaults (#2367)
* fix: array merge regression - layer arrays now replace defaults (#2353) PR #2288 introduced element-by-element array merging to fix #2281, but this caused a regression where layer/environment arrays were merged instead of replacing base arrays entirely. This fix uses automatic sparse array detection: - Arrays with nil values (from --state-values-set) merge element-by-element - Arrays without nils (from layer YAML) replace entirely This follows Helm's documented behavior where arrays replace rather than merge. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: use separate CLIOverrides field for element-by-element array merging The previous approach using ArrayMergeStrategySparse detection didn't work for --state-values-set array[0]=value because setting index 0 produces no nils in the array. This fix adds a CLIOverrides field to Environment that keeps CLI values separate from layer values. CLI overrides are merged last using ArrayMergeStrategyMerge (always element-by-element), while layer values use the default strategy (arrays replace). This ensures: - --state-values-set array[0]=x only changes index 0, preserving other elements - Layer/environment file arrays still replace base arrays entirely - Issue #2281 fix is preserved (--state-values-set array[1].field=x works) Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: correct comment about array merge strategy in test Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: propagate Defaults in multi-part helmfiles and fix merge order - Add Defaults field merging from ctxEnv to preserve base values across helmfile parts separated by --- - Fix merge order: current part values now correctly override previous parts (was reversed, causing older values to win) - Update 147 snapshot test files for new Environment log format with CLIOverrides field This completes the fix for issue #2353 by ensuring: 1. Layer arrays replace entirely (not element-by-element merge) 2. CLI --state-values-set sparse arrays still merge element-by-element 3. Multi-part helmfiles properly inherit and override values Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: address Copilot review comments - Initialize EmptyEnvironment with empty maps to match New() constructor - Update test comment to accurately describe ArrayMergeStrategySparse Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: ensure templates access merged values via .Environment.Values This commit fixes a regression in the CLIOverrides integration where templates accessing .Environment.Values couldn't see CLI override values. Changes: - Remove CLIOverrides-into-Values merge from Merge() to keep proper layering order (Defaults → Values → CLIOverrides) in GetMergedValues() - Update NewEnvironmentTemplateData to set envCopy.Values to the merged values, ensuring templates see the same values via both .Values and .Environment.Values This ensures: - Issue #2353: Layer arrays still replace entirely (Sparse strategy) - Issue #2281: CLI sparse arrays still merge element-by-element - Templates can access CLI overrides via .Environment.Values Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * docs: improve mergeSlices documentation per Copilot review Address Copilot review comments on PR #2367: - Document empty array edge case: explicitly setting [] clears base array - Document recursive strategy propagation for nested map merging - Add comprehensive behavior description for all array merge strategies Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: use merged values when rendering environment value files Environment value files (*.yaml.gotmpl) can reference CLI values via .Values. Previously, only env.Values was passed to template rendering, which didn't include CLIOverrides. Now we call env.GetMergedValues() to get Defaults + Values + CLIOverrides before rendering, so templates can access CLI values like: --state-values-set foo=bar This fixes the state-values-set-cli-args-in-environments integration test. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> --------- Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> |
||
|
|
c4a828686e |
fix: pass --kube-context to helm template when using jsonPatches (#2363)
fix: pass --kube-context to helm template when using jsonPatches (#2309) When using jsonPatches or strategicMergePatches in helmfile, the `helm template` command was not receiving the `--kube-context` flag. This caused issues when `--dry-run=server` was used (introduced in PR #2271 to support lookup() functions), because helm would connect to the wrong cluster context. Root Cause: 1. `flagsForTemplate()` did not call `appendConnectionFlags()`, unlike `flagsForUpgrade()` and `flagsForDiff()` which both include this call. 2. `processChartification()` did not include `--kube-context` when setting `chartifyOpts.TemplateArgs` for internal helm template calls. Fix: 1. Added `appendConnectionFlags()` call to `flagsForTemplate()` to ensure kube-context and other connection flags are passed to helm template. 2. Added `getKubeContext()` helper function that resolves kube-context with proper priority: release > environment > helmDefaults. 3. Modified `processChartification()` to include `--kube-context` in chartifyOpts.TemplateArgs when chartify needs to run helm template. 4. Added compatibility check for `--validate` flag to avoid Helm 4 mutual exclusion error between --validate and --dry-run (Issue #2355). Fixes #2309 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> |
||
|
|
5b7cbe54e9 |
Add --sequential-helmfiles flag for optional sequential processing (#2350)
* Initial plan * Fix helmfile.d parallel processing to respect alphabetical order Changed multiple helmfile.d file processing from parallel to sequential to match the documented behavior. Files are now processed in alphabetical order as stated in the documentation, ensuring predictable deployment order. This fixes issues where deployments would break because parallel processing did not respect the intended ordering (e.g., databases before applications). - Modified visitStatesWithContext to process files sequentially - Removed unused processStateFileParallel function - Updated test snapshots to reflect deterministic ordering Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * Add --sequential-helmfiles flag for opt-in sequential processing Based on feedback, added a flag to control processing mode instead of forcing sequential behavior. Parallel processing is now the default for performance, with an opt-in --sequential-helmfiles flag for when order matters. Changes: - Added SequentialHelmfiles field to GlobalOptions and App - Added --sequential-helmfiles CLI flag - Modified visitStatesWithContext to check flag and choose parallel vs sequential - Updated documentation to clarify parallel is default, sequential is opt-in - Restored original parallel processing as default behavior This gives users control over the behavior based on their needs. Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * Add documentation and improve code readability - Added documentation to processStateFileParallel function - Extracted shouldProcessInParallel variable for clarity - All tests pass, security scan clean Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> * Fix lint issue: remove trailing whitespace Removed trailing whitespace from line 983 in pkg/app/app.go to fix formatting lint error. Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> |
||
|
|
5fd154e2fd |
bump helm version to 4.0.4 (#2335)
Signed-off-by: yxxhero <aiopsclub@163.com> |
||
|
|
f3b19fd81e |
Add parameter to render helmfile as go template without .gotmpl extension (#2312)
* Add parameter to render helmfile as go template without gotmpl extension Signed-off-by: Ronaldo <ronaldo.ur@gmail.com> * Update pkg/envvar/const.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Signed-off-by: Ronaldo <ronaldo.ur@gmail.com> Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> |
||
|
|
97779914ec |
feat: add print-env command (#2279)
* feat: add print-env command Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de> |
||
|
|
534d0b618c |
build(deps): update Helm v4 to 4.0.1 and helm-secrets to 4.7.4 (#2304)
* build(deps): update Helm v4 from 4.0.0 to 4.0.1 Update Helm v4 binary and Go library dependency to version 4.0.1. Changes: - Update helm.sh/helm/v4 Go module from v4.0.0 to v4.0.1 - Update Helm binary version in all Dockerfiles (alpine, ubuntu, debian) - Update SHA256 checksums for linux/amd64 and linux/arm64 - Update CI workflow matrix to test against v4.0.1 - Update HelmRecommendedVersion constant in pkg/app/init.go - Update test mocks to return v4.0.1 version string - Update test plugin fixture version Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * build(deps): update helm-secrets from 4.7.0 to 4.7.4 Update helm-secrets plugin version across all configurations: - Docker images (all 3 variants) - use ARG variable for version - CI test matrix - Integration test defaults - Unit test fixtures and expectations - HelmSecretsRecommendedVersion constant - Dynamic plugin installation in exec.go Also update plugin filename format from helm-secrets-*.tgz to secrets-{version}.tgz to match the new release naming convention. Update suppress-output-line-regex test expected output for Helm 4.0.1 which now suppresses Service diff after ipFamily normalization. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> --------- Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> |
||
|
|
9c70adc038 |
fix: resolve issues #2295, #2296, and #2297 (#2298)
* fix: resolve issues #2295, #2296, #2297 and OCI registry login This PR fixes four related bugs affecting chart preparation, caching, and OCI registry authentication. Issue #2295: OCI chart cache conflicts with parallel helmfile processes - Added filesystem-level locking using flock for cross-process sync - Implements double-check locking pattern for efficiency - Retry logic with 5-minute timeout and 3 retries - Refactored into reusable acquireChartLock() helper function - Added refresh marker coordination for cross-process cache management Issue #2296: helmDefaults.skipDeps and helmDefaults.skipRefresh ignored - Check both CLI options AND helmDefaults when deciding to skip repo sync Issue #2297: Local chart + transformers causes panic - Normalize local chart paths to absolute before calling chartify OCI Registry Login URL Fix: - Added extractRegistryHost() to extract just the registry host from URLs - Fixed SyncRepos to use extracted host for OCI registry login - e.g., "account.dkr.ecr.region.amazonaws.com/charts" -> "account.dkr.ecr.region.amazonaws.com" Test Plan: - Unit tests for issues #2295, #2296, #2297 - Unit tests for OCI registry login (extractRegistryHost, SyncRepos_OCI) - Integration tests for issues #2295 and #2297 - All existing unit tests pass (including TestLint) Fixes #2295 Fixes #2296 Fixes #2297 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: replace 60s timeout with reader-writer locks for OCI chart caching Address PR review feedback from @champtar about the OCI chart caching mechanism. The previous implementation used a 60-second timeout which was arbitrary and caused race conditions when helm deployments took longer (e.g., deployments triggering scaling up/down). Changes: - Replace 60s refresh marker timeout with proper reader-writer locks - Use shared locks (RLock) when using cached charts (allows concurrent reads) - Use exclusive locks (Lock) when refreshing/downloading charts - Hold locks during entire helm operation lifecycle (not just during download) - Add getNamedRWMutex() for in-process RW coordination - Update PrepareCharts() to return locks map for lifecycle management - Add chartLockReleaser in run.go to release locks after helm callback - Remove unused mutexMap and getNamedMutex (replaced by RW versions) - Add comprehensive tests for shared/exclusive lock behavior This eliminates the race condition where one process could delete a cached chart while another process's helm command was still using it. Fixes review comment on PR #2298 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: prevent deadlock when multiple releases share the same chart When multiple releases use the same OCI chart (e.g., same chart different values), workers in PrepareCharts would deadlock: 1. Worker 1 acquires lock for chart/path, downloads, adds to cache 2. Worker 2 finds chart in cache, tries to acquire lock on same path 3. Worker 2 blocks waiting for Worker 1's lock 4. Collector waits for Worker 2's result 5. Worker 1's lock held until PrepareCharts finishes -> deadlock The fix: when using the in-memory chart cache (which means another worker in the same process already downloaded the chart), don't acquire another lock. This is safe because: - The in-memory cache is only used within a single helmfile process - The tempDir cleanup is deferred until after helm callback completes - Cross-process coordination is still handled by file locks during downloads This fixes the "signal: killed" test failures in CI for: - oci_chart_pull_direct - oci_chart_pull_once - oci_chart_pull_once2 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: resolve deadlock by releasing OCI chart locks immediately after download This commit simplifies the OCI chart locking mechanism to fix deadlock issues that occurred when multiple releases shared the same chart. Problem: When multiple releases used the same OCI chart, workers in PrepareCharts would deadlock because: 1. Worker 1 acquires lock for chart/path, downloads chart 2. Worker 2 tries to acquire lock on same path, blocks waiting 3. PrepareCharts waits for all workers to complete 4. Worker 1's lock held until PrepareCharts finishes -> deadlock Solution: Release locks immediately after chart download completes. This is safe because: - The tempDir cleanup is deferred until after helm operations complete in withPreparedCharts(), so charts won't be deleted mid-use - The in-memory chart cache prevents redundant downloads within a process - Cross-process coordination via file locks still works during download Changes: - Remove chartLock field from chartPrepareResult struct - Release locks immediately in getOCIChart() and forcedDownloadChart() - Simplify PrepareCharts() by removing lock collection and release logic - Update function signatures to return only (path, error) This also fixes the "signal: killed" test failures in CI for: - oci_chart_pull_direct - oci_chart_pull_once - oci_chart_pull_once2 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: add double-check locking for in-memory chart cache When multiple workers concurrently process releases using the same chart, they all check the in-memory cache before acquiring locks. If none have populated the cache yet, all workers miss and try to download. Previously, even after acquiring the exclusive lock, the code would re-download the chart when needsRefresh=true (the default). This caused multiple "Pulling" messages in tests like oci_chart_pull_once. The fix adds a second in-memory cache check AFTER acquiring the lock. This implements proper double-check locking: 1. Check cache (outside lock) → miss 2. Acquire lock 3. Check cache again (inside lock) → hit if another worker populated it 4. If still miss, download and add to cache This ensures only one worker downloads the chart, while others use the cached version populated by the first worker. Changes: - Add in-memory cache double-check in getOCIChart() after acquiring lock - Add in-memory cache double-check in forcedDownloadChart() after acquiring lock This fixes the oci_chart_pull_once and oci_chart_pull_direct test failures where charts were being pulled multiple times instead of once. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: use callback to prevent redundant chart downloads within a process When multiple workers concurrently process releases using the same chart, they need to coordinate to avoid redundant downloads. The previous fix set SkipRefresh=true for OCI charts, which prevented legitimate refresh scenarios (e.g., floating tags). This commit implements a better solution using a callback mechanism: 1. acquireChartLock() now accepts an optional skipRefreshCheck callback 2. Before deleting a cached chart for refresh, the callback is invoked 3. If the callback returns true (in-memory cache has the chart), skip refresh 4. This allows deduplication within a process while respecting cross-run refresh The flow is now: - Worker 1 downloads chart, adds to in-memory cache, releases lock - Worker 2 acquires lock, sees needsRefresh=true, but callback sees in-memory cache is populated → uses cached instead of deleting This correctly handles: - Within-process deduplication: only one download per chart - Cross-run refresh: respects --skip-refresh flag for floating tags - Immutable versions: cached and reused as expected Changes: - Add skipRefreshCheck callback parameter to acquireChartLock() - Update getOCIChart() to pass in-memory cache check callback - Update forcedDownloadChart() to pass in-memory cache check callback - Remove SkipRefresh=true workaround for OCI charts Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: address Copilot review comments on PR #2298 This commit addresses the automated review comments from GitHub Copilot: 1. pkg/state/state.go: Add nil check for logger in Release() method to prevent potential nil pointer dereference when logger is nil. 2. pkg/state/state.go: Fix misleading comment about "external callers" to accurately reflect that Logger() is used by the app package. 3. pkg/state/issue_2296_test.go: Add comment noting that boolPtr helper is already defined in skip_test.go (shared across test files). 4. test/integration/test-cases/oci-parallel-pull.sh: Replace hardcoded /tmp paths with a dedicated temp directory for test outputs. Add cleanup for the output directory in the cleanup function. 5. test/integration/test-cases/issue-2297-local-chart-transformers.sh: Add cleanup trap to remove temp directory on exit, preventing leftover files from accumulating. 6. Remove dead code: The chartLocks map in PrepareCharts was always empty since locks are released immediately after download. Removed the unused return value and corresponding handling in run.go to improve code clarity and maintainability. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: make oci-parallel-pull test resilient to registry issues The integration test was intermittently failing in CI due to Docker Hub rate limiting or network issues. These failures are not helmfile bugs. Changes: - Add is_registry_error() function to detect external registry issues (rate limits, network timeouts, connection refused, etc.) - Check for the race condition bug (issue #2295) first and fail fast - If other failures occur, check if they're registry-related - Skip test gracefully when registry issues are detected instead of failing CI on external infrastructure problems This ensures the test still catches the actual race condition bug while not causing false failures due to Docker Hub rate limits in CI. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: make oci-parallel-pull test resilient to registry issues The integration test was failing in CI for two reasons: 1. Docker Hub rate limiting or network issues causing helmfile to fail 2. The test script exits early due to `set -e` when `wait` returns non-zero Changes: - Use `wait $pid || exit=$?` pattern to capture exit codes without triggering set -e. When wait returns non-zero, the || branch captures the exit code into the variable, preventing script termination. - Add is_registry_error() function to detect external registry issues (rate limits, network timeouts, connection refused, etc.) - Check for the race condition bug (issue #2295) first and fail fast - Skip test gracefully when registry issues are detected instead of failing CI on external infrastructure problems This ensures the test still catches the actual race condition bug while not causing false failures due to Docker Hub rate limits in CI. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: address PR #2298 review - reinitialize fileLock after release Address Copilot review comments: 1. pkg/state/state.go: Reinitialize fileLock after releasing shared lock When upgrading from shared to exclusive lock, the fileLock needs to be reinitialized with flock.New() after calling Release(). This ensures a fresh flock object is used for the exclusive lock acquisition. 2. test/integration/test-cases/oci-parallel-pull.sh: Add lock file verification warning if no lock files are found, to ensure the locking mechanism is actually being tested. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: address PR #2298 Copilot review comments (round 4) Address 8 Copilot review comments: 1. pkg/state/state.go: Release in-process mutex during retry backoff to avoid blocking other goroutines for up to 90 seconds. 2. pkg/state/state.go: Include chartPath in shared lock error message for better debugging. 3. pkg/state/state.go: Document that extractRegistryHost does not handle URLs with query parameters or fragments (uncommon for OCI registries). 4. pkg/state/state.go: Document that skipRefreshCheck callback should be fast and non-blocking since it runs while holding exclusive lock. 5. oci-parallel-pull.sh: Use case-insensitive grep (-i flag) to catch error variations like "I/O timeout". 6. helmfile.yaml: Expand comment explaining why library charts can't be used for this test (they can't be templated by Helm). Skipped (with justification): - PrepareChartKey helper: Only 2 usages with different source structs - Context reuse in retry: Per-attempt contexts provide clearer semantics Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: address PR #2298 Copilot review comments (round 5) 1. Make race condition detection grep more robust (oci-parallel-pull.sh) - Use case-insensitive extended regex (-iqE) - Add multiple pattern variations to catch different tar/helm versions 2. Remove unused Logger() method from HelmState (state.go) - Method was never called; all lock releases use st.logger directly 3. Add clarifying comments for lock retry behavior (state.go) - Document why file system errors are retried but timeouts are not - Explain flock returns (false, nil) on context deadline exceeded Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: clarify lock file check is informational only Lock files are ephemeral and may be cleaned up immediately after helmfile processes complete. Update comments and warning message to make clear their absence doesn't indicate locking wasn't used. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: add HELM_BIN env var to Dockerfiles The helm-git plugin requires HELM_BIN environment variable to be set. Without it, the plugin fails with "HELM_BIN: parameter not set". Add HELM_BIN=/usr/local/bin/helm to all Dockerfile variants. Fixes #2303 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> --------- Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> |
||
|
|
c8bcbcd629 |
🐛 Fix four critical issues: environment merging, kubeVersion detection, lookup() with kustomize, and Helm 4 color flags (#2276)
* fix: deep merge environments from multiple bases (#2273) Problem: When using multiple base helmfiles, environment values were being completely replaced instead of deep-merged due to mergo.WithOverride introduced in PR #2228. Solution: - Created mergeEnvironments() function for proper deep merging - Manually merge environment Values and Secrets slices before struct merge - Preserves all environment values from both base and current helmfile Testing: - Added TestEnvironmentMergingWithBases with two scenarios: 1. Multiple bases with overlapping environment values 2. Environment values with array merging Fixes #2273 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: auto-detect Kubernetes version for helm-diff (#2275) Problem: When helmfile runs helm-diff without specifying kubeVersion, helm-diff falls back to v1.20.0. This causes chart compatibility checks to fail for charts requiring newer Kubernetes versions (e.g., kubeVersion: ">=1.25.0"). Root Cause: - flagsForDiff() was not passing kubeVersion to helm-diff plugin - Without --kube-version flag, helm-diff uses default v1.20.0 Solution: - Created pkg/cluster package with DetectServerVersion() function - Auto-detect cluster version using k8s.io/client-go discovery API - Pass detected version to helm-diff via --kube-version flag - Priority: helmfile.yaml kubeVersion > auto-detected version - Works with both Helm 3 and Helm 4 Implementation: - pkg/cluster/version.go: Cluster version detection - pkg/app/app.go: detectKubeVersion() helper used in diff() and apply() - pkg/state/state.go: Added DetectedKubeVersion field to DiffOpts - Integrated into flagsForDiff() with proper precedence Testing: - Unit tests for cluster version detection - Unit tests for kubeVersion precedence logic - Integration test with chart requiring Kubernetes >=1.25.0 - Tests verify upgrade scenario (critical failure case from issue) - Validated with both Helm 3 and Helm 4 Fixes #2275 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: enable lookup() function with strategicMergePatches (#2271) Problem: When using strategicMergePatches (kustomize), Helm's lookup() function stops working. Charts like Grafana use lookup() to preserve existing resource values (e.g., PVC volumeName), which get lost when using patches. Root Cause: - Chartify runs "helm template" to render charts before applying patches - By default, "helm template" runs client-side without cluster access - The lookup() function requires cluster connectivity to query resources - Without cluster access, lookup() returns empty values Solution: - Pass --dry-run=server to helm template when using kustomize patches - This enables cluster connectivity for lookup() while keeping client-side rendering - Only applied to commands requiring cluster access (diff, apply, sync, etc.) - Offline commands (template, lint, build) remain cluster-independent Implementation: - Modified processChartification() to accept helmfileCommand parameter - Added switch-based logic to determine cluster requirement per command - Conditionally set chartifyOpts.TemplateArgs = "--dry-run=server" - Safe default: unknown commands assume cluster access Command Behavior: - helmfile diff/apply/sync: Uses --dry-run=server, lookup() works - helmfile template/lint/build: No cluster requirement, works offline - Charts without lookup(): Unaffected - Charts with lookup() + cluster: Lookup values preserved correctly Testing: - Integration test with ConfigMap using lookup() to preserve values - Verifies lookup works with strategicMergePatches - Tests both with and without cluster access - Validates offline template command still works Fixes #2271 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: remove unnecessary error return from mergeEnvironments The mergeEnvironments function always returns nil, making the error return value unnecessary. This fixes the unparam linter warning. - Changed function signature to not return error - Updated call site to not handle error - All tests still pass Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: handle nil Environments map in mergeEnvironments Fixes panic when base helmfile has nil Environments map. Initialize the destination map if nil before merging to prevent "assignment to entry in nil map" panic. - Added nil check in mergeEnvironments to return early - Initialize layers[0].Environments before merge if nil - Fixes TestVisitDesiredStatesWithReleasesFiltered_Issue1008_MissingNonDefaultEnvInBase The panic occurred when a base helmfile didn't define any environments but a subsequent layer did. Now we properly initialize an empty map to merge into. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * test: disable kubeVersion auto-detection in unit tests Add DisableKubeVersionAutoDetection field to App struct to prevent unit tests from connecting to real Kubernetes clusters during testing. The kubeVersion auto-detection feature (issue #2275) was causing unit tests to fail because: 1. Tests use mock helm implementations without real cluster access 2. Auto-detection was connecting to local minikube cluster (v1.34.0) 3. Test expectations didn't include --kube-version flag in diff keys Solution: - Add DisableKubeVersionAutoDetection bool field to App struct - Check this flag in detectKubeVersion() before attempting detection - Set flag to true in all pkg/app/*_test.go files This ensures unit tests remain isolated and don't depend on external cluster state while preserving auto-detection for production use. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * chore: upgrade helm-diff plugin to v3.14.1 Update helm-diff plugin from v3.14.0 to v3.14.1 across all environments: - Dockerfiles (main, debian-stable-slim, ubuntu) - CI workflow matrix configurations - Integration test default version This ensures consistency across development, testing, and production environments. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * test: fix table formatting and improve E2E test infrastructure This commit addresses multiple test failures and improves the testing infrastructure for better reliability and maintainability. Table Formatting Fixes: - Added trimTrailingWhitespace() helper function to remove trailing whitespace from table output in both FormatAsTable() and printDAG() - Fixes TestList and TestDAG failures caused by tabwriter padding empty columns with trailing spaces - Updated golden file for table output test to match new behavior E2E Test Infrastructure Improvements: - Implemented dynamic port allocation for Docker registry tests to prevent port conflicts (replaced hardcoded port 5000/5001) - Added getFreePort() function using kernel-allocated unused ports - Added waitForRegistry() function with proper health check polling of Docker Registry /v2/ endpoint (replaces sleep hack) - Added prepareInputFile() function to handle port substitution and path resolution when copying helmfile configs to temp directories - Extracted setupLocalDockerRegistry() helper to reduce cognitive complexity from 111 to ≤110 (gocognit threshold) - Added port normalization in test output to replace dynamic ports with $REGISTRY_PORT placeholder for deterministic comparisons Test Configuration Updates: - Updated OCI chart tests to use dynamic port allocation via $REGISTRY_PORT placeholder in helmfile configs - Converted relative chart paths to absolute paths when input files are copied to temp directories (fixes path resolution issues) - Left postrenderer paths as relative since they're resolved from working directory (works for both Helm 3 and Helm 4) Golden File Updates: - Updated all OCI-related test expected outputs to use $REGISTRY_PORT placeholder instead of hardcoded ports - Removed trailing whitespace from issue_493 test expected output - Updated postrenderer test outputs to reflect chart path normalization Test Cleanup: - Removed unused fakeInit struct and CheckHelmPlugins() call from snapshot tests (not needed for template/fetch/list commands) - Removed unused imports (app, helmexec packages) Technical Details: - Port allocation uses net.Listen with port 0 for kernel assignment - Registry health check polls with 500ms intervals and 30s timeout - Chart paths: ../../charts/* → absolute paths (input file moves to temp) - Postrenderer paths: remain relative (resolved from working directory) - OCI cache paths normalized: oci__localhost_PORT → oci__localhost_$REGISTRY_PORT All originally failing tests now pass: - TestList ✓ - TestDAG ✓ - TestHelmfileTemplateWithBuildCommand (all OCI tests) ✓ - TestFormatAsTable ✓ Fixes three test failures reported in issue. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix(test): convert postrenderer paths to absolute for Helm 3 Helm 3 resolves postrenderer script paths relative to the helmfile location. When the input file is copied to a temp directory for port substitution, relative postrenderer paths break. Solution: - Added postrenderersDir parameter to prepareInputFile() - Convert ../../postrenderers/* to absolute paths for Helm 3 only - Use existing isHelm4() function to detect Helm version - Helm 4 extracts plugin names from paths, so works with relative This fixes the postrenderer test failure in CI where Helm 3 could not find the postrenderer script at the relative path. Fixes: Error: unable to find binary at ../../postrenderers/add-cm2.bash Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix(test): remove remaining hardcoded port 5001 in OCI tests Updated 4 remaining OCI chart tests that still had hardcoded port 5001: - oci_chart_pull - oci_chart_pull_once - oci_chart_pull_once2 - oci_chart_pull_direct Changes: - config.yaml: Removed hardcoded port, use dynamic allocation - input.yaml.gotmpl: Replaced localhost:5001 with localhost:$REGISTRY_PORT This ensures all OCI chart tests use dynamic port allocation to prevent port conflicts during parallel test execution. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: prevent helm-diff from normalizing server-side defaults Problem: The suppress-output-line-regex integration test was failing because helm-diff was reporting "has changed, but diff is empty after suppression" for Service resources when it should have shown ipFamilyPolicy and ipFamilies fields being removed. Root Cause: When auto-detected kubeVersion (e.g., 1.34.0) is passed to helm-diff via --kube-version flag, helm-diff normalizes server-side defaults. This makes fields like ipFamilyPolicy and ipFamilies appear unchanged, even though they don't exist in the chart template and will be removed by the upgrade. After applying suppressOutputLineRegex patterns, only label changes remained (helm.sh/chart and app.kubernetes.io/version). These were correctly suppressed, leaving an empty diff - hence the "diff is empty after suppression" message. Solution: Added a new configuration option 'disableAutoDetectedKubeVersionForDiff' to allow disabling auto-detected kubeVersion being passed to helm-diff. This prevents helm-diff from normalizing server-side defaults when needed. Default behavior: Pass auto-detected kubeVersion (fixes issue #2275, existing behavior) Opt-out behavior: Set flag to true to only use explicit kubeVersion from helmfile.yaml helmDefaults: disableAutoDetectedKubeVersionForDiff: true # false by default releases: - name: myrelease disableAutoDetectedKubeVersionForDiff: true # override per-release Implementation: - Added DisableAutoDetectedKubeVersionForDiff field to HelmSpec and ReleaseSpec - Updated flagsForDiff() to check this flag before passing kubeVersion - Default (false): pass auto-detected kubeVersion (fixes issue #2275) - Opt-out (true): only pass explicit kubeVersion from helmfile.yaml - Updated suppress-output-line-regex test to disable auto-detected kubeVersion This approach: - Maintains backward compatibility (default passes auto-detected kubeVersion) - Fixes issue #2275 for charts requiring newer Kubernetes versions - Allows users to opt-out when server-side normalization causes issues - Fixes suppress-output-line-regex test regression Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * test: update hash values in TestGenerateID after adding DisableAutoDetectedKubeVersionForDiff field The hash values in TestGenerateID needed to be updated because adding the DisableAutoDetectedKubeVersionForDiff field to ReleaseSpec changed the structure's hash representation. This is expected behavior as generateValuesID() hashes the entire ReleaseSpec structure. Updated all expected hash values to match the new values: - baseline: foo-values-66f7fd6f7b - different bytes content: foo-values-6664979cd7 - different map content: foo-values-78897dfd49 - different chart: foo-values-64b7846cb7 - different name: bar-values-576cb7ddc7 - specific ns: myns-foo-values-6c567f54c Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: address PR review comments and resolve issue #2280 This commit addresses all review comments from GitHub Copilot and resolves issue #2280 regarding --color flag conflict with Helm 4. Changes: 1. Fixed documentation in pkg/cluster/version.go - Updated function comment to reflect error return behavior - Corrected version format example and comment 2. Added complete command categorization in pkg/state/state.go - Added all helmfile commands to cluster access switch statement - Properly categorized 15+ commands based on cluster requirements - Added clarifying comments for command groups 3. Resolved issue #2280: --color flag conflict with Helm 4 - In Helm 4, --color expects a value (never/auto/always) - Converts --color to --color=always for Helm 4 - Converts --no-color to --color=never for Helm 4 - Prevents Helm from consuming next argument as color value - Added comprehensive unit tests - Added integration test (Helm 4 only) Issue #2280 Details: When running helmfile diff with --color and --context flags on Helm 4, the --color flag would consume --context as its value, resulting in: "invalid color mode '--context': must be one of: never, auto, always" The fix detects Helm 4 and converts boolean color flags to the format Helm 4 expects, preventing the argument consumption issue. Fixes #2280 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: correct kubeVersion precedence comment in test The comment incorrectly stated that state.KubeVersion takes precedence over paramKubeVersion, but the actual implementation (getKubeVersion in state.go:3354-3364) shows the correct order is: 1. paramKubeVersion (auto-detected from cluster) 2. release.KubeVersion (per-release override) 3. state.KubeVersion (helmfile.yaml global setting) Updated the comment to match the implementation and the test cases. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * fix: resolve Helm 4 --color flag conflict (issue #2280) This commit resolves issue #2280 where the --color flag causes Helm 4 to consume the next argument, resulting in errors like: "invalid color mode '--context': must be one of: never, auto, always" Root Cause: In Helm 4, the --color flag is parsed by the Helm binary before being passed to plugins like helm-diff. This causes Helm to interpret the next argument (e.g., --context) as the value for --color. Solution: Remove --color and --no-color flags from helm-diff commands when using Helm 4, and instead use the HELM_DIFF_COLOR environment variable. The helm-diff plugin supports HELM_DIFF_COLOR=[true|false] as an alternative to the --color/--no-color flags. Changes: 1. Added filterColorFlagsForHelm4() function in pkg/helmexec/exec.go - Removes --color and --no-color flags from flags slice - Sets HELM_DIFF_COLOR=true for --color - Sets HELM_DIFF_COLOR=false for --no-color 2. Modified DiffRelease() to call filterColorFlagsForHelm4() on Helm 4 3. Added comprehensive unit tests in pkg/helmexec/exec_test.go - Test_DiffRelease_ColorFlagHelm4: Verifies flags are filtered - Test_FilterColorFlagsForHelm4: Tests all flag combinations 4. Added integration test in test/integration/test-cases/issue-2280.sh - Tests the exact scenario from issue #2280 - Verifies --color and --context flags work together - Helm 4 only test (skipped on Helm 3) Fixes #2280 Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * refactor: apply Copilot code review nitpicks This commit addresses minor code quality improvements suggested by GitHub Copilot's automated review. Changes: 1. pkg/app/formatters.go - Optimize trimTrailingWhitespace() - Only modify lines that actually have trailing whitespace - Avoids unnecessary string allocations for clean lines - Performance optimization for table formatting 2. test/e2e/template/helmfile/snapshot_test.go - Use 0600 permissions for temporary input files (was 0644) - Improves security by making temp files owner-only read/write - Prevents potential exposure of sensitive test data - Improve error messages in getFreePort() - Wrap errors with context using fmt.Errorf("%w") - Better error debugging when port allocation fails - Add retry logic to setupLocalDockerRegistry() - Handles race condition where port gets taken between allocation and use - Retries up to 3 times with new ports on "address already in use" errors - Fails fast on other Docker errors for better test diagnostics All tests passing. These are non-functional improvements that enhance code quality, performance, security, and test reliability. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * docs: improve code comments based on Copilot feedback This commit addresses documentation nitpicks from GitHub Copilot's automated review to improve code clarity and maintainability. Changes: 1. pkg/app/app.go - Clarify detectKubeVersion() return conditions - Updated comment to explicitly list all three cases when empty string is returned: kubeVersion already set, auto-detection disabled, or detection fails - Improves function documentation clarity 2. test/e2e/template/helmfile/snapshot_test.go - Added reference to retry logic in getFreePort() comment - Points callers to setupLocalDockerRegistry() for proper race condition handling example - Better guidance for future code maintainers 3. pkg/state/state.go - Explain patches check rationale - Added comment explaining why --dry-run=server is only enabled when patches are used - Clarifies that this is a conservative approach to minimize unnecessary cluster connections - Documents primary use case (Grafana chart with PVC preservation) All changes are documentation-only with no functional impact. All tests passing. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> * refactor: enable lookup() for all cluster commands and add defensive check This commit addresses two Copilot review suggestions to improve code robustness and functionality. Changes: 1. pkg/state/state.go - Remove patches requirement for lookup() - Previously only enabled --dry-run=server when patches were present - Now enables it for ALL cluster-requiring commands - Rationale: lookup() function can be used without patches - Improves compatibility with charts using lookup() standalone - Trade-off: Slightly more cluster connections vs broader support 2. pkg/helmexec/exec.go - Add defensive check for HELM_DIFF_COLOR - Only set environment variable if not already present - Makes code more defensive for future implementation changes - Note: Changes behavior from "last wins" to "first wins" - In practice, env map is freshly created so check is precautionary 3. pkg/helmexec/exec_test.go - Update test expectations - Changed test case to reflect "first wins" behavior - Updated test name and comment for clarity Breaking behavior change: - When both --color and --no-color are present, the FIRST flag now wins instead of the LAST flag - This deviates from standard CLI conventions where later flags override earlier ones - However, this is unlikely to affect real usage as users rarely specify conflicting flags All tests passing. Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> --------- Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> |
||
|
|
4f275b3667 |
feat: add Helm 4 support while maintaining Helm 3 compatibility (#2262)
This commit adds comprehensive support for Helm 4 while maintaining full backward compatibility with Helm 3. The implementation includes: - Updated helm version detection to support both Helm 3 and Helm 4 - Added HELMFILE_HELM4 environment variable to control Helm version - Modified helm execution paths to handle version-specific binaries - Updated helm plugin installation to support split architecture - Helm 4: Uses split plugin architecture (3 separate .tgz files) - helm-secrets.tgz - helm-secrets-getter.tgz - helm-secrets-post-renderer.tgz - Helm 3: Continues using single plugin installation - Updated Dockerfiles, CI workflows, and core installation code - Helm 4 requires post-renderers to be plugins, not executable scripts - Created Helm plugin structure for integration tests - Updated helmfile.yaml templates to dynamically select renderer type - Added test plugins: add-cm, add-cm1, add-cm2 - Updated integration tests for Helm 3/4 compatibility - Created Helm 4 variant expected output files - Fixed test determinism issues (repo cleanup between iterations) - Added version-specific output filtering for warnings/messages - Updated workflows to test both Helm 3 and Helm 4 - Matrix testing across Helm versions - Updated helm-diff to v3.14.0 for compatibility - Updated README and docs with Helm 4 information - Added migration guidance - Updated version requirements All changes are backward compatible - existing Helm 3 users will see no behavior changes. fix: update Helm 4 lint expected output to match filtered output The grep filter removes the semver warning, so the expected output should not include it. Updated lint-helm4 files to match the filtered output (warning removed, no extra blank line). Signed-off-by: Aditya Menon <amenon@canarytechnologies.com> |