* fix: ensure OCI registry login when SkipRepos is set (#1847)
Commands like build, status, list, and show-dag set SkipRepos: true to
avoid slow helm repo add/update for classic repos. However, this also
skipped helm registry login for OCI registries, causing 401 Unauthorized
errors when pulling OCI charts.
Add a variadic SyncOption parameter (backward compatible) with
WithOCIOnly() that limits repo processing to OCI registries only.
When skipRepos is true, callers now pass WithOCIOnly() so that OCI
authentication still happens before chart pulls.
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: reword OCI login comments per review feedback
RegistryLogin is a no-op when credentials are not configured, so the
word 'always' was misleading. Clarify that login is only needed when
credentials are present.
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: skip OCI login for commands that don't pull charts
Commands like 'list' and 'write-values' skip chart preparation entirely,
so OCI registry login is unnecessary for them. Extract the skip-command
list into a shared variable and use it to gate OCI-only login in
WithPreparedCharts.
Signed-off-by: yxxhero <aiopsclub@163.com>
* docs: clarify commandsSkipChartPrep comment per review feedback
Clarify that these commands only skip OCI login when skipRepos is true;
when skipRepos is false, SyncReposOnce still runs normally for all repos.
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
The '========== Updated Releases ==========' header was a fixed 38
chars regardless of the table width below it. Now the divider line
is extended to match the table's visual width, with the title text
centered within the '=' borders.
- Add TableVisualWidth() to measure table width via runewidth
- Add HeaderDividerCentered() and HeaderDividerCenteredStyled()
for centered dividers with optional bold+blue ANSI styling
- Refactor DisplayAffectedReleases to build the table first, then
compute its width before logging the header
- Update all test snapshots and integration test output files
Signed-off-by: yxxhero <aiopsclub@163.com>
* feat: add `inherits:` for sub-helmfile config inheritance
Add an opt-in `inherits:` field to `helmfiles:` entries so a sub-helmfile
can inherit specific configuration categories from its parent:
helmfiles:
- path: myapp.yaml
inherits: [repositories, environments]
Allowed values: repositories, helmDefaults, commonLabels, apiVersions,
kubeVersion, templates, environments. Child values win; parent fills gaps
(consistent with `bases:`). This directly fixes#1495, where a repository
declared in the parent was unavailable to sub-helmfiles, producing a
confusing "repo not found" error.
Implementation notes:
- The 6 pure fields (repositories, helmDefaults, commonLabels, apiVersions,
kubeVersion, templates) are merged post-load via MergeInherited; verified
all are consumed post-load (ExecuteTemplates/converge), never at parse.
- environments is injected pre-load as ctxEnv, because RenderedValues is
baked at load time; the parent's resolved values become the base and the
child's own environments: block overrides per key.
- helmDefaults uses a *HelmSpec pointer (value type is non-comparable) with
a no-override mergo merge, so a child that omits helmDefaults inherits the
parent's fully.
- A footgun warning (WarnUninheritedRepos) suggests
`inherits: [repositories]` when a release references a repo the parent
declares but the child lacks.
- Unknown inherits keys are rejected at parse time with the allowed set.
Inheritance is opt-in and fully backward compatible: empty (the default)
preserves the historical independent-sub-helmfile behavior.
Fixes#1495
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: address review — deep-copy inherited config and fix bases: doc link
- BuildInheritedConfig now deep-copies the pure fields via a YAML round-trip
(Env via environment.DeepCopy) so the returned config never aliases the
parent state's slices/maps, matching its doc comment. Now returns an error
to surface round-trip failures; the call site in processNestedHelmfiles is
updated. Added TestBuildInheritedConfig_PureFieldsAreDeepCopied to lock
in the no-aliasing guarantee.
- Fix the broken `bases:` anchor (#) in shared-configuration-across-teams.md
to point to writing-helmfile.md#layering-state-files.
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: address review — reject inherits without path and document helmDefaults caveat
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: address review — make AllowedInherits immutable and clarify effective-repo wording
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: retry rendering with lenient requiredEnv when selectors are active (#1172)
The entire helmfile document is rendered as a Go template before selector
labels filter releases. This means requiredEnv calls in releases excluded
by selectors still fail, blocking the whole run.
When selectors are active and rendering fails due to a requiredEnv error,
helmfile now retries with lenient mode: unset env vars produce empty
strings instead of failing. The document can then be parsed and filtered
by selectors normally.
Behavior:
- Without selectors: requiredEnv fails as before (validation preserved)
- With selectors, all env vars set: strict render succeeds, no retry
- With selectors, some env vars missing: lenient retry, excluded releases
get empty values and are filtered out by selectors
Implementation:
- Add RequiredEnvError type + ErrRequiredEnvNotSet sentinel for type-safe
error detection via errors.As
- Add lenientRequiredEnv flag to tmpl.Context; requiredEnv returns empty
string instead of failing when set
- Add NewLenientFileRenderer via functional options pattern
(FileRendererOption / WithPreRender / WithLenientRequiredEnv)
- Extract renderWithSelectorFallback in two_pass_renderer.go
- Pass selectors from LoadOpts to desiredStateLoader
Closes#1172
Signed-off-by: yxxhero <yxxhero@example.com>
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: add integration test for selector filtering with requiredEnv (#1172)
Verify that selector-based filtering works correctly when requiredEnv is
used in release values. Users set all required env vars, so rendering
succeeds, and selectors filter out non-matching releases.
Test scenarios:
- helmfile template -l tier=label2: only rel2 is templated (rel1 excluded)
- helmfile template without selector: both releases are templated
Closes#1172
Signed-off-by: yxxhero <yxxhero@example.com>
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <yxxhero@example.com>
Signed-off-by: yxxhero <aiopsclub@163.com>
Environment.DeepCopy() used a YAML marshal/unmarshal round-trip to copy
values. When SOPS/KMS-encrypted secret files contained values with special
characters (colons, quotes, braces such as ~masked:ab#7i7!;{'".), the
YAML round-trip could mangle or silently drop adjacent keys, producing
the "map has no entry for key" error reported in #973.
Replace the YAML-based DeepCopy with maputil.DeepCopyMap(), a proper
recursive deep copy that:
- Preserves original Go types (string "true" stays string, not bool)
- Never loses data due to special characters in values
- Normalises map[any]any keys to strings (matching CastKeysToStrings)
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: add integration test for issue #1880 transformers with file:// deps
Add an integration test reproducing the exact scenario from issue #1880:
a local chart with a relative file:// dependency (file://../library) used
together with kustomize transformers.
Before the fix (rewriteChartDependencies in PR #2334), chartify copied
the chart to a temp directory, breaking the relative file:// path and
causing helm dependency up to fail with:
Error: directory /tmp/chartify.../monitoring/library not found
Also fix test artifact leak in issue923_test.go where OCI chart downloads
wrote to CWD because OutputDirTemplate lacked {{ .OutputDir }}.
Closes#1880
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix(test): guard exit-code captures against set -e in integration tests
Under set -e (enabled in run.sh), a failing command exits the shell
before 'var=$?' can execute, defeating diagnostic cat+fail blocks and
breaking helm diff tests that expect exit code 2.
Replaced 'cmd; var=$?' with 'var=0; cmd || var=$?' across 12 test
files (29 sites), matching the pattern already used in oci-parallel-pull.sh.
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: support go-getter URLs in ad-hoc dependencies to fix#821
Ad-hoc release dependencies (release.dependencies[].chart) that used
go-getter URLs like "git::https://host/repo.git@path?ref=tag" were passed
to chartify as-is. chartify then tried to resolve them via `helm repo
list`, which fails with "no helm list entry found for repository
\"git::https:\". please `helm repo add` it!".
The primary chart already fetched such URLs via downloadChartWithGoGetter,
but the ad-hoc dependency path in PrepareChartify only handled local
directories and OCI rewrites, so go-getter URLs fell through.
This adds a branch that detects remote go-getter URLs (remote.IsRemote)
and fetches them to a local cache directory via a new
downloadAdhocDepChartWithGoGetter helper, mirroring the primary-chart
fetch path. chartify then sees a local chart and takes its file:// branch.
Fixes#821
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: add integration test for go-getter ad-hoc dependencies (#821)
Adds an integration test that commits a chart to a throwaway local git repo
and references it via a "git::file://..." go-getter URL as a release
ad-hoc dependency, then asserts `helmfile template` renders both the main
chart and the fetched dependency.
Using file:// (rather than https://) keeps the test deterministic and
network-free while exercising the exact fix path (remote.IsRemote +
downloadAdhocDepChartWithGoGetter in PrepareChartify). Verified to fail on
the unfixed code with the original "no helm list entry found for repository
\"git::file:\"" error and pass on the fixed code.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: surface helmfile error in issue #821 integration test
The integration runner (run.sh) enables `set -e`, so a non-zero helmfile
exit aborted the script before the captured output could be printed,
hiding the real failure in CI. Disable `set -e` around the helmfile
invocation and report the exit code plus full output on failure.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: fix issue-821 integration test chart path and errexit handling
Two issues caused the integration test to fail in CI (while passing in my
local smoke test, which used an absolute path):
1. The main chart path was relative to the integration CWD, but the
helmfile.yaml is generated in a temp directory and helmfile resolves
`chart:` relative to that directory (its basePath). The relative path
was interpreted as a named-repo chart and failed instantly with
`Error: repo test not found`. Resolve the case dir to an absolute path
with `$(cd ... && pwd)`.
2. run.sh runs under `set -e`, so the unguarded helmfile invocation exited
the whole script on failure before the captured output could be printed,
hiding the real error. Capture the exit code via `cmd || rc=$?` so
failures are reported.
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
* feat: add --template-args to enable helm lookup() during template/apply/sync (#1833)
Add a --template-args flag to the template, apply, and sync subcommands so
extra args (most notably --dry-run=server) can be passed to the helm template
invocation, enabling Helm's lookup() function to resolve live cluster values.
- template: --template-args reaches both chartify's pre-render helm template
and the final helm template output (flagsForTemplate).
- apply/sync: --template-args reaches chartify's pre-render helm template.
apply/sync already inject --dry-run=server automatically for cluster
operations; the flag is an explicit opt-in for the template subcommand or
for passing additional flags.
- When --dry-run is present in template args, kube-context/kubeconfig are also
injected into chartify so lookup() can actually reach the cluster.
- Resolves the long-stale PR #1833 rebased onto current main, which already
contains the cluster-connectivity infrastructure (issues #2271, #2309,
#2355, #2444).
- Includes integration test (lookup.sh) covering both chartify and
non-chartify scenarios.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: make lookup template nil-safe to fix integration CI
The lookup() function returns an empty map when the chart is rendered
without a cluster connection (notably the helm-diff phase of `helmfile
apply`). The original fixture chained `index` over the lookup result,
panicking with "index of untyped nil" during apply's diff rendering.
Guard every index with `default dict` so the template falls back to
"overwritten" when lookup is empty, while still resolving to the live
value ("init") when cluster access is available (--dry-run=server via
--template-args, or a real helm upgrade).
Signed-off-by: yxxhero <aiopsclub@163.com>
* feat: enable lookup() during apply/diff via --template-args in helm-diff
Thread --template-args into the helm-diff rendering path so that
`helmfile apply`/`diff --template-args="--dry-run=server"` resolves
Helm's lookup() function during the diff phase too. helm-diff supports
`--dry-run=server`, which explicitly "enables the cluster access ...
and the lookup template function".
Previously --template-args only reached chartify's pre-render (which is a
no-op for plain charts due to chartify's early-return when there is no
forceNamespace/patches/injections) and the final `helm template` of the
`template` subcommand. As a result `helmfile apply` on a lookup chart
rendered client-side during the diff phase.
Changes:
- pkg/state: add TemplateArgs to DiffOpts; append it in appendExtraDiffFlags
(reaches every helm-diff invocation: apply, standalone diff, interactive
sync), mirroring the existing flagsForTemplate handling.
- pkg/config + cmd: add --template-args to the diff/doctor commands and to
DiffConfigProvider, so lookup works for `helmfile diff` as well.
- pkg/app: populate DiffOpts.TemplateArgs from apply/diff/sync-interactive.
- docs/cli.md: correct the previous overpromising wording and document diff
support plus the nil-safe lookup guidance.
- tests: unit-test the TemplateArgs handling in appendExtraDiffFlags and
flagsForTemplate; integration lookup.sh now exercises apply with
--template-args="--dry-run=server".
Signed-off-by: yxxhero <aiopsclub@163.com>
* refactor: de-duplicate chartify template-args logic, add helmDefaults.templateArgs
Address review feedback on #2666:
1. Eliminate stale duplicated test helpers (issue_2444_test.go, issue_2355_test.go).
Both files intentionally copied the processChartification flag-building logic
with explicit SYNC WARNING comments, then drifted out of sync when #2666
refactored the production code (needsKubeConnection gate, user-args merge).
Extract the real logic into pure, unit-tested helpers
(buildChartifyTemplateArgs, commandRequiresCluster) and delete the copies.
2. Add unit coverage for the new chartify merge path: template +
--template-args=--dry-run=server now triggers kubeconfig/kube-context
injection (TestTemplateArgsDryRunTriggersKubeInjection,
TestTemplateArgsMergedBeforeInjection) — previously only covered by the
cluster-dependent integration test.
3. Add a negative integration case (lookup.sh assert_template_fallback)
verifying lookup() falls back to the default value WITHOUT --template-args,
guarding against a regression that silently always connects to the cluster.
4. Add helmDefaults.templateArgs for parity with diffArgs/syncArgs, so users
can enable lookup() support permanently instead of passing the flag on every
invocation. CLI --template-args overrides (does not merge with) the default.
Resolved via effectiveTemplateArgs, wired into the chartify, flagsForTemplate,
and appendExtraDiffFlags paths.
5. Minor: capitalize --template-args help text to match surrounding flags;
document helmDefaults.templateArgs precedence in docs/cli.md.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: cover helmDefaults->chartify composition; fix helm helm-diff typo
Address remaining review nits on #2666:
- Add TestHelmDefaultsTemplateArgsReachesChartify, a belt-and-suspenders test
for the processChartification composition (effectiveTemplateArgs ->
buildChartifyTemplateArgs), closing the last unit-level coverage gap for
helmDefaults.templateArgs reaching the chartify path.
- Fix pre-existing typo in cmd/bind_diff_flags.go: 'pass args to helm helm-diff'
-> 'Pass args to helm-diff' (doubled 'helm', lowercase).
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: correct 'helm helm-diff' typo in apply --diff-args help text
Sibling of the bind_diff_flags.go fix; the same doubled-'helm' typo and
lowercase help existed in cmd/apply.go's --diff-args registration, leaving
the apply and diff/doctor help strings inconsistent.
Signed-off-by: yxxhero <aiopsclub@163.com>
* docs: add helmDefaults.templateArgs to configuration reference
The complete helmfile.yaml schema in docs/configuration.md documents
diffArgs and syncArgs under helmDefaults but was missing the new
templateArgs field added in #2666. Add it beside syncArgs for
discoverability, noting the --template-args CLI override.
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
fix: clean up chartify temp directories after helm operations (#1799)
Chartify creates temporary output directories (e.g. /tmp/chartify<random>/)
during chart preparation for commands like build, template, and diff. These
directories were never tracked for cleanup, causing disk space to accumulate
over time with thousands of orphaned chartify* folders.
The existing clean() closure in PrepareChartify only removed generated values
files, not the chartify output directory itself. The chartified chart must
survive until all helm operations complete, so it could not be removed during
chart preparation.
This change:
- Adds chartifyTempDirTracker to HelmState (pointer-based to avoid copy-lock
issues from HelmState being copied in several places)
- Tracks chartify output dirs via addChartifyTempDir() after c.Chartify()
succeeds in processChartification
- Cleans them up via CleanupChartifyTempDirs() in WithPreparedCharts after
all helm operations complete
- Also removes empty parent temp directories (e.g. /tmp/chartify<random>/)
Fixes#1799
Signed-off-by: yxxhero <aiopsclub@163.com>
When multiple releases in a helmfile use the same remote chart, concurrent
helm upgrade/diff calls race on helm's internal repository cache file rename,
causing intermittent 'cannot rename: Access is denied' errors on Windows.
This fix introduces two layers of serialization:
1. withChartOperationLock (operation-level): wraps SyncRelease/DiffRelease
calls with a per-chart+version mutex. Only applies to remote charts
(release.ChartPath is empty); local/pre-fetched/OCI charts bypass the
lock entirely. Different charts remain fully parallel.
2. Per-chart+version download mutex in forcedDownloadChart/getOCIChart
(download-level): uses double-check locking to ensure only one
helm fetch runs per unique chart+version within a process.
The fix does NOT change chart paths passed to helm, preserving backward
compatibility with all existing behavior and tests.
Trade-off: same-chart releases are fully serialized (the entire helm
operation including deployment, not just download). This is unavoidable
without pre-fetching because helm downloads and deploys atomically.
Releases with different charts are unaffected.
Fixes#768
Signed-off-by: yxxhero <aiopsclub@163.com>
fix: ensure OCI charts are prepared for needed releases with --include-needs (#923)
When using --include-needs with a selector, releases included via needs
must have their charts prepared (pulled/exported) before diff/sync/apply
can process them. The core fix (ChartPrepareOptions.IncludeTransitiveNeeds
= c.IncludeNeeds()) was already in place, but ForEachState calls in
Diff/Template/Lint/Unittest/Sync/Apply still passed c.IncludeTransitiveNeeds()
instead of c.IncludeNeeds(), creating an inconsistency that would resurface
if SetFilter(true) were ever added.
Changes:
- Use c.IncludeNeeds() in ForEachState for all commands supporting
--include-needs (Diff, Template, Lint, Unittest, Sync, Apply, Doctor)
- Doctor is the only command with SetFilter(true), so this fixes a real
bug: helmfile doctor --include-needs was silently ignored for filtering
- Add explanatory doc comment on ForEachState parameter semantics
- Enhance exectest.Helm.ChartPull to create minimal chart files and track
pulls, enabling OCI chart testing
- Add resetChartCacheForTest() for test isolation from global chart cache
- Add regression tests for issue #923
Signed-off-by: yxxhero <11087727+yxxhero@users.noreply.github.com>
Signed-off-by: yxxhero <aiopsclub@163.com>
In nix/devbox environments, helm plugin directories are typically
symlinks into the Nix store. GetPluginVersion used entry.IsDir()
which does not follow symlinks, causing the plugin to be reported
as not installed. Follow symlinks with os.Stat before skipping
non-directory entries.
Signed-off-by: Shane Starcher <shane.starcher@gmail.com>
Co-authored-by: Shane Starcher <shane.starcher@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add `helmfile doctor` command for AI-assisted diff analysis
`helmfile doctor` runs `helmfile diff` and asks an OpenAI-compatible LLM to
summarize the changes and flag risks (data loss, security exposure, breaking
changes, downtime, performance, best-practice issues).
Key design decisions:
- When no LLM is configured, doctor is equivalent to `helmfile diff` with
one exception: --show-secrets is always forced off (secrets never reach
stdout, even without an LLM).
- Secrets are ALWAYS redacted via two layers: (1) ShowSecrets() forced to
false so helm-diff emits <REDACTED> placeholders; (2) a defense-in-depth
text redactor strips residual secret-looking content (Secret YAML blocks,
sensitive key/value lines, base64 blobs, JWT tokens) before LLM transmission.
- LLM configuration precedence: env (HELMFILE_LLM_*) < helmfile.yaml (llm:)
< CLI flags (--llm-*).
- Supports any OpenAI-compatible backend (OpenAI, Azure, One-API, LiteLLM,
Ollama, etc.) with automatic response_format fallback for backends that
don't support JSON mode.
- Prompt injection defense: release names and environment values are
JSON-encoded before insertion into the LLM prompt.
- Exit codes: 0 (success/low-risk), 2 (high-risk gate, bypass with --force),
1 (other errors). Helm-diff's 'detected changes' exit-2 is swallowed.
New packages:
- pkg/agent/llm: OpenAI-compatible client with JSON response parsing, mock
client for testing, prompt builder with injection defense.
- pkg/agent/doctor: secret redactor (state machine + regex), report renderer
(markdown + JSON), config resolver (env < yaml < flag merge).
Testing: 70+ unit tests covering redaction patterns, prompt injection,
response_format fallback, JSON parsing, yaml roundtrip, concurrency safety,
panic recovery, and error propagation. go test -race passes.
Documentation: full doctor section in docs/cli.md, llm: block reference in
docs/configuration.md, updated skills/helmfile for AI agents.
Signed-off-by: yxxhero <aiopsclub@163.com>
* docs: fix doctor equivalence wording per PR review
Per review feedback (PR #2660): the docs claimed doctor is 'equivalent to
helmfile diff — same flags, same output, same exit codes' in the unconfigured
path, but this over-promises because:
1. doctor --output is the report format (not helm-diff's output format)
2. helm-diff's --output is exposed as --diff-output in doctor
3. --show-secrets is silently ignored
Updated all three locations (cli.md, cmd/doctor.go Long + godoc, pkg/app/doctor.go
godoc) to say 'falls back to helmfile diff with --show-secrets forced off' and
explicitly note the --output / --diff-output flag difference.
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: yxxhero <aiopsclub@163.com>
* feat: parallel kubedog tracking with progress printer and safety valves
Rework kubedog integration so resource tracking runs in parallel with
helm upgrade/install, giving live progress output and recovering from
known helm/kubedog wedge conditions.
Core:
- kubedogTrackingHandle runs tracking in a background goroutine alongside
the helm subprocess (startBackgroundKubedogTracking); helm output is
buffered and replayed as a single block so it no longer interleaves
with progress ticks.
- Capture UID+generation baselines before handing off to helm so each
tracker waits until the resource actually changes (freshness gate).
Progress printer (pkg/kubedog/printer.go):
- Styled, auto-sized progress table with a heartbeat flusher, child (pod)
status roll-up, pre-ready pod-phase handling, multi-namespace support,
and optional color. PreviewBreakdown summarizes kept/filtered resources.
Safety valves (verify cluster state via the live API):
- Tracker-race valve (always on): when helm succeeds but a dyntracker
goroutine is wedged, poll the API and cancel the tracker so wait()
returns success instead of blocking until --track-timeout.
- Helm-stuck killer (opt-in via helmStuckGrace): if the cluster stays
converged while helm v4's hook waiter is wedged, SIGINT the helm
subprocess to recover.
- Failure watchdog (pkg/kubedog/watchdog.go): surface failing pods that
never made it into dyntracker's resource graph.
Options: trackFailedLogs, helmStuckGrace, trackTimeout, color
(Color/NoColor), and resource filtering (trackKinds/skipKinds/
trackResources). PersistentVolumeClaim support in resource classification.
Signed-off-by: Roman Mykhailiuk <romanm@cybellum.com>
* test: add unit tests for kubedog tracking
Cover the progress printer, resource classification, the failure
watchdog, helm-output trimming/dedup, the release hard-timeout helper,
and the color/track option plumbing.
Signed-off-by: Roman Mykhailiuk <romanm@cybellum.com>
* test: update golden logs, e2e snapshots, and values-id fixtures
Refresh pkg/app testapply/testdestroy golden logs, e2e template
snapshots, and the TestGenerateID values-id golden hashes for the new
kubedog progress output and the merged release struct layout.
Signed-off-by: Roman Mykhailiuk <romanm@cybellum.com>
* refactor: remove dead kubedog display code and dedupe tracker setup
Deep-review pass on the parallel kubedog tracking changes:
- Remove pkg/kubedog/display.go (308 lines) and display_test.go (453 lines).
These rendered progress for the legacy per-kind trackers that this PR
replaces; in the merged tree every function is unreferenced outside its
own tests. The new progressPrinter (printer.go) supersedes them.
TestMain (color.ForceColor for deterministic ANSI in tests) is preserved
in a new main_test.go.
- Dedupe trackWithKubedog: the post-helm fallback rebuilt the exact same
tracker options as buildReleaseTracker. Reuse buildReleaseTracker instead,
dropping ~40 lines of duplicated timeout/log/filter/tracker construction.
No behavior change; build, go vet, golangci-lint, and the kubedog/state
unit tests all pass.
Signed-off-by: yxxhero <aiopsclub@163.com>
* fix: stop waitForFreshness busy-looping the API after helm finishes
Once upstreamDoneCh closes it is always ready, so the select in
waitForFreshness stopped blocking on the ticker and re-ran probe() (a
live GET) as fast as the round-trip allowed for the whole 3s grace
window — hammering the API server once per tracked resource.
Track a local view of the channel and nil it out on first delivery so
the first hit records the timestamp (one fast retry, as intended) and
all subsequent polls are ticker-throttled. Functional behavior is
unchanged: return nil when fresh, errUpstreamDoneNoChange after grace.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: drop trailing blank line from helm4 OCI pull snapshots
The trailing-newline trim in helmexec.info() removes the blank line helm
prints after the OCI chart "Digest:" line. The helm3 (output.yaml)
snapshots never captured that line, but the helm4 (output-helm4.yaml)
snapshots for oci_chart_pull{,_direct,_once,_once2} and
issue_473_oci_chart_url_fetch still expected it, so they failed under
helm 4. Remove the blank line so the snapshots match the trimmed output.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: refresh diff-args integration goldens for styled release headers
DisplayAffectedReleases now emits a styled "========== Updated Releases
==========" header (matching the app/e2e goldens already updated by this
PR) and helmexec.info() trims the trailing blank after helm's install
status. Update the diff-args apply-stderr{,-helm4} and apply-live-
stderr{,-helm4} goldens accordingly so they match the actual stderr.
Signed-off-by: yxxhero <aiopsclub@163.com>
* test: drop trimmed blank line from v1-subhelmfile template golden
The trailing-newline trim in helmexec.info() removes the blank line helm
prints after '"incubator" has been added to your repositories'. Update
the v1-subhelmfile-multi-bases-with-array-values result and result-live
goldens so the template stdout comparison matches.
Signed-off-by: yxxhero <aiopsclub@163.com>
---------
Signed-off-by: Roman Mykhailiuk <romanm@cybellum.com>
Signed-off-by: yxxhero <aiopsclub@163.com>
Co-authored-by: Roman Mykhailiuk <romanm@cybellum.com>
fix: helmfile deps broken for OCI charts with underscores in path (#954)
For OCI charts with multi-segment paths (e.g., myrepo/path_with_underscores/example),
helmfile was putting the full path as the dependency name in the generated Chart.yaml.
Helm then reconstructed the OCI reference using this name, and underscores in the
path caused issues with helm's OCI reference handling during dependency update.
Fix: move the chart path prefix into the repository URL and use only the chart
basename as the dependency name, matching Helm's recommended Chart.yaml format
for OCI dependencies:
# Before (broken):
dependencies:
- name: path_with_underscores/example
repository: oci://harbor.custom.com
# After (fixed):
dependencies:
- name: example
repository: oci://harbor.custom.com/path_with_underscores
The resulting OCI reference is identical, but the dependency name is now clean.
Includes backward-compatibility fallback for old lock files that used the full
path as the dependency name.
Signed-off-by: yxxhero <aiopsclub@163.com>
Add appendServerSideFlagsForDiff to validate helm-diff plugin version
(v3.15.10+) before passing the --server-side flag to helm diff upgrade.
Extract resolveServerSideValue helper to share precedence logic between
upgrade and diff paths. Bump helm-diff recommended version to v3.15.10
across Dockerfiles, CI, and integration scripts.
Signed-off-by: yxxhero <aiopsclub@163.com>
go-getter v2 (used since v1.4) removed its built-in S3 getter, so helmfile's own AWS-SDK-v2 S3Getter was added to compensate. However the routing only handled the s3://bucket/key form (Getter==normal, Scheme==s3); the go-getter forced-getter vhost form s3::https://bucket.s3.region.amazonaws.com/key fell through to go-getter v2, which can no longer download S3 at all, producing 'error downloading'.
This restores 1.2.x behavior by:
- routing u.Getter==s3 URLs to the built-in S3Getter
- extending ParseS3Url to parse vhost/path-style amazonaws.com URLs (region/bucket/key), modeled on go-getter v1
- stripping the helmfile @<file> selector before deriving the S3 key
- auto-decompressing archive objects (tar.gz/zip/...) via go-getter v2 decompressors so the @<file> selector resolves inside a tarball, as go-getter v1 did
- cleaning up the cache dir on download/decompress failure (matching the GoGetter branch) and avoiding a nil-response panic in GetObject error handling
Fixes#2643
Signed-off-by: yxxhero <aiopsclub@163.com>
* 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>
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>