Files
helmfile/pkg/app/config.go
T
yxxhero e3f757d5ed feat: add --template-args flag to template/apply/sync for helm lookup() support (#2666)
* 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>
2026-06-28 12:19:33 +08:00

391 lines
6.7 KiB
Go

package app
import (
"go.uber.org/zap"
"github.com/helmfile/helmfile/pkg/agent/llm"
)
type ConfigProvider interface {
Args() string
HelmBinary() string
KustomizeBinary() string
EnableLiveOutput() bool
StripArgsValuesOnExitError() bool
DisableForceUpdate() bool
EnforcePluginVerification() bool
HelmOCIPlainHTTP() bool
SkipDeps() bool
SkipRefresh() bool
SequentialHelmfiles() bool
FileOrDir() string
KubeContext() string
Namespace() string
Chart() string
Selectors() []string
StateValuesSet() map[string]any
StateValuesFiles() []string
Kubeconfig() string
Env() string
loggingConfig
}
type DepsConfigProvider interface {
Args() string
SkipRepos() bool
IncludeTransitiveNeeds() bool
concurrencyConfig
}
type ReposConfigProvider interface {
Args() string
IncludeTransitiveNeeds() bool
}
type ApplyConfigProvider interface {
Args() string
PostRenderer() string
PostRendererArgs() []string
SkipSchemaValidation() bool
Cascade() string
HideNotes() bool
TakeOwnership() bool
ServerSide() string
SuppressOutputLineRegex() []string
Values() []string
Set() []string
SkipCRDs() bool
SkipDeps() bool
SkipRefresh() bool
Wait() bool
WaitRetries() int
WaitForJobs() bool
Timeout() int
IncludeTests() bool
Suppress() []string
SuppressSecrets() bool
ShowSecrets() bool
NoHooks() bool
SuppressDiff() bool
DetailedExitcode() bool
StripTrailingCR() bool
Color() bool
NoColor() bool
Context() int
DiffOutput() string
Validate() bool
SkipCleanup() bool
SkipDiffOnInstall() bool
DiffArgs() string
SyncArgs() string
TemplateArgs() string
SyncReleaseLabels() bool
DAGConfig
TrackMode() string
TrackTimeout() int
TrackLogs() bool
TrackFailedLogs() bool
HelmStuckGrace() int
TrackFailOnError() bool
Description() string
concurrencyConfig
interactive
loggingConfig
valuesControlMode
}
type SyncConfigProvider interface {
Args() string
PostRenderer() string
SkipSchemaValidation() bool
PostRendererArgs() []string
HideNotes() bool
TakeOwnership() bool
ServerSide() string
Cascade() string
Values() []string
Set() []string
SkipCRDs() bool
SkipDeps() bool
SkipRefresh() bool
Wait() bool
WaitRetries() int
WaitForJobs() bool
Timeout() int
SyncArgs() string
Validate() bool
SkipNeeds() bool
IncludeNeeds() bool
IncludeTransitiveNeeds() bool
SyncReleaseLabels() bool
TrackMode() string
TrackTimeout() int
TrackLogs() bool
TrackFailedLogs() bool
HelmStuckGrace() int
TrackFailOnError() bool
Color() bool
NoColor() bool
Description() string
TemplateArgs() string
DAGConfig
concurrencyConfig
interactive
loggingConfig
valuesControlMode
}
type DiffConfigProvider interface {
Args() string
PostRenderer() string
PostRendererArgs() []string
SkipSchemaValidation() bool
SuppressOutputLineRegex() []string
Values() []string
Set() []string
Validate() bool
SkipCRDs() bool
SkipDeps() bool
SkipRefresh() bool
IncludeTests() bool
Suppress() []string
SuppressSecrets() bool
ShowSecrets() bool
NoHooks() bool
SuppressDiff() bool
SkipDiffOnInstall() bool
DiffArgs() string
TemplateArgs() string
DAGConfig
DetailedExitcode() bool
StripTrailingCR() bool
Color() bool
NoColor() bool
Context() int
DiffOutput() string
TakeOwnership() bool
ServerSide() string
concurrencyConfig
valuesControlMode
}
// DoctorConfigProvider is the configuration surface required by App.Doctor.
// It embeds DiffConfigProvider because doctor is a strict superset of diff:
// the same helm-diff flags plus a handful of AI-specific knobs.
//
// The LLM-related accessors return the flag-sourced config only; env and
// helmfile.yaml sources are resolved by the doctor package itself
// (see pkg/agent/doctor/config.go).
type DoctorConfigProvider interface {
DiffConfigProvider
// FlagLLMConfig returns the LLM configuration sourced from --llm-* flags.
// Empty fields mean "flag not set" and do not override env/yaml.
FlagLLMConfig() llm.Config
// Force skips the high-risk exit-code-2 gate.
Force() bool
// DoctorOutput returns the report format ("text" or "json"). Named
// DoctorOutput to avoid colliding with DiffConfigProvider.DiffOutput
// which is the helm-diff plugin output format.
DoctorOutput() string
}
type DestroyConfigProvider interface {
Args() string
Cascade() string
SkipDeps() bool
SkipRefresh() bool
SkipCharts() bool
DeleteWait() bool
DeleteTimeout() int
NoColor() bool
interactive
loggingConfig
concurrencyConfig
}
type TestConfigProvider interface {
Args() string
SkipDeps() bool
SkipRefresh() bool
Timeout() int
Cleanup() bool
Logs() bool
concurrencyConfig
}
type LintConfigProvider interface {
Args() string
Values() []string
Set() []string
SkipDeps() bool
SkipRefresh() bool
SkipCleanup() bool
DAGConfig
concurrencyConfig
}
type UnittestConfigProvider interface {
Args() string
Values() []string
Set() []string
FailFast() bool
Color() bool
DebugPlugin() bool
SkipDeps() bool
SkipRefresh() bool
SkipCleanup() bool
DAGConfig
concurrencyConfig
}
type FetchConfigProvider interface {
SkipDeps() bool
SkipRefresh() bool
OutputDir() string
OutputDirTemplate() string
WriteOutput() bool
concurrencyConfig
}
type TemplateConfigProvider interface {
Args() string
PostRenderer() string
PostRendererArgs() []string
SkipSchemaValidation() bool
Values() []string
Set() []string
OutputDirTemplate() string
Validate() bool
SkipDeps() bool
SkipRefresh() bool
SkipCleanup() bool
SkipTests() bool
OutputDir() string
IncludeCRDs() bool
NoHooks() bool
KubeVersion() string
ShowOnly() []string
TemplateArgs() string
DAGConfig
concurrencyConfig
}
type DAGConfig interface {
SkipNeeds() bool
IncludeNeeds() bool
IncludeTransitiveNeeds() bool
EnforceNeedsAreInstalled() bool
}
type WriteValuesConfigProvider interface {
Values() []string
Set() []string
OutputFileTemplate() string
SkipDeps() bool
SkipRefresh() bool
SkipCleanup() bool
IncludeTransitiveNeeds() bool
concurrencyConfig
}
type StatusesConfigProvider interface {
Args() string
concurrencyConfig
}
type StateConfigProvider interface {
EmbedValues() bool
}
type DAGConfigProvider any
type concurrencyConfig interface {
Concurrency() int
}
type loggingConfig interface {
Logger() *zap.SugaredLogger
}
type interactive interface {
Interactive() bool
}
type ListConfigProvider interface {
Output() string
SkipCharts() bool
}
type CacheConfigProvider any
type InitConfigProvider interface {
Force() bool
}
type CreateConfigProvider interface {
Name() string
OutputDir() string
Force() bool
loggingConfig
}
type PrintEnvConfigProvider interface {
Output() string
}
// reset/reuse values helm cli flags handling for apply/sync/diff
type valuesControlMode interface {
ReuseValues() bool
ResetValues() bool
}