From 2e52967d686cae4df390feca8265b837f1c8f9d5 Mon Sep 17 00:00:00 2001 From: Kerstin Albers Date: Thu, 6 Feb 2025 14:31:33 +0100 Subject: [PATCH 1/5] feat: add template args to be used for template and within apply Signed-off-by: Kerstin Albers --- cmd/apply.go | 1 + cmd/template.go | 1 + docs/index.md | 2 ++ pkg/app/app.go | 2 ++ pkg/app/app_test.go | 10 ++++++++++ pkg/app/config.go | 2 ++ pkg/config/apply.go | 9 ++++++++- pkg/config/template.go | 7 +++++++ pkg/state/state.go | 6 ++++++ 9 files changed, 39 insertions(+), 1 deletion(-) diff --git a/cmd/apply.go b/cmd/apply.go index 6b5a23f4..b4b598ab 100644 --- a/cmd/apply.go +++ b/cmd/apply.go @@ -42,6 +42,7 @@ func NewApplyCmd(globalCfg *config.GlobalImpl) *cobra.Command { f.BoolVar(&applyOptions.StripTrailingCR, "strip-trailing-cr", false, "strip trailing carriage return on input") f.StringVar(&applyOptions.DiffArgs, "diff-args", "", `pass args to helm helm-diff`) f.StringVar(&applyOptions.SyncArgs, "sync-args", "", `pass args to helm upgrade`) + f.StringVar(&applyOptions.TemplateArgs, "template-args", "", `pass args to helm template`) f.StringVar(&globalCfg.GlobalOptions.Args, "args", "", "pass args to helm exec") f.BoolVar(&applyOptions.SkipCleanup, "skip-cleanup", false, "Stop cleaning up temporary values generated by helmfile and helm-secrets. Useful for debugging. Don't use in production for security") f.BoolVar(&applyOptions.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present") diff --git a/cmd/template.go b/cmd/template.go index 6cb81fea..5bb146a0 100644 --- a/cmd/template.go +++ b/cmd/template.go @@ -50,6 +50,7 @@ func NewTemplateCmd(globalCfg *config.GlobalImpl) *cobra.Command { f.BoolVar(&templateOptions.SkipSchemaValidation, "skip-schema-validation", false, `pass skip-schema-validation to "helm template" or "helm upgrade --install"`) f.StringVar(&templateOptions.KubeVersion, "kube-version", "", `pass --kube-version to "helm template". Overrides kubeVersion in helmfile.yaml`) f.StringArrayVar(&templateOptions.ShowOnly, "show-only", nil, `pass --show-only to "helm template"`) + f.StringVar(&templateOptions.TemplateArgs, "template-args", "", `pass args to helm template`) return cmd } diff --git a/docs/index.md b/docs/index.md index 59d3442f..a1a2c12c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -187,6 +187,8 @@ helmDefaults: - "--suppress-secrets" syncArgs: - "--labels=app.kubernetes.io/managed-by=helmfile" + templateArgs: + - "--dry-run=server" # verify the chart before upgrading (only works with packaged charts not directories) (default false) verify: true keyring: path/to/keyring.gpg diff --git a/pkg/app/app.go b/pkg/app/app.go index aa73fbb2..7da166de 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -236,6 +236,7 @@ func (a *App) Template(c TemplateConfigProvider) error { Set: c.Set(), Values: c.Values(), KubeVersion: c.KubeVersion(), + TemplateArgs: c.TemplateArgs(), }, func() { ok, errs = a.template(run, c) }) @@ -406,6 +407,7 @@ func (a *App) Apply(c ApplyConfigProvider) error { Validate: c.Validate(), Concurrency: c.Concurrency(), IncludeTransitiveNeeds: c.IncludeNeeds(), + TemplateArgs: c.TemplateArgs(), }, func() { matched, updated, es := a.apply(run, c) diff --git a/pkg/app/app_test.go b/pkg/app/app_test.go index cf38aa2e..25d11b6b 100644 --- a/pkg/app/app_test.go +++ b/pkg/app/app_test.go @@ -2109,6 +2109,7 @@ type configImpl struct { includeTransitiveNeeds bool skipCharts bool kubeVersion string + templateArgs string } func (c configImpl) Selectors() []string { @@ -2207,6 +2208,10 @@ func (c configImpl) KubeVersion() string { return c.kubeVersion } +func (c configImpl) TemplateArgs() string { + return c.templateArgs +} + func (c configImpl) SkipSchemaValidation() bool { return c.skipSchemaValidation } @@ -2246,6 +2251,7 @@ type applyConfig struct { skipDiffOnInstall bool syncArgs string diffArgs string + templateArgs string logger *zap.SugaredLogger wait bool waitRetries int @@ -2398,6 +2404,10 @@ func (a applyConfig) DiffArgs() string { return a.diffArgs } +func (a applyConfig) TemplateArgs() string { + return a.templateArgs +} + // helmfile-template-only flags func (a applyConfig) IncludeCRDs() bool { return a.includeCRDs diff --git a/pkg/app/config.go b/pkg/app/config.go index e699d86f..a3d76d7e 100644 --- a/pkg/app/config.go +++ b/pkg/app/config.go @@ -79,6 +79,7 @@ type ApplyConfigProvider interface { DiffArgs() string SyncArgs() string + TemplateArgs() string SyncReleaseLabels() bool @@ -232,6 +233,7 @@ type TemplateConfigProvider interface { NoHooks() bool KubeVersion() string ShowOnly() []string + TemplateArgs() string DAGConfig diff --git a/pkg/config/apply.go b/pkg/config/apply.go index 81a9a195..006956a3 100644 --- a/pkg/config/apply.go +++ b/pkg/config/apply.go @@ -68,11 +68,13 @@ type ApplyOptions struct { SyncArgs string // HideNotes is the hide notes flag HideNotes bool - // TakeOwnership is true if the ownership should be taken TakeOwnership bool SyncReleaseLabels bool + + // TemplateArgs is the list of arguments to pass to helm template + TemplateArgs string } // NewApply creates a new Apply @@ -273,3 +275,8 @@ func (a *ApplyImpl) TakeOwnership() bool { func (a *ApplyImpl) SyncReleaseLabels() bool { return a.ApplyOptions.SyncReleaseLabels } + +// TemplateArgs returns the TemplateArgs. +func (a *ApplyImpl) TemplateArgs() string { + return a.ApplyOptions.TemplateArgs +} diff --git a/pkg/config/template.go b/pkg/config/template.go index 90c82691..b12736a1 100644 --- a/pkg/config/template.go +++ b/pkg/config/template.go @@ -44,6 +44,8 @@ type TemplateOptions struct { KubeVersion string // Propagate '--show-only` to helm template ShowOnly []string + // TemplateArgs + TemplateArgs string } // NewTemplateOptions creates a new Apply @@ -158,3 +160,8 @@ func (t *TemplateImpl) KubeVersion() string { func (t *TemplateImpl) ShowOnly() []string { return t.TemplateOptions.ShowOnly } + +// TemplateArgs returns the TemplateArgs +func (t *TemplateImpl) TemplateArgs() string { + return t.TemplateOptions.TemplateArgs +} diff --git a/pkg/state/state.go b/pkg/state/state.go index af26d017..54b0b9f7 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -1160,6 +1160,7 @@ type ChartPrepareOptions struct { KubeVersion string Set []string Values []string + TemplateArgs string // Delete wait DeleteWait bool DeleteTimeout int @@ -1337,6 +1338,10 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre chartifyOpts.Validate = opts.Validate + if (helmfileCommand == "template" || helmfileCommand == "apply") && opts.TemplateArgs != "" { + chartifyOpts.TemplateArgs = opts.TemplateArgs + } + chartifyOpts.KubeVersion = st.getKubeVersion(release, opts.KubeVersion) chartifyOpts.ApiVersions = st.getApiVersions(release) @@ -1543,6 +1548,7 @@ type TemplateOpts struct { ShowOnly []string // Propagate '--skip-schema-validation' to helmv3 template and helm install SkipSchemaValidation bool + TemplateArgs string } type TemplateOpt interface{ Apply(*TemplateOpts) } From 228aab70a95d26ddd02529857557dd40d946fbf7 Mon Sep 17 00:00:00 2001 From: Kerstin Albers Date: Fri, 21 Feb 2025 13:47:46 +0100 Subject: [PATCH 2/5] test: add test for prepare charts with template args Signed-off-by: Kerstin Albers --- pkg/app/run.go | 19 +++++++- pkg/state/state.go | 23 +++++---- pkg/state/state_test.go | 103 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 11 deletions(-) diff --git a/pkg/app/run.go b/pkg/app/run.go index 2beab11a..811cbb6a 100644 --- a/pkg/app/run.go +++ b/pkg/app/run.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/fatih/color" + "github.com/helmfile/chartify" "github.com/helmfile/helmfile/pkg/helmexec" "github.com/helmfile/helmfile/pkg/state" @@ -42,6 +43,14 @@ func (r *Run) askForConfirmation(msg string) bool { return AskForConfirmation(msg) } +type Chartifier struct { + runner *chartify.Runner +} + +func (c *Chartifier) Chartify(release, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) { + return c.runner.Chartify(release, dirOrChart, opts...) +} + func (r *Run) prepareChartsIfNeeded(helmfileCommand string, dir string, concurrency int, opts state.ChartPrepareOptions) (map[state.PrepareChartKey]string, error) { // Skip chart preparation for certain commands skipCommands := []string{"write-values", "list"} @@ -49,7 +58,15 @@ func (r *Run) prepareChartsIfNeeded(helmfileCommand string, dir string, concurre return nil, nil } - releaseToChart, errs := r.state.PrepareCharts(r.helm, dir, concurrency, helmfileCommand, opts) + chartifier := &Chartifier{ + runner: chartify.New( + chartify.HelmBin(r.state.DefaultHelmBinary), + chartify.KustomizeBin(r.state.DefaultKustomizeBinary), + chartify.UseHelm3(true), + chartify.WithLogf(r.state.Logger().Debugf)), + } + + releaseToChart, errs := r.state.PrepareCharts(r.helm, chartifier, dir, concurrency, helmfileCommand, opts) if len(errs) > 0 { return nil, fmt.Errorf("%v", errs) } diff --git a/pkg/state/state.go b/pkg/state/state.go index 54b0b9f7..2a31dca1 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -1209,6 +1209,16 @@ type PrepareChartKey struct { Namespace, Name, KubeContext string } +func (st *HelmState) Logger() *zap.SugaredLogger { + return st.logger +} + +type Chartifier interface { + // Chartify creates a temporary Helm chart from a directory or a remote chart, and applies various transformations. + // Returns the full path to the temporary directory containing the generated chart if succeeded. + Chartify(release, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) +} + // PrepareCharts creates temporary directories of charts. // // Each resulting "chart" can be one of the followings: @@ -1220,10 +1230,10 @@ type PrepareChartKey struct { // When running `helmfile template` on helm v2, or `helmfile lint` on both helm v2 and v3, // PrepareCharts will download and untar charts for linting and templating. // -// Otheriwse, if a chart is not a helm chart, it will call "chartify" to turn it into a chart. +// Otherwise, if a chart is not a helm chart, it will call "chartify" to turn it into a chart. // // If exists, it will also patch resources by json patches, strategic-merge patches, and injectors. -func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurrency int, helmfileCommand string, opts ChartPrepareOptions) (map[PrepareChartKey]string, []error) { +func (st *HelmState) PrepareCharts(helm helmexec.Interface, chartifier Chartifier, dir string, concurrency int, helmfileCommand string, opts ChartPrepareOptions) (map[PrepareChartKey]string, []error) { if !opts.SkipResolve { updated, err := st.ResolveDeps() if err != nil { @@ -1317,13 +1327,6 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre skipDeps := (!isLocal && !chartFetchedByGoGetter) || skipDepsGlobal || skipDepsRelease || skipDepsDefault if chartification != nil && helmfileCommand != "pull" { - c := chartify.New( - chartify.HelmBin(st.DefaultHelmBinary), - chartify.KustomizeBin(st.DefaultKustomizeBinary), - chartify.UseHelm3(true), - chartify.WithLogf(st.logger.Debugf), - ) - chartifyOpts := chartification.Opts if skipDeps { @@ -1357,7 +1360,7 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre } chartifyOpts.SetFlags = append(chartifyOpts.SetFlags, flags...) - out, err := c.Chartify(release.Name, chartPath, chartify.WithChartifyOpts(chartifyOpts)) + out, err := chartifier.Chartify(release.Name, chartPath, chartify.WithChartifyOpts(chartifyOpts)) if err != nil { results <- &chartPrepareResult{err: err} return diff --git a/pkg/state/state_test.go b/pkg/state/state_test.go index 57774b23..70be5035 100644 --- a/pkg/state/state_test.go +++ b/pkg/state/state_test.go @@ -4,11 +4,13 @@ import ( "fmt" "io" "os" + "path" "path/filepath" "reflect" "testing" "github.com/Masterminds/semver/v3" + "github.com/helmfile/chartify" "github.com/helmfile/vals" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -2974,6 +2976,107 @@ func TestDiffpareSyncReleases(t *testing.T) { } } +// capturingChartifier implements state.Chartifier for tests. +type capturingChartifier struct { + mChartify func(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) + capturedArgs []chartifyArgs +} + +type chartifyArgs struct { + release string + dirOrChart string + opts []chartify.ChartifyOption +} + +func (c *capturingChartifier) Chartify(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) { + c.capturedArgs = append(c.capturedArgs, chartifyArgs{release: release, dirOrChart: dirOrChart, opts: opts}) + return c.mChartify(release, dirOrChart, opts...) +} + +func TestPrepareCharts_invokesChartifierWithTemplateArgs(t *testing.T) { + tests := []struct { + name string + chartifier *capturingChartifier + dir string + concurrency int + command string + opts ChartPrepareOptions + expectedArgs []chartifyArgs + helmDefaults *HelmSpec + }{ + { + name: "template command", + chartifier: &capturingChartifier{ + mChartify: func(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) { + return "someTempDir", nil + }, + }, + dir: "someChartPath", + concurrency: 1, + command: "template", + opts: ChartPrepareOptions{ + SkipDeps: true, + TemplateArgs: "someArgs", + }, + helmDefaults: &HelmSpec{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpDir, err := os.MkdirTemp("", "test-prepare-charts-*") + if err != nil { + t.Fatalf("setup temp test dir: %v", err) + } + defer os.RemoveAll(tmpDir) + + err = os.Mkdir(path.Join(tmpDir, tt.dir), 0755) + if err != nil { + t.Fatalf("setup chart dir: %v", err) + } + + release := ReleaseSpec{ + Name: tt.name, + } + releases := []ReleaseSpec{ + release, + } + + state := &HelmState{ + basePath: tmpDir, + ReleaseSetSpec: ReleaseSetSpec{ + Releases: releases, + HelmDefaults: *tt.helmDefaults, + }, + logger: logger, + valsRuntime: valsRuntime, + fs: filesystem.DefaultFileSystem(), + RenderedValues: map[string]any{}, + } + helm := &exectest.Helm{ + Lists: map[exectest.ListKey]string{}, + Helm3: true, + } + + _, errs := state.PrepareCharts(helm, tt.chartifier, path.Join(tmpDir, tt.dir), tt.concurrency, tt.command, tt.opts) + + require.Len(t, errs, 0) + require.Len(t, tt.chartifier.capturedArgs, 1) + + appliedChartifyOpts := &chartify.ChartifyOpts{} + + for _, o := range tt.chartifier.capturedArgs[0].opts { + err = o.SetChartifyOption(appliedChartifyOpts) + if err != nil { + t.Fatalf("set captured chartify options: %v", err) + } + } + + require.Equal(t, tt.opts.TemplateArgs, appliedChartifyOpts.TemplateArgs) + }) + } +} + func TestPrepareSyncReleases(t *testing.T) { tests := []struct { name string From bc3ceabee70c91e9fe4a1231b8f80e2fb697beb3 Mon Sep 17 00:00:00 2001 From: Kerstin Albers Date: Thu, 6 Mar 2025 16:09:15 +0100 Subject: [PATCH 3/5] chore: fix linter Signed-off-by: Kerstin Albers --- pkg/state/state.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/state/state.go b/pkg/state/state.go index 2a31dca1..d6e27703 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -1551,7 +1551,7 @@ type TemplateOpts struct { ShowOnly []string // Propagate '--skip-schema-validation' to helmv3 template and helm install SkipSchemaValidation bool - TemplateArgs string + TemplateArgs string } type TemplateOpt interface{ Apply(*TemplateOpts) } From f53fb4f37fbb4b88134584fc57f38015d8a297a5 Mon Sep 17 00:00:00 2001 From: KATechDev Date: Tue, 30 Sep 2025 17:15:18 +0200 Subject: [PATCH 4/5] change dry-run to be used per default on sync and apply for chartify to achieve consistent behavior. For template prodive option --template-args Signed-off-by: Kerstin Albers --- cmd/apply.go | 1 - cmd/template.go | 2 +- pkg/app/app.go | 6 +- pkg/app/app_test.go | 20 ++-- pkg/app/run.go | 19 +--- pkg/config/apply.go | 13 +-- pkg/config/template.go | 4 +- pkg/state/state.go | 48 +++++--- pkg/state/state_test.go | 103 ------------------ test/integration/lib/output.sh | 12 +- test/integration/run.sh | 1 + test/integration/test-cases/lookup.sh | 62 +++++++++++ .../input-chartify/helmfile.yaml.gotmpl | 17 +++ .../lookup/input-init/helmfile.yaml.gotmpl | 14 +++ .../lookup/input-plain/helmfile.yaml.gotmpl | 15 +++ 15 files changed, 172 insertions(+), 165 deletions(-) create mode 100644 test/integration/test-cases/lookup.sh create mode 100644 test/integration/test-cases/lookup/input-chartify/helmfile.yaml.gotmpl create mode 100644 test/integration/test-cases/lookup/input-init/helmfile.yaml.gotmpl create mode 100644 test/integration/test-cases/lookup/input-plain/helmfile.yaml.gotmpl diff --git a/cmd/apply.go b/cmd/apply.go index b4b598ab..6b5a23f4 100644 --- a/cmd/apply.go +++ b/cmd/apply.go @@ -42,7 +42,6 @@ func NewApplyCmd(globalCfg *config.GlobalImpl) *cobra.Command { f.BoolVar(&applyOptions.StripTrailingCR, "strip-trailing-cr", false, "strip trailing carriage return on input") f.StringVar(&applyOptions.DiffArgs, "diff-args", "", `pass args to helm helm-diff`) f.StringVar(&applyOptions.SyncArgs, "sync-args", "", `pass args to helm upgrade`) - f.StringVar(&applyOptions.TemplateArgs, "template-args", "", `pass args to helm template`) f.StringVar(&globalCfg.GlobalOptions.Args, "args", "", "pass args to helm exec") f.BoolVar(&applyOptions.SkipCleanup, "skip-cleanup", false, "Stop cleaning up temporary values generated by helmfile and helm-secrets. Useful for debugging. Don't use in production for security") f.BoolVar(&applyOptions.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present") diff --git a/cmd/template.go b/cmd/template.go index 5bb146a0..a2eeffee 100644 --- a/cmd/template.go +++ b/cmd/template.go @@ -50,7 +50,7 @@ func NewTemplateCmd(globalCfg *config.GlobalImpl) *cobra.Command { f.BoolVar(&templateOptions.SkipSchemaValidation, "skip-schema-validation", false, `pass skip-schema-validation to "helm template" or "helm upgrade --install"`) f.StringVar(&templateOptions.KubeVersion, "kube-version", "", `pass --kube-version to "helm template". Overrides kubeVersion in helmfile.yaml`) f.StringArrayVar(&templateOptions.ShowOnly, "show-only", nil, `pass --show-only to "helm template"`) - f.StringVar(&templateOptions.TemplateArgs, "template-args", "", `pass args to helm template`) + f.StringVar(&templateOptions.TemplateArgs, "template-args", "", `pass extra args to "helm template" (e.g., --dry-run=server)`) return cmd } diff --git a/pkg/app/app.go b/pkg/app/app.go index 7da166de..b7b99a1a 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -371,6 +371,8 @@ func (a *App) Sync(c SyncConfigProvider) error { IncludeTransitiveNeeds: c.IncludeNeeds(), Validate: c.Validate(), Concurrency: c.Concurrency(), + // Ensure lookup during chartify pre-render connects to cluster + TemplateArgs: "--dry-run=server", }, func() { ok, errs = a.sync(run, c) }) @@ -407,7 +409,8 @@ func (a *App) Apply(c ApplyConfigProvider) error { Validate: c.Validate(), Concurrency: c.Concurrency(), IncludeTransitiveNeeds: c.IncludeNeeds(), - TemplateArgs: c.TemplateArgs(), + // Ensure lookup during chartify pre-render connects to cluster + TemplateArgs: "--dry-run=server", }, func() { matched, updated, es := a.apply(run, c) @@ -1954,6 +1957,7 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) { KubeVersion: c.KubeVersion(), ShowOnly: c.ShowOnly(), SkipSchemaValidation: c.SkipSchemaValidation(), + TemplateArgs: c.TemplateArgs(), } return st.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), c.Validate(), opts) }) diff --git a/pkg/app/app_test.go b/pkg/app/app_test.go index 25d11b6b..17473257 100644 --- a/pkg/app/app_test.go +++ b/pkg/app/app_test.go @@ -2109,7 +2109,6 @@ type configImpl struct { includeTransitiveNeeds bool skipCharts bool kubeVersion string - templateArgs string } func (c configImpl) Selectors() []string { @@ -2208,10 +2207,6 @@ func (c configImpl) KubeVersion() string { return c.kubeVersion } -func (c configImpl) TemplateArgs() string { - return c.templateArgs -} - func (c configImpl) SkipSchemaValidation() bool { return c.skipSchemaValidation } @@ -2220,6 +2215,11 @@ func (c configImpl) ShowOnly() []string { return nil } +// TemplateArgs satisfies TemplateConfigProvider for template-specific extra flags +func (c configImpl) TemplateArgs() string { + return "" +} + type applyConfig struct { args string cascade string @@ -2251,7 +2251,6 @@ type applyConfig struct { skipDiffOnInstall bool syncArgs string diffArgs string - templateArgs string logger *zap.SugaredLogger wait bool waitRetries int @@ -2404,10 +2403,6 @@ func (a applyConfig) DiffArgs() string { return a.diffArgs } -func (a applyConfig) TemplateArgs() string { - return a.templateArgs -} - // helmfile-template-only flags func (a applyConfig) IncludeCRDs() bool { return a.includeCRDs @@ -2456,6 +2451,11 @@ func (a applyConfig) ShowOnly() []string { return a.showOnly } +// TemplateArgs satisfies TemplateConfigProvider for template-specific extra flags +func (a applyConfig) TemplateArgs() string { + return "" +} + func (a applyConfig) HideNotes() bool { return a.hideNotes } diff --git a/pkg/app/run.go b/pkg/app/run.go index 811cbb6a..2beab11a 100644 --- a/pkg/app/run.go +++ b/pkg/app/run.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/fatih/color" - "github.com/helmfile/chartify" "github.com/helmfile/helmfile/pkg/helmexec" "github.com/helmfile/helmfile/pkg/state" @@ -43,14 +42,6 @@ func (r *Run) askForConfirmation(msg string) bool { return AskForConfirmation(msg) } -type Chartifier struct { - runner *chartify.Runner -} - -func (c *Chartifier) Chartify(release, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) { - return c.runner.Chartify(release, dirOrChart, opts...) -} - func (r *Run) prepareChartsIfNeeded(helmfileCommand string, dir string, concurrency int, opts state.ChartPrepareOptions) (map[state.PrepareChartKey]string, error) { // Skip chart preparation for certain commands skipCommands := []string{"write-values", "list"} @@ -58,15 +49,7 @@ func (r *Run) prepareChartsIfNeeded(helmfileCommand string, dir string, concurre return nil, nil } - chartifier := &Chartifier{ - runner: chartify.New( - chartify.HelmBin(r.state.DefaultHelmBinary), - chartify.KustomizeBin(r.state.DefaultKustomizeBinary), - chartify.UseHelm3(true), - chartify.WithLogf(r.state.Logger().Debugf)), - } - - releaseToChart, errs := r.state.PrepareCharts(r.helm, chartifier, dir, concurrency, helmfileCommand, opts) + releaseToChart, errs := r.state.PrepareCharts(r.helm, dir, concurrency, helmfileCommand, opts) if len(errs) > 0 { return nil, fmt.Errorf("%v", errs) } diff --git a/pkg/config/apply.go b/pkg/config/apply.go index 006956a3..3f22d59b 100644 --- a/pkg/config/apply.go +++ b/pkg/config/apply.go @@ -72,9 +72,6 @@ type ApplyOptions struct { TakeOwnership bool SyncReleaseLabels bool - - // TemplateArgs is the list of arguments to pass to helm template - TemplateArgs string } // NewApply creates a new Apply @@ -256,6 +253,11 @@ func (a *ApplyImpl) SuppressOutputLineRegex() []string { return a.ApplyOptions.SuppressOutputLineRegex } +// TemplateArgs returns extra args for helm template; not applicable to apply, return empty. +func (a *ApplyImpl) TemplateArgs() string { + return "" +} + // SyncArgs returns the SyncArgs. func (a *ApplyImpl) SyncArgs() string { return a.ApplyOptions.SyncArgs @@ -275,8 +277,3 @@ func (a *ApplyImpl) TakeOwnership() bool { func (a *ApplyImpl) SyncReleaseLabels() bool { return a.ApplyOptions.SyncReleaseLabels } - -// TemplateArgs returns the TemplateArgs. -func (a *ApplyImpl) TemplateArgs() string { - return a.ApplyOptions.TemplateArgs -} diff --git a/pkg/config/template.go b/pkg/config/template.go index b12736a1..0d3f0faa 100644 --- a/pkg/config/template.go +++ b/pkg/config/template.go @@ -44,7 +44,7 @@ type TemplateOptions struct { KubeVersion string // Propagate '--show-only` to helm template ShowOnly []string - // TemplateArgs + // TemplateArgs are extra args appended to helm template (e.g., --dry-run=server) TemplateArgs string } @@ -161,7 +161,7 @@ func (t *TemplateImpl) ShowOnly() []string { return t.TemplateOptions.ShowOnly } -// TemplateArgs returns the TemplateArgs +// TemplateArgs returns the extra args for helm template. func (t *TemplateImpl) TemplateArgs() string { return t.TemplateOptions.TemplateArgs } diff --git a/pkg/state/state.go b/pkg/state/state.go index d6e27703..20f19310 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -1209,16 +1209,6 @@ type PrepareChartKey struct { Namespace, Name, KubeContext string } -func (st *HelmState) Logger() *zap.SugaredLogger { - return st.logger -} - -type Chartifier interface { - // Chartify creates a temporary Helm chart from a directory or a remote chart, and applies various transformations. - // Returns the full path to the temporary directory containing the generated chart if succeeded. - Chartify(release, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) -} - // PrepareCharts creates temporary directories of charts. // // Each resulting "chart" can be one of the followings: @@ -1233,7 +1223,9 @@ type Chartifier interface { // Otherwise, if a chart is not a helm chart, it will call "chartify" to turn it into a chart. // // If exists, it will also patch resources by json patches, strategic-merge patches, and injectors. -func (st *HelmState) PrepareCharts(helm helmexec.Interface, chartifier Chartifier, dir string, concurrency int, helmfileCommand string, opts ChartPrepareOptions) (map[PrepareChartKey]string, []error) { +// +//nolint:gocognit // High complexity due to orchestration; refactoring is out of scope here. +func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurrency int, helmfileCommand string, opts ChartPrepareOptions) (map[PrepareChartKey]string, []error) { if !opts.SkipResolve { updated, err := st.ResolveDeps() if err != nil { @@ -1327,6 +1319,13 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, chartifier Chartifie skipDeps := (!isLocal && !chartFetchedByGoGetter) || skipDepsGlobal || skipDepsRelease || skipDepsDefault if chartification != nil && helmfileCommand != "pull" { + c := chartify.New( + chartify.HelmBin(st.DefaultHelmBinary), + chartify.KustomizeBin(st.DefaultKustomizeBinary), + chartify.UseHelm3(true), + chartify.WithLogf(st.logger.Debugf), + ) + chartifyOpts := chartification.Opts if skipDeps { @@ -1341,8 +1340,23 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, chartifier Chartifie chartifyOpts.Validate = opts.Validate - if (helmfileCommand == "template" || helmfileCommand == "apply") && opts.TemplateArgs != "" { - chartifyOpts.TemplateArgs = opts.TemplateArgs + // Ensure chartify's internal helm template uses the correct kube context for lookup to work + if kc := st.kubeConnectionFlags(release); len(kc) > 0 { + if chartifyOpts.TemplateArgs != "" { + chartifyOpts.TemplateArgs = strings.TrimSpace(chartifyOpts.TemplateArgs + " " + strings.Join(kc, " ")) + } else { + chartifyOpts.TemplateArgs = strings.Join(kc, " ") + } + } + // If the current command provided extra template args (e.g., --dry-run=server for `helmfile template`), + // pass them through to the chartify helm template as well to make lookup behavior consistent. + if opts.TemplateArgs != "" { + extra := strings.Join(argparser.CollectArgs(opts.TemplateArgs), " ") + if chartifyOpts.TemplateArgs != "" { + chartifyOpts.TemplateArgs = strings.TrimSpace(chartifyOpts.TemplateArgs + " " + extra) + } else { + chartifyOpts.TemplateArgs = extra + } } chartifyOpts.KubeVersion = st.getKubeVersion(release, opts.KubeVersion) @@ -1360,7 +1374,7 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, chartifier Chartifie } chartifyOpts.SetFlags = append(chartifyOpts.SetFlags, flags...) - out, err := chartifier.Chartify(release.Name, chartPath, chartify.WithChartifyOpts(chartifyOpts)) + out, err := c.Chartify(release.Name, chartPath, chartify.WithChartifyOpts(chartifyOpts)) if err != nil { results <- &chartPrepareResult{err: err} return @@ -1551,7 +1565,8 @@ type TemplateOpts struct { ShowOnly []string // Propagate '--skip-schema-validation' to helmv3 template and helm install SkipSchemaValidation bool - TemplateArgs string + // TemplateArgs are extra args appended to "helm template" (e.g., "--dry-run=server") + TemplateArgs string } type TemplateOpt interface{ Apply(*TemplateOpts) } @@ -2932,6 +2947,9 @@ func (st *HelmState) flagsForTemplate(helm helmexec.Interface, release *ReleaseS flags = st.appendChartDownloadFlags(flags, release) flags = st.appendShowOnlyFlags(flags, showOnly) flags = st.appendSkipSchemaValidationFlags(flags, release, skipSchemaValidation) + if opt != nil && opt.TemplateArgs != "" { + flags = append(flags, argparser.CollectArgs(opt.TemplateArgs)...) + } common, files, err := st.namespaceAndValuesFlags(helm, release, workerIndex) if err != nil { diff --git a/pkg/state/state_test.go b/pkg/state/state_test.go index 70be5035..57774b23 100644 --- a/pkg/state/state_test.go +++ b/pkg/state/state_test.go @@ -4,13 +4,11 @@ import ( "fmt" "io" "os" - "path" "path/filepath" "reflect" "testing" "github.com/Masterminds/semver/v3" - "github.com/helmfile/chartify" "github.com/helmfile/vals" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -2976,107 +2974,6 @@ func TestDiffpareSyncReleases(t *testing.T) { } } -// capturingChartifier implements state.Chartifier for tests. -type capturingChartifier struct { - mChartify func(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) - capturedArgs []chartifyArgs -} - -type chartifyArgs struct { - release string - dirOrChart string - opts []chartify.ChartifyOption -} - -func (c *capturingChartifier) Chartify(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) { - c.capturedArgs = append(c.capturedArgs, chartifyArgs{release: release, dirOrChart: dirOrChart, opts: opts}) - return c.mChartify(release, dirOrChart, opts...) -} - -func TestPrepareCharts_invokesChartifierWithTemplateArgs(t *testing.T) { - tests := []struct { - name string - chartifier *capturingChartifier - dir string - concurrency int - command string - opts ChartPrepareOptions - expectedArgs []chartifyArgs - helmDefaults *HelmSpec - }{ - { - name: "template command", - chartifier: &capturingChartifier{ - mChartify: func(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) { - return "someTempDir", nil - }, - }, - dir: "someChartPath", - concurrency: 1, - command: "template", - opts: ChartPrepareOptions{ - SkipDeps: true, - TemplateArgs: "someArgs", - }, - helmDefaults: &HelmSpec{}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tmpDir, err := os.MkdirTemp("", "test-prepare-charts-*") - if err != nil { - t.Fatalf("setup temp test dir: %v", err) - } - defer os.RemoveAll(tmpDir) - - err = os.Mkdir(path.Join(tmpDir, tt.dir), 0755) - if err != nil { - t.Fatalf("setup chart dir: %v", err) - } - - release := ReleaseSpec{ - Name: tt.name, - } - releases := []ReleaseSpec{ - release, - } - - state := &HelmState{ - basePath: tmpDir, - ReleaseSetSpec: ReleaseSetSpec{ - Releases: releases, - HelmDefaults: *tt.helmDefaults, - }, - logger: logger, - valsRuntime: valsRuntime, - fs: filesystem.DefaultFileSystem(), - RenderedValues: map[string]any{}, - } - helm := &exectest.Helm{ - Lists: map[exectest.ListKey]string{}, - Helm3: true, - } - - _, errs := state.PrepareCharts(helm, tt.chartifier, path.Join(tmpDir, tt.dir), tt.concurrency, tt.command, tt.opts) - - require.Len(t, errs, 0) - require.Len(t, tt.chartifier.capturedArgs, 1) - - appliedChartifyOpts := &chartify.ChartifyOpts{} - - for _, o := range tt.chartifier.capturedArgs[0].opts { - err = o.SetChartifyOption(appliedChartifyOpts) - if err != nil { - t.Fatalf("set captured chartify options: %v", err) - } - } - - require.Equal(t, tt.opts.TemplateArgs, appliedChartifyOpts.TemplateArgs) - }) - } -} - func TestPrepareSyncReleases(t *testing.T) { tests := []struct { name string diff --git a/test/integration/lib/output.sh b/test/integration/lib/output.sh index 05db3d5b..762298cf 100644 --- a/test/integration/lib/output.sh +++ b/test/integration/lib/output.sh @@ -3,22 +3,22 @@ declare -i tests_total=0 function info () { - tput bold; tput setaf 4; echo -n "INFO: "; tput sgr0; echo "${@}" + tput bold >/dev/null 2>&1 || true; tput setaf 4 >/dev/null 2>&1 || true; echo -n "INFO: "; tput sgr0 >/dev/null 2>&1 || true; echo "${@}" } function warn () { - tput bold; tput setaf 3; echo -n "WARN: "; tput sgr0; echo "${@}" + tput bold >/dev/null 2>&1 || true; tput setaf 3 >/dev/null 2>&1 || true; echo -n "WARN: "; tput sgr0 >/dev/null 2>&1 || true; echo "${@}" } function fail () { - tput bold; tput setaf 1; echo -n "FAIL: "; tput sgr0; echo "${@}" + tput bold >/dev/null 2>&1 || true; tput setaf 1 >/dev/null 2>&1 || true; echo -n "FAIL: "; tput sgr0 >/dev/null 2>&1 || true; echo "${@}" exit 1 } function test_start () { - tput bold; tput setaf 6; echo -n "TEST: "; tput sgr0; echo "${@}" + tput bold >/dev/null 2>&1 || true; tput setaf 6 >/dev/null 2>&1 || true; echo -n "TEST: "; tput sgr0 >/dev/null 2>&1 || true; echo "${@}" } function test_pass () { tests_total=$((tests_total+1)) - tput bold; tput setaf 2; echo -n "PASS: "; tput sgr0; echo "${@}" + tput bold >/dev/null 2>&1 || true; tput setaf 2 >/dev/null 2>&1 || true; echo -n "PASS: "; tput sgr0 >/dev/null 2>&1 || true; echo "${@}" } function all_tests_passed () { - tput bold; tput setaf 2; echo -n "PASS: "; tput sgr0; echo "${tests_total} tests passed" + tput bold >/dev/null 2>&1 || true; tput setaf 2 >/dev/null 2>&1 || true; echo -n "PASS: "; tput sgr0 >/dev/null 2>&1 || true; echo "${tests_total} tests passed" } diff --git a/test/integration/run.sh b/test/integration/run.sh index d0abedfb..e606c8ec 100755 --- a/test/integration/run.sh +++ b/test/integration/run.sh @@ -103,6 +103,7 @@ ${kubectl} create namespace ${test_ns} || fail "Could not create namespace ${tes . ${dir}/test-cases/issue-1749.sh . ${dir}/test-cases/issue-1893.sh . ${dir}/test-cases/state-values-set-cli-args-in-environments.sh +. ${dir}/test-cases/lookup.sh # ALL DONE ----------------------------------------------------------------------------------------------------------- diff --git a/test/integration/test-cases/lookup.sh b/test/integration/test-cases/lookup.sh new file mode 100644 index 00000000..f0ed2b3c --- /dev/null +++ b/test/integration/test-cases/lookup.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# Verify Helm `lookup` works under helmfile for both chartify and non-chartify scenarios. +# +# Assumptions (prepared by test/integration/run.sh): +# - A minikube cluster is running, context=minikube +# - Namespace ${test_ns} is created +# - Variables ${helmfile}, ${kubectl}, and ${cases_dir} are defined + +set -euo pipefail + +reset_live_secret() { + info "Resetting live secret to key=init" + ${kubectl} delete secret my-secret -n ${test_ns} >/dev/null 2>&1 || true + init_hf="${cases_dir}/lookup/input-init/helmfile.yaml.gotmpl" + ${helmfile} -f "${init_hf}" sync -q +} + +assert_template_outputs() { + reset_live_secret + local hf_file="$1" + info "Templating ${hf_file} with --template-args=\"--dry-run=server\"" + out=$(mktemp) + ${helmfile} -f "${hf_file}" template --template-args="--dry-run=server" >"${out}" + grep -q "key: init" "${out}" || fail "template output did not contain 'key: init'" + rm -f "${out}" +} + +assert_cluster_key_is_init() { + v=$(${kubectl} get secret my-secret -o jsonpath='{.data.key}' | base64 -d) + [ "${v}" = "init" ] || fail "expected live secret key to be 'init', got '${v}'" +} + +assert_apply() { + local hf_file="$1" + reset_live_secret + info "Applying ${hf_file}" + ${helmfile} -f "${hf_file}" apply -q || fail "apply failed" + assert_cluster_key_is_init +} + +assert_sync() { + local hf_file="$1" + reset_live_secret + info "Syncing ${hf_file}" + ${helmfile} -f "${hf_file}" sync -q || fail "sync failed" + assert_cluster_key_is_init +} + +# Non-chartify scenario +plain_hf="${cases_dir}/lookup/input-plain/helmfile.yaml.gotmpl" +assert_template_outputs "${plain_hf}" +assert_apply "${plain_hf}" +assert_sync "${plain_hf}" +test_pass "lookup without chartify" + +# Chartify scenario (e.g. forceNamespace triggers chartify) +chartify_hf="${cases_dir}/lookup/input-chartify/helmfile.yaml.gotmpl" +assert_template_outputs "${chartify_hf}" +assert_apply "${chartify_hf}" +assert_sync "${chartify_hf}" +test_pass "lookup with chartify" + diff --git a/test/integration/test-cases/lookup/input-chartify/helmfile.yaml.gotmpl b/test/integration/test-cases/lookup/input-chartify/helmfile.yaml.gotmpl new file mode 100644 index 00000000..1b7506e0 --- /dev/null +++ b/test/integration/test-cases/lookup/input-chartify/helmfile.yaml.gotmpl @@ -0,0 +1,17 @@ +releases: + - name: lookup-test + chart: ../../../charts/raw + namespace: {{ .Namespace }} + # forceNamespace triggers chartify + forceNamespace: {{ .Namespace }} + values: + - templates: + - | + apiVersion: v1 + kind: Secret + metadata: + name: lookup-result + type: Opaque + stringData: + # When lookup can reach the cluster, this resolves to the current live value (init) + key: {{`{{ index (index (lookup "v1" "Secret" .Release.Namespace "my-secret") "data") "key" | b64dec | default "overwritten" }}`}} diff --git a/test/integration/test-cases/lookup/input-init/helmfile.yaml.gotmpl b/test/integration/test-cases/lookup/input-init/helmfile.yaml.gotmpl new file mode 100644 index 00000000..abfbc656 --- /dev/null +++ b/test/integration/test-cases/lookup/input-init/helmfile.yaml.gotmpl @@ -0,0 +1,14 @@ +releases: + - name: setup-init + chart: ../../../charts/raw + namespace: {{ .Namespace }} + values: + - templates: + - | + apiVersion: v1 + kind: Secret + metadata: + name: my-secret + type: Opaque + stringData: + key: "init" diff --git a/test/integration/test-cases/lookup/input-plain/helmfile.yaml.gotmpl b/test/integration/test-cases/lookup/input-plain/helmfile.yaml.gotmpl new file mode 100644 index 00000000..daa9af24 --- /dev/null +++ b/test/integration/test-cases/lookup/input-plain/helmfile.yaml.gotmpl @@ -0,0 +1,15 @@ +releases: + - name: lookup-test + chart: ../../../charts/raw + namespace: {{ .Namespace }} + forceNamespace: {{ .Namespace }} + values: + - templates: + - | + apiVersion: v1 + kind: Secret + metadata: + name: lookup-result + type: Opaque + stringData: + key: {{`{{ index (index (lookup "v1" "Secret" .Release.Namespace "my-secret") "data") "key" | b64dec | default "overwritten" }}`}} From f05d0c71e6744e0eff20fe9e05c46f9f4b0ebafa Mon Sep 17 00:00:00 2001 From: Kerstin Albers Date: Wed, 1 Oct 2025 10:48:44 +0200 Subject: [PATCH 5/5] provide --template-args as parameter to allow overwriting, defaults to --sry-run=server for sync and apply Signed-off-by: Kerstin Albers --- cmd/apply.go | 1 + cmd/sync.go | 1 + pkg/app/app.go | 7 +++---- pkg/app/config.go | 1 + pkg/config/apply.go | 6 ++++-- pkg/config/sync.go | 7 +++++++ 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/cmd/apply.go b/cmd/apply.go index 6b5a23f4..84209400 100644 --- a/cmd/apply.go +++ b/cmd/apply.go @@ -67,6 +67,7 @@ func NewApplyCmd(globalCfg *config.GlobalImpl) *cobra.Command { f.BoolVar(&applyOptions.SkipSchemaValidation, "skip-schema-validation", false, `pass --skip-schema-validation to "helm template" or "helm upgrade --install"`) f.StringVar(&applyOptions.Cascade, "cascade", "", "pass cascade to helm exec, default: background") f.StringArrayVar(&applyOptions.SuppressOutputLineRegex, "suppress-output-line-regex", nil, "a list of regex patterns to suppress output lines from the diff output") + f.StringVar(&applyOptions.TemplateArgs, "template-args", "--dry-run=server", `pass extra args to helm template during chartify pre-render (default: --dry-run=server)`) return cmd } diff --git a/cmd/sync.go b/cmd/sync.go index 3bd80e6f..d9336826 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -53,6 +53,7 @@ func NewSyncCmd(globalCfg *config.GlobalImpl) *cobra.Command { f.StringArrayVar(&syncOptions.PostRendererArgs, "post-renderer-args", nil, `pass --post-renderer-args to "helm template" or "helm upgrade --install"`) f.BoolVar(&syncOptions.SkipSchemaValidation, "skip-schema-validation", false, `pass --skip-schema-validation to "helm template" or "helm upgrade --install"`) f.StringVar(&syncOptions.Cascade, "cascade", "", "pass cascade to helm exec, default: background") + f.StringVar(&syncOptions.TemplateArgs, "template-args", "--dry-run=server", `pass extra args to helm template during chartify pre-render (default: --dry-run=server)`) return cmd } diff --git a/pkg/app/app.go b/pkg/app/app.go index b7b99a1a..0aea82e9 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -371,8 +371,7 @@ func (a *App) Sync(c SyncConfigProvider) error { IncludeTransitiveNeeds: c.IncludeNeeds(), Validate: c.Validate(), Concurrency: c.Concurrency(), - // Ensure lookup during chartify pre-render connects to cluster - TemplateArgs: "--dry-run=server", + TemplateArgs: c.TemplateArgs(), }, func() { ok, errs = a.sync(run, c) }) @@ -409,8 +408,8 @@ func (a *App) Apply(c ApplyConfigProvider) error { Validate: c.Validate(), Concurrency: c.Concurrency(), IncludeTransitiveNeeds: c.IncludeNeeds(), - // Ensure lookup during chartify pre-render connects to cluster - TemplateArgs: "--dry-run=server", + // Use user-provided template args; default is set via flag ("--dry-run=server") + TemplateArgs: c.TemplateArgs(), }, func() { matched, updated, es := a.apply(run, c) diff --git a/pkg/app/config.go b/pkg/app/config.go index a3d76d7e..8caea3c8 100644 --- a/pkg/app/config.go +++ b/pkg/app/config.go @@ -117,6 +117,7 @@ type SyncConfigProvider interface { IncludeTransitiveNeeds() bool SyncReleaseLabels() bool + TemplateArgs() string DAGConfig diff --git a/pkg/config/apply.go b/pkg/config/apply.go index 3f22d59b..a4a760d2 100644 --- a/pkg/config/apply.go +++ b/pkg/config/apply.go @@ -72,6 +72,8 @@ type ApplyOptions struct { TakeOwnership bool SyncReleaseLabels bool + // TemplateArgs for chartify pre-render (default provided by CLI flag) + TemplateArgs string } // NewApply creates a new Apply @@ -253,9 +255,9 @@ func (a *ApplyImpl) SuppressOutputLineRegex() []string { return a.ApplyOptions.SuppressOutputLineRegex } -// TemplateArgs returns extra args for helm template; not applicable to apply, return empty. +// TemplateArgs returns extra args for helm template func (a *ApplyImpl) TemplateArgs() string { - return "" + return a.ApplyOptions.TemplateArgs } // SyncArgs returns the SyncArgs. diff --git a/pkg/config/sync.go b/pkg/config/sync.go index 8d68aba8..ddb7fcd0 100644 --- a/pkg/config/sync.go +++ b/pkg/config/sync.go @@ -46,6 +46,9 @@ type SyncOptions struct { TakeOwnership bool // SyncReleaseLabels is the sync release labels flag SyncReleaseLabels bool + // TemplateArgs are extra args appended to helm template during chartify pre-render for sync + // Defaults to "--dry-run=server" via flag. + TemplateArgs string } // NewSyncOptions creates a new Apply @@ -180,3 +183,7 @@ func (t *SyncImpl) TakeOwnership() bool { func (t *SyncImpl) SyncReleaseLabels() bool { return t.SyncOptions.SyncReleaseLabels } + +func (t *SyncImpl) TemplateArgs() string { + return t.SyncOptions.TemplateArgs +}