From 912971c9239414dfb296aae0321465de28c7e760 Mon Sep 17 00:00:00 2001 From: Hubertbits <170125456+hubertbits@users.noreply.github.com> Date: Wed, 16 Apr 2025 15:44:19 +0200 Subject: [PATCH] pkg/config: Split impl from options and integrate flag handler including tests Signed-off-by: yxxhero --- pkg/config/README.md | 118 ++++++++++++++++ pkg/config/apply.go | 229 ++++---------------------------- pkg/config/apply_impl.go | 204 ++++++++++++++++++++++++++++ pkg/config/apply_test.go | 57 ++++++++ pkg/config/build.go | 19 --- pkg/config/build_impl.go | 20 +++ pkg/config/cache.go | 14 -- pkg/config/cache_impl.go | 15 +++ pkg/config/deps.go | 29 ---- pkg/config/deps_impl.go | 30 +++++ pkg/config/destroy.go | 39 ------ pkg/config/destroy_impl.go | 40 ++++++ pkg/config/diff.go | 178 +++---------------------- pkg/config/diff_impl.go | 160 ++++++++++++++++++++++ pkg/config/diff_test.go | 17 +++ pkg/config/fetch.go | 29 ---- pkg/config/fetch_impl.go | 30 +++++ pkg/config/flag_utils.go | 17 +++ pkg/config/global.go | 184 ------------------------- pkg/config/global_impl.go | 190 ++++++++++++++++++++++++++ pkg/config/init.go | 19 --- pkg/config/init_impl.go | 20 +++ pkg/config/linit_impl.go | 54 ++++++++ pkg/config/lint.go | 53 -------- pkg/config/list.go | 24 ---- pkg/config/list_impl.go | 25 ++++ pkg/config/options.go | 68 ++-------- pkg/config/options_test.go | 61 +++++++++ pkg/config/repos.go | 19 --- pkg/config/repos_impl.go | 20 +++ pkg/config/show-dag.go | 14 -- pkg/config/show-dag_impl.go | 15 +++ pkg/config/status.go | 24 ---- pkg/config/status_impl.go | 25 ++++ pkg/config/sync.go | 161 ++++------------------ pkg/config/sync_impl.go | 134 +++++++++++++++++++ pkg/config/sync_test.go | 23 ++++ pkg/config/template.go | 141 +++----------------- pkg/config/template_impl.go | 125 +++++++++++++++++ pkg/config/template_test.go | 17 +++ pkg/config/test.go | 44 ------ pkg/config/test_impl.go | 45 +++++++ pkg/config/write-values.go | 44 ------ pkg/config/write-values_impl.go | 45 +++++++ 44 files changed, 1601 insertions(+), 1238 deletions(-) create mode 100644 pkg/config/README.md create mode 100644 pkg/config/apply_impl.go create mode 100644 pkg/config/apply_test.go create mode 100644 pkg/config/build_impl.go create mode 100644 pkg/config/cache_impl.go create mode 100644 pkg/config/deps_impl.go create mode 100644 pkg/config/destroy_impl.go create mode 100644 pkg/config/diff_impl.go create mode 100644 pkg/config/diff_test.go create mode 100644 pkg/config/fetch_impl.go create mode 100644 pkg/config/flag_utils.go create mode 100644 pkg/config/global_impl.go create mode 100644 pkg/config/init_impl.go create mode 100644 pkg/config/linit_impl.go create mode 100644 pkg/config/list_impl.go create mode 100644 pkg/config/options_test.go create mode 100644 pkg/config/repos_impl.go create mode 100644 pkg/config/show-dag_impl.go create mode 100644 pkg/config/status_impl.go create mode 100644 pkg/config/sync_impl.go create mode 100644 pkg/config/sync_test.go create mode 100644 pkg/config/template_impl.go create mode 100644 pkg/config/template_test.go create mode 100644 pkg/config/test_impl.go create mode 100644 pkg/config/write-values_impl.go diff --git a/pkg/config/README.md b/pkg/config/README.md new file mode 100644 index 00000000..5d7dc7c6 --- /dev/null +++ b/pkg/config/README.md @@ -0,0 +1,118 @@ +# Config Package + +## Overview + +The `pkg/config` package contains configuration options for various Helmfile commands. These options control the behavior of commands like `apply`, `diff`, `template`, `sync`, and others. + +## File Structure + +``` +pkg/config/ +├── options.go # Base options interfaces and common functionality +├── options_test.go # Tests for base options +├── global.go # Global options shared across all commands +├── global_impl.go # Implementation of global options +├── apply.go # ApplyOptions implementation for 'apply' command +├── apply_impl.go # Implementation of ApplyOptions +├── apply_test.go # Tests for ApplyOptions +├── build.go # BuildOptions implementation for 'build' command +├── build_impl.go # Implementation of BuildOptions +├── cache.go # CacheOptions implementation for 'cache' command +├── cache_impl.go # Implementation of CacheOptions +├── deps.go # DepsOptions implementation for 'deps' command +├── deps_impl.go # Implementation of DepsOptions +├── destroy.go # DestroyOptions implementation for 'destroy' command +├── destroy_impl.go # Implementation of DestroyOptions +├── destroy_test.go # Tests for DestroyOptions +├── diff.go # DiffOptions implementation for 'diff' command +├── diff_impl.go # Implementation of DiffOptions +├── diff_test.go # Tests for DiffOptions +├── fetch.go # FetchOptions implementation for 'fetch' command +├── fetch_impl.go # Implementation of FetchOptions +├── fetch_test.go # Tests for FetchOptions +├── init.go # InitOptions implementation for 'init' command +├── init_impl.go # Implementation of InitOptions +├── lint.go # LintOptions implementation for 'lint' command +├── linit_impl.go # Implementation of LintOptions +├── lint_test.go # Tests for LintOptions +├── list.go # ListOptions implementation for 'list' command +├── list_impl.go # Implementation of ListOptions +├── list_test.go # Tests for ListOptions +├── repos.go # ReposOptions implementation for 'repos' command +├── repos_impl.go # Implementation of ReposOptions +├── show-dag.go # ShowDAGOptions implementation for 'show-dag' command +├── show-dag_impl.go # Implementation of ShowDAGOptions +├── status.go # StatusOptions implementation for 'status' command +├── status_impl.go # Implementation of StatusOptions +├── status_test.go # Tests for StatusOptions +├── sync.go # SyncOptions implementation for 'sync' command +├── sync_impl.go # Implementation of SyncOptions +├── sync_test.go # Tests for SyncOptions +├── template.go # TemplateOptions implementation for 'template' command +├── template_impl.go # Implementation of TemplateOptions +├── template_test.go # Tests for TemplateOptions +├── test.go # TestOptions implementation for 'test' command +├── test_impl.go # Implementation of TestOptions +├── write-values.go # WriteValuesOptions implementation for 'write-values' command +├── write-values_impl.go # Implementation of WriteValuesOptions +└── common/ # Common option types shared across commands + ├── bool_flag.go # Boolean flag implementation + ├── string_flag.go # String flag implementation + └── array_flag.go # String array flag implementation +``` + +## Components + +- **Options Interfaces**: Base interfaces that define common option behaviors +- **Global Options**: Configuration options shared across all commands +- **Command-specific Options**: Implementations for each command (e.g., `ApplyOptions`, `DiffOptions`) +- **Implementation Classes**: Classes that combine global options with command-specific options +- **Flag Handling**: Each options struct implements the `FlagHandler` interface from the `pkg/flags` package +- **Common Flag Types**: Reusable flag implementations in the `common` subpackage + +## Key Features + +- **Command Configuration**: Each command has its own options type that controls its behavior +- **Flag Handling**: Options implement the `FlagHandler` interface to receive flag values +- **Default Values**: Options provide sensible defaults that can be overridden +- **Validation**: Some options include validation logic to ensure valid configurations +- **Implementation Pattern**: Each command has both an options struct and an implementation struct that combines global and command-specific options + +## Usage + +Options objects are typically created by factory methods and populated with values from command-line flags. They are then passed to command implementations to control their behavior. + +### Example: + +```go +// Create options +opts := config.NewApplyOptions() + +// Handle flags +handled := opts.HandleFlag("include-crds", &includeCRDs, true) +if !handled { + // Flag wasn't recognized +} + +// Create implementation with global options +globalOpts := config.NewGlobalImpl(&config.GlobalOptions{}) +impl := config.NewApplyImpl(globalOpts, opts) + +// Use in command +cmd.Execute(impl) +``` + +## Testing + +All option implementations should have comprehensive tests in this package. Tests should verify: + +1. Default values are set correctly +2. Flags are handled properly +3. The boolean return value from `HandleFlag` correctly indicates whether a flag was recognized +4. Option validation works as expected + +## Related Packages + +- `pkg/flags`: Provides flag registration and handling functionality +- `pkg/factory`: Creates properly configured options for commands +- `pkg/app`: Uses options to control command execution diff --git a/pkg/config/apply.go b/pkg/config/apply.go index 5aa27eb8..e0ecc445 100644 --- a/pkg/config/apply.go +++ b/pkg/config/apply.go @@ -1,6 +1,9 @@ package config -import "github.com/helmfile/helmfile/pkg/common" +import ( + "github.com/helmfile/helmfile/pkg/common" + "github.com/helmfile/helmfile/pkg/flags" +) // ApplyOptoons is the options for the apply command type ApplyOptions struct { @@ -81,216 +84,34 @@ type ApplyOptions struct { // NewApply creates a new Apply func NewApplyOptions() *ApplyOptions { - newOptions := &ApplyOptions{ - IncludeCRDsFlag: common.NewBoolFlag(false), - SkipCRDsFlag: common.NewBoolFlag(false), - } + newOptions := &ApplyOptions{} + newOptions.Initialize() return newOptions } -// ApplyImpl is impl for applyOptions -type ApplyImpl struct { - *GlobalImpl - *ApplyOptions +func (o *ApplyOptions) Initialize() { + flags.EnsureBoolFlag(&o.IncludeCRDsFlag, false) + flags.EnsureBoolFlag(&o.SkipCRDsFlag, false) } -// NewApplyImpl creates a new ApplyImpl -func NewApplyImpl(g *GlobalImpl, a *ApplyOptions) *ApplyImpl { - return &ApplyImpl{ - GlobalImpl: g, - ApplyOptions: a, +func (o *ApplyOptions) HandleFlag(name string, value interface{}, changed bool) bool { + switch name { + case "include-crds": + if changed { + if boolVal, ok := value.(*bool); ok { + o.IncludeCRDsFlag.Set(*boolVal) + } + } + return true + case "skip-crds": + if changed { + if boolVal, ok := value.(*bool); ok { + o.SkipCRDsFlag.Set(*boolVal) + } + } + return true } -} -// Set returns the set. -func (a *ApplyImpl) Set() []string { - return a.ApplyOptions.Set -} - -// Concurrency returns the concurrency. -func (a *ApplyImpl) Concurrency() int { - return a.ApplyOptions.Concurrency -} - -// Context returns the context. -func (a *ApplyImpl) Context() int { - return a.ApplyOptions.Context -} - -// DetailedExitcode returns the detailed exitcode. -func (a *ApplyImpl) DetailedExitcode() bool { - return a.ApplyOptions.DetailedExitcode -} - -// StripTrailingCR is true if trailing carriage returns should be stripped during diffing -func (a *ApplyImpl) StripTrailingCR() bool { - return a.ApplyOptions.StripTrailingCR -} - -// DiffOutput returns the diff output. -func (a *ApplyImpl) DiffOutput() string { - return a.Output -} - -// IncludeNeeds returns the include needs. -func (a *ApplyImpl) IncludeNeeds() bool { - return a.ApplyOptions.IncludeNeeds || a.IncludeTransitiveNeeds() -} - -// IncludeTests returns the include tests. -func (a *ApplyImpl) IncludeTests() bool { - return a.ApplyOptions.IncludeTests -} - -// IncludeTransitiveNeeds returns the include transitive needs. -func (a *ApplyImpl) IncludeTransitiveNeeds() bool { - return a.ApplyOptions.IncludeTransitiveNeeds -} - -// ShowSecrets returns the show secrets. -func (a *ApplyImpl) ShowSecrets() bool { - return a.ApplyOptions.ShowSecrets -} - -// NoHooks skips hooks. -func (a *ApplyImpl) NoHooks() bool { - return a.ApplyOptions.NoHooks -} - -// SkipCRDs returns the skip CRDs. -func (a *ApplyImpl) SkipCRDs() bool { - return a.ApplyOptions.SkipCRDsFlag.Value() -} - -// IncludeCRDs returns the include CRDs. -func (a *ApplyImpl) IncludeCRDs() bool { - return a.ApplyOptions.IncludeCRDsFlag.Value() -} - -// ShouldIncludeCRDs returns true if CRDs should be included. -func (a *ApplyImpl) ShouldIncludeCRDs() bool { - includeCRDsExplicit := a.IncludeCRDsFlag.WasExplicitlySet() && a.IncludeCRDsFlag.Value() - skipCRDsExplicit := a.SkipCRDsFlag.WasExplicitlySet() && !a.SkipCRDsFlag.Value() - - return includeCRDsExplicit || skipCRDsExplicit -} - -// SkipCleanup returns the skip cleanup. -func (a *ApplyImpl) SkipCleanup() bool { - return a.ApplyOptions.SkipCleanup -} - -// SkipDiffOnInstall returns the skip diff on install. -func (a *ApplyImpl) SkipDiffOnInstall() bool { - return a.ApplyOptions.SkipDiffOnInstall -} - -// DiffArgs is the list of arguments to pass to helm-diff. -func (a *ApplyImpl) DiffArgs() string { - return a.ApplyOptions.DiffArgs -} - -// SkipNeeds returns the skip needs. -func (a *ApplyImpl) SkipNeeds() bool { - if !a.IncludeNeeds() { - return a.ApplyOptions.SkipNeeds - } return false } - -// Suppress returns the suppress. -func (a *ApplyImpl) Suppress() []string { - return a.ApplyOptions.Suppress -} - -// SuppressDiff returns the suppress diff. -func (a *ApplyImpl) SuppressDiff() bool { - return a.ApplyOptions.SuppressDiff -} - -// SuppressSecrets returns the suppress secrets. -func (a *ApplyImpl) SuppressSecrets() bool { - return a.ApplyOptions.SuppressSecrets -} - -// Validate returns the validate. -func (a *ApplyImpl) Validate() bool { - return a.ApplyOptions.Validate -} - -// Values returns the values. -func (a *ApplyImpl) Values() []string { - return a.ApplyOptions.Values -} - -// Wait returns the wait. -func (a *ApplyImpl) Wait() bool { - return a.ApplyOptions.Wait -} - -// WaitRetries returns the wait retries. -func (a *ApplyImpl) WaitRetries() int { - return a.ApplyOptions.WaitRetries -} - -// WaitForJobs returns the wait for jobs. -func (a *ApplyImpl) WaitForJobs() bool { - return a.ApplyOptions.WaitForJobs -} - -// ReuseValues returns the ReuseValues. -func (a *ApplyImpl) ReuseValues() bool { - if !a.ResetValues() { - return a.ApplyOptions.ReuseValues - } - return false -} - -func (a *ApplyImpl) ResetValues() bool { - return a.ApplyOptions.ResetValues -} - -// PostRenderer returns the PostRenderer. -func (a *ApplyImpl) PostRenderer() string { - return a.ApplyOptions.PostRenderer -} - -// PostRendererArgs returns the PostRendererArgs. -func (a *ApplyImpl) PostRendererArgs() []string { - return a.ApplyOptions.PostRendererArgs -} - -// SkipSchemaValidation returns the SkipSchemaValidation. -func (a *ApplyImpl) SkipSchemaValidation() bool { - return a.ApplyOptions.SkipSchemaValidation -} - -// Cascade returns cascade flag -func (a *ApplyImpl) Cascade() string { - return a.ApplyOptions.Cascade -} - -// SuppressOutputLineRegex returns the SuppressOutputLineRegex. -func (a *ApplyImpl) SuppressOutputLineRegex() []string { - return a.ApplyOptions.SuppressOutputLineRegex -} - -// SyncArgs returns the SyncArgs. -func (a *ApplyImpl) SyncArgs() string { - return a.ApplyOptions.SyncArgs -} - -// HideNotes returns the HideNotes. -func (a *ApplyImpl) HideNotes() bool { - return a.ApplyOptions.HideNotes -} - -// TakeOwnership returns the TakeOwnership. -func (a *ApplyImpl) TakeOwnership() bool { - return a.ApplyOptions.TakeOwnership -} - -func (a *ApplyImpl) SyncReleaseLabels() bool { - return a.ApplyOptions.SyncReleaseLabels -} diff --git a/pkg/config/apply_impl.go b/pkg/config/apply_impl.go new file mode 100644 index 00000000..defd6dfe --- /dev/null +++ b/pkg/config/apply_impl.go @@ -0,0 +1,204 @@ +package config + +// ApplyImpl is impl for applyOptions +type ApplyImpl struct { + *GlobalImpl + *ApplyOptions +} + +// NewApplyImpl creates a new ApplyImpl +func NewApplyImpl(g *GlobalImpl, a *ApplyOptions) *ApplyImpl { + return &ApplyImpl{ + GlobalImpl: g, + ApplyOptions: a, + } +} + +// Set returns the set. +func (t *ApplyImpl) Set() []string { + return t.ApplyOptions.Set +} + +// Concurrency returns the concurrency. +func (t *ApplyImpl) Concurrency() int { + return t.ApplyOptions.Concurrency +} + +// Context returns the context. +func (t *ApplyImpl) Context() int { + return t.ApplyOptions.Context +} + +// DetailedExitcode returns the detailed exitcode. +func (t *ApplyImpl) DetailedExitcode() bool { + return t.ApplyOptions.DetailedExitcode +} + +// StripTrailingCR is true if trailing carriage returns should be stripped during diffing +func (t *ApplyImpl) StripTrailingCR() bool { + return t.ApplyOptions.StripTrailingCR +} + +// DiffOutput returns the diff output. +func (t *ApplyImpl) DiffOutput() string { + return t.Output +} + +// IncludeNeeds returns the include needs. +func (t *ApplyImpl) IncludeNeeds() bool { + return t.ApplyOptions.IncludeNeeds || t.IncludeTransitiveNeeds() +} + +// IncludeTests returns the include tests. +func (t *ApplyImpl) IncludeTests() bool { + return t.ApplyOptions.IncludeTests +} + +// IncludeTransitiveNeeds returns the include transitive needs. +func (t *ApplyImpl) IncludeTransitiveNeeds() bool { + return t.ApplyOptions.IncludeTransitiveNeeds +} + +// ShowSecrets returns the show secrets. +func (t *ApplyImpl) ShowSecrets() bool { + return t.ApplyOptions.ShowSecrets +} + +// NoHooks skips hooks. +func (t *ApplyImpl) NoHooks() bool { + return t.ApplyOptions.NoHooks +} + +// SkipCRDs returns the skip CRDs. +func (t *ApplyImpl) SkipCRDs() bool { + return t.ApplyOptions.SkipCRDsFlag.Value() +} + +// IncludeCRDs returns the include CRDs. +func (t *ApplyImpl) IncludeCRDs() bool { + return t.ApplyOptions.IncludeCRDsFlag.Value() +} + +// ShouldIncludeCRDs determines if CRDs should be included in the operation. +func (t *ApplyImpl) ShouldIncludeCRDs() bool { + return ShouldIncludeCRDs(t.IncludeCRDsFlag, t.SkipCRDsFlag) +} + +// SkipCleanup returns the skip cleanup. +func (t *ApplyImpl) SkipCleanup() bool { + return t.ApplyOptions.SkipCleanup +} + +// SkipDiffOnInstall returns the skip diff on install. +func (t *ApplyImpl) SkipDiffOnInstall() bool { + return t.ApplyOptions.SkipDiffOnInstall +} + +// DiffArgs is the list of arguments to pass to helm-diff. +func (t *ApplyImpl) DiffArgs() string { + return t.ApplyOptions.DiffArgs +} + +// SkipNeeds returns the skip needs. +func (t *ApplyImpl) SkipNeeds() bool { + if !t.IncludeNeeds() { + return t.ApplyOptions.SkipNeeds + } + return false +} + +// Suppress returns the suppress. +func (t *ApplyImpl) Suppress() []string { + return t.ApplyOptions.Suppress +} + +// SuppressDiff returns the suppress diff. +func (t *ApplyImpl) SuppressDiff() bool { + return t.ApplyOptions.SuppressDiff +} + +// SuppressSecrets returns the suppress secrets. +func (t *ApplyImpl) SuppressSecrets() bool { + return t.ApplyOptions.SuppressSecrets +} + +// Validate returns the validate. +func (t *ApplyImpl) Validate() bool { + return t.ApplyOptions.Validate +} + +// Values returns the values. +func (t *ApplyImpl) Values() []string { + return t.ApplyOptions.Values +} + +// Wait returns the wait. +func (t *ApplyImpl) Wait() bool { + return t.ApplyOptions.Wait +} + +// WaitRetries returns the wait retries. +func (t *ApplyImpl) WaitRetries() int { + return t.ApplyOptions.WaitRetries +} + +// WaitForJobs returns the wait for jobs. +func (t *ApplyImpl) WaitForJobs() bool { + return t.ApplyOptions.WaitForJobs +} + +// ReuseValues returns the ReuseValues. +func (t *ApplyImpl) ReuseValues() bool { + if !t.ResetValues() { + return t.ApplyOptions.ReuseValues + } + return false +} + +func (t *ApplyImpl) ResetValues() bool { + return t.ApplyOptions.ResetValues +} + +// PostRenderer returns the PostRenderer. +func (t *ApplyImpl) PostRenderer() string { + return t.ApplyOptions.PostRenderer +} + +// PostRendererArgs returns the PostRendererArgs. +func (t *ApplyImpl) PostRendererArgs() []string { + return t.ApplyOptions.PostRendererArgs +} + +// SkipSchemaValidation returns the SkipSchemaValidation. +func (t *ApplyImpl) SkipSchemaValidation() bool { + return t.ApplyOptions.SkipSchemaValidation +} + +// Cascade returns cascade flag +func (t *ApplyImpl) Cascade() string { + return t.ApplyOptions.Cascade +} + +// SuppressOutputLineRegex returns the SuppressOutputLineRegex. +func (t *ApplyImpl) SuppressOutputLineRegex() []string { + return t.ApplyOptions.SuppressOutputLineRegex +} + +// SyncArgs returns the SyncArgs. +func (t *ApplyImpl) SyncArgs() string { + return t.ApplyOptions.SyncArgs +} + +// HideNotes returns the HideNotes. +func (t *ApplyImpl) HideNotes() bool { + return t.ApplyOptions.HideNotes +} + +// TakeOwnership returns the TakeOwnership. +func (t *ApplyImpl) TakeOwnership() bool { + return t.ApplyOptions.TakeOwnership +} + +func (t *ApplyImpl) SyncReleaseLabels() bool { + return t.ApplyOptions.SyncReleaseLabels +} diff --git a/pkg/config/apply_test.go b/pkg/config/apply_test.go new file mode 100644 index 00000000..3a4cf211 --- /dev/null +++ b/pkg/config/apply_test.go @@ -0,0 +1,57 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestApplyOptions_HandleFlag(t *testing.T) { + options := NewApplyOptions() + + // Test handling include-crds flag + includeCRDs := true + handled := options.HandleFlag("include-crds", &includeCRDs, true) + assert.True(t, handled, "include-crds flag should be handled") + assert.True(t, options.IncludeCRDsFlag.WasExplicitlySet()) + assert.True(t, options.IncludeCRDsFlag.Value()) + + // Test that flag is handled even when not changed + handled = options.HandleFlag("include-crds", &includeCRDs, false) + assert.True(t, handled, "include-crds flag should be handled even when not changed") + + // Test handling skip-crds flag + skipCRDs := true + handled = options.HandleFlag("skip-crds", &skipCRDs, true) + assert.True(t, options.SkipCRDsFlag.WasExplicitlySet()) + assert.True(t, handled, "skip-crds flag should be handled") + assert.True(t, options.SkipCRDsFlag.WasExplicitlySet()) + assert.True(t, options.SkipCRDsFlag.Value()) +} + +func TestApplyOptions_HandleFlag_UnknownFlag(t *testing.T) { + options := NewApplyOptions() + + // Test handling a non-existent flag + skipCRDs := true + handled := options.HandleFlag("non-existent-flag", &skipCRDs, true) + assert.False(t, handled, "non-existent flag should not be handled") +} + +func TestApplyOptions_HandleFlag_NotBool(t *testing.T) { + options := NewApplyOptions() + + // Test handling include-crds flag + includeCRDs := true + handled := options.HandleFlag("include-crds", &includeCRDs, true) + assert.True(t, handled, "include-crds flag should be handled") + assert.True(t, options.IncludeCRDsFlag.Value()) + + // Test with incorrect value type + stringValue := "not-a-bool" + handled = options.HandleFlag("include-crds", &stringValue, true) + assert.True(t, handled, "include-crds flag should be handled even with incorrect type") + + // Value should not change when type is incorrect + assert.True(t, options.IncludeCRDsFlag.Value()) +} diff --git a/pkg/config/build.go b/pkg/config/build.go index 26bb6bea..0d3551cf 100644 --- a/pkg/config/build.go +++ b/pkg/config/build.go @@ -10,22 +10,3 @@ type BuildOptions struct { func NewBuildOptions() *BuildOptions { return &BuildOptions{} } - -// BuildImpl is impl for applyOptions -type BuildImpl struct { - *GlobalImpl - *BuildOptions -} - -// NewBuildImpl creates a new BuildImpl -func NewBuildImpl(g *GlobalImpl, b *BuildOptions) *BuildImpl { - return &BuildImpl{ - GlobalImpl: g, - BuildOptions: b, - } -} - -// EmbedValues returns the embed values. -func (b *BuildImpl) EmbedValues() bool { - return b.BuildOptions.EmbedValues -} diff --git a/pkg/config/build_impl.go b/pkg/config/build_impl.go new file mode 100644 index 00000000..9809d1ae --- /dev/null +++ b/pkg/config/build_impl.go @@ -0,0 +1,20 @@ +package config + +// BuildImpl is impl for BuildOptions +type BuildImpl struct { + *GlobalImpl + *BuildOptions +} + +// NewBuildImpl creates a new BuildImpl +func NewBuildImpl(g *GlobalImpl, b *BuildOptions) *BuildImpl { + return &BuildImpl{ + GlobalImpl: g, + BuildOptions: b, + } +} + +// EmbedValues returns the embed values. +func (b *BuildImpl) EmbedValues() bool { + return b.BuildOptions.EmbedValues +} diff --git a/pkg/config/cache.go b/pkg/config/cache.go index b4e4010a..e4102eda 100644 --- a/pkg/config/cache.go +++ b/pkg/config/cache.go @@ -7,17 +7,3 @@ type CacheOptions struct{} func NewCacheOptions() *CacheOptions { return &CacheOptions{} } - -// CacheImpl is impl for applyOptions -type CacheImpl struct { - *GlobalImpl - *CacheOptions -} - -// NewCacheImpl creates a new CacheImpl -func NewCacheImpl(g *GlobalImpl, b *CacheOptions) *CacheImpl { - return &CacheImpl{ - GlobalImpl: g, - CacheOptions: b, - } -} diff --git a/pkg/config/cache_impl.go b/pkg/config/cache_impl.go new file mode 100644 index 00000000..f08482c4 --- /dev/null +++ b/pkg/config/cache_impl.go @@ -0,0 +1,15 @@ +package config + +// CacheImpl is impl for CacheOptions +type CacheImpl struct { + *GlobalImpl + *CacheOptions +} + +// NewCacheImpl creates a new CacheImpl +func NewCacheImpl(g *GlobalImpl, b *CacheOptions) *CacheImpl { + return &CacheImpl{ + GlobalImpl: g, + CacheOptions: b, + } +} diff --git a/pkg/config/deps.go b/pkg/config/deps.go index f4dd4608..729e19d0 100644 --- a/pkg/config/deps.go +++ b/pkg/config/deps.go @@ -12,32 +12,3 @@ type DepsOptions struct { func NewDepsOptions() *DepsOptions { return &DepsOptions{} } - -// DepsImpl is impl for applyOptions -type DepsImpl struct { - *GlobalImpl - *DepsOptions -} - -// NewDepsImpl creates a new DepsImpl -func NewDepsImpl(g *GlobalImpl, b *DepsOptions) *DepsImpl { - return &DepsImpl{ - GlobalImpl: g, - DepsOptions: b, - } -} - -// SkipRepos returns the skip deps -func (d *DepsImpl) SkipRepos() bool { - return d.DepsOptions.SkipRepos -} - -// IncludeTransitiveNeeds returns the includeTransitiveNeeds -func (d *DepsImpl) IncludeTransitiveNeeds() bool { - return false -} - -// Concurrency returns the concurrency -func (c *DepsImpl) Concurrency() int { - return c.DepsOptions.Concurrency -} diff --git a/pkg/config/deps_impl.go b/pkg/config/deps_impl.go new file mode 100644 index 00000000..b069454f --- /dev/null +++ b/pkg/config/deps_impl.go @@ -0,0 +1,30 @@ +package config + +// DepsImpl is impl for DepsOptions +type DepsImpl struct { + *GlobalImpl + *DepsOptions +} + +// NewDepsImpl creates a new DepsImpl +func NewDepsImpl(g *GlobalImpl, b *DepsOptions) *DepsImpl { + return &DepsImpl{ + GlobalImpl: g, + DepsOptions: b, + } +} + +// SkipRepos returns the skip deps +func (d *DepsImpl) SkipRepos() bool { + return d.DepsOptions.SkipRepos +} + +// IncludeTransitiveNeeds returns the includeTransitiveNeeds +func (d *DepsImpl) IncludeTransitiveNeeds() bool { + return false +} + +// Concurrency returns the concurrency +func (c *DepsImpl) Concurrency() int { + return c.DepsOptions.Concurrency +} diff --git a/pkg/config/destroy.go b/pkg/config/destroy.go index 4bcaccfb..1d3c97b7 100644 --- a/pkg/config/destroy.go +++ b/pkg/config/destroy.go @@ -18,42 +18,3 @@ type DestroyOptions struct { func NewDestroyOptions() *DestroyOptions { return &DestroyOptions{} } - -// DestroyImpl is impl for applyOptions -type DestroyImpl struct { - *GlobalImpl - *DestroyOptions -} - -// NewDestroyImpl creates a new DestroyImpl -func NewDestroyImpl(g *GlobalImpl, b *DestroyOptions) *DestroyImpl { - return &DestroyImpl{ - GlobalImpl: g, - DestroyOptions: b, - } -} - -// Concurrency returns the concurrency -func (c *DestroyImpl) Concurrency() int { - return c.DestroyOptions.Concurrency -} - -// SkipCharts returns skipCharts flag -func (c *DestroyImpl) SkipCharts() bool { - return c.DestroyOptions.SkipCharts -} - -// Cascade returns cascade flag -func (c *DestroyImpl) Cascade() string { - return c.DestroyOptions.Cascade -} - -// DeleteWait returns the wait flag -func (c *DestroyImpl) DeleteWait() bool { - return c.DestroyOptions.DeleteWait -} - -// DeleteTimeout returns the timeout flag -func (c *DestroyImpl) DeleteTimeout() int { - return c.DestroyOptions.DeleteTimeout -} diff --git a/pkg/config/destroy_impl.go b/pkg/config/destroy_impl.go new file mode 100644 index 00000000..12765cc5 --- /dev/null +++ b/pkg/config/destroy_impl.go @@ -0,0 +1,40 @@ +package config + +// DestroyImpl is impl for DestroyOptions +type DestroyImpl struct { + *GlobalImpl + *DestroyOptions +} + +// NewDestroyImpl creates a new DestroyImpl +func NewDestroyImpl(g *GlobalImpl, b *DestroyOptions) *DestroyImpl { + return &DestroyImpl{ + GlobalImpl: g, + DestroyOptions: b, + } +} + +// Concurrency returns the concurrency +func (c *DestroyImpl) Concurrency() int { + return c.DestroyOptions.Concurrency +} + +// SkipCharts returns skipCharts flag +func (c *DestroyImpl) SkipCharts() bool { + return c.DestroyOptions.SkipCharts +} + +// Cascade returns cascade flag +func (c *DestroyImpl) Cascade() string { + return c.DestroyOptions.Cascade +} + +// DeleteWait returns the wait flag +func (c *DestroyImpl) DeleteWait() bool { + return c.DestroyOptions.DeleteWait +} + +// DeleteTimeout returns the timeout flag +func (c *DestroyImpl) DeleteTimeout() int { + return c.DestroyOptions.DeleteTimeout +} diff --git a/pkg/config/diff.go b/pkg/config/diff.go index 5f5621c6..8f9bf472 100644 --- a/pkg/config/diff.go +++ b/pkg/config/diff.go @@ -1,6 +1,9 @@ package config -import "github.com/helmfile/helmfile/pkg/common" +import ( + "github.com/helmfile/helmfile/pkg/common" + "github.com/helmfile/helmfile/pkg/flags" +) // DiffOptions is the options for the build command type DiffOptions struct { @@ -59,172 +62,27 @@ type DiffOptions struct { // NewDiffOptions creates a new Apply func NewDiffOptions() *DiffOptions { - newOptions := &DiffOptions{ - IncludeCRDsFlag: common.NewBoolFlag(false), - SkipCRDsFlag: common.NewBoolFlag(false), - } + newOptions := &DiffOptions{} + newOptions.Initialize() return newOptions } -// DiffImpl is impl for applyOptions -type DiffImpl struct { - *GlobalImpl - *DiffOptions +func (o *DiffOptions) Initialize() { + flags.EnsureBoolFlag(&o.IncludeCRDsFlag, false) + flags.EnsureBoolFlag(&o.SkipCRDsFlag, false) // not exposed as cli flag but needed for ShouldIncludeCRDs() until skip-crds is removed } -// NewDiffImpl creates a new DiffImpl -func NewDiffImpl(g *GlobalImpl, t *DiffOptions) *DiffImpl { - return &DiffImpl{ - GlobalImpl: g, - DiffOptions: t, - } -} - -// Concurrency returns the concurrency -func (t *DiffImpl) Concurrency() int { - return t.DiffOptions.Concurrency -} - -// IncludeNeeds returns the include needs -func (t *DiffImpl) IncludeNeeds() bool { - return t.DiffOptions.IncludeNeeds || t.IncludeTransitiveNeeds() -} - -// IncludeTransitiveNeeds returns the include transitive needs -func (t *DiffImpl) IncludeTransitiveNeeds() bool { - return t.DiffOptions.IncludeTransitiveNeeds -} - -// Set returns the Set -func (t *DiffImpl) Set() []string { - return t.DiffOptions.Set -} - -// SkipNeeds returns the skip needs -func (t *DiffImpl) SkipNeeds() bool { - if !t.IncludeNeeds() { - return t.DiffOptions.SkipNeeds +func (o *DiffOptions) HandleFlag(name string, value interface{}, changed bool) bool { + switch name { + case "include-crds": + if changed { + if boolVal, ok := value.(*bool); ok { + o.IncludeCRDsFlag.Set(*boolVal) + } + } + return true } return false } - -// Validate returns the validate -func (t *DiffImpl) Validate() bool { - return t.DiffOptions.Validate -} - -// Values returns the values -func (t *DiffImpl) Values() []string { - return t.DiffOptions.Values -} - -// Context returns the context -func (t *DiffImpl) Context() int { - return t.DiffOptions.Context -} - -// DetailedExitCode returns the detailed exit code -func (t *DiffImpl) DetailedExitcode() bool { - return t.DiffOptions.DetailedExitcode -} - -// StripTrailingCR is true if trailing carriage returns should be stripped during diffing -func (a *DiffImpl) StripTrailingCR() bool { - return a.DiffOptions.StripTrailingCR -} - -// Output returns the output -func (t *DiffImpl) DiffOutput() string { - return t.Output -} - -// IncludeTests returns the include tests -func (t *DiffImpl) IncludeTests() bool { - return t.DiffOptions.IncludeTests -} - -// ShowSecrets returns the show secrets -func (t *DiffImpl) ShowSecrets() bool { - return t.DiffOptions.ShowSecrets -} - -// NoHooks skips hooks. -func (t *DiffImpl) NoHooks() bool { - return t.DiffOptions.NoHooks -} - -// SkipCRDs returns the skip crds -func (t *DiffImpl) SkipCRDs() bool { - return t.DiffOptions.SkipCRDsFlag.Value() -} - -// IncludeCRDs returns the include crds -func (t *DiffImpl) IncludeCRDs() bool { - return t.DiffOptions.IncludeCRDsFlag.Value() -} - -// ShouldIncludeCRDs returns true if CRDs should be included -func (t *DiffImpl) ShouldIncludeCRDs() bool { - includeCRDsExplicit := t.IncludeCRDsFlag.WasExplicitlySet() && t.IncludeCRDsFlag.Value() - skipCRDsExplicit := t.SkipCRDsFlag.WasExplicitlySet() && !t.SkipCRDsFlag.Value() - - return includeCRDsExplicit || skipCRDsExplicit -} - -// SkipDiffOnInstall returns the skip diff on install -func (t *DiffImpl) SkipDiffOnInstall() bool { - return t.DiffOptions.SkipDiffOnInstall -} - -// DiffArgs returns the list of arguments to pass to helm-diff. -func (t *DiffImpl) DiffArgs() string { - return t.DiffOptions.DiffArgs -} - -// Suppress returns the suppress -func (t *DiffImpl) Suppress() []string { - return t.DiffOptions.Suppress -} - -// SuppressDiff returns the suppress diff -func (t *DiffImpl) SuppressDiff() bool { - return false -} - -// SuppressSecrets returns the suppress secrets -func (t *DiffImpl) SuppressSecrets() bool { - return t.DiffOptions.SuppressSecrets -} - -// ReuseValues returns the ReuseValues. -func (t *DiffImpl) ReuseValues() bool { - if !t.ResetValues() { - return t.DiffOptions.ReuseValues - } - return false -} - -func (t *DiffImpl) ResetValues() bool { - return t.DiffOptions.ResetValues -} - -// PostRenderer returns the PostRenderer. -func (t *DiffImpl) PostRenderer() string { - return t.DiffOptions.PostRenderer -} - -// PostRendererArgs returns the PostRendererArgs. -func (t *DiffImpl) PostRendererArgs() []string { - return t.DiffOptions.PostRendererArgs -} - -// SuppressOutputLineRegex returns the SuppressOutputLineRegex. -func (t *DiffImpl) SuppressOutputLineRegex() []string { - return t.DiffOptions.SuppressOutputLineRegex -} - -func (t *DiffImpl) SkipSchemaValidation() bool { - return t.DiffOptions.SkipSchemaValidation -} diff --git a/pkg/config/diff_impl.go b/pkg/config/diff_impl.go new file mode 100644 index 00000000..519b6a63 --- /dev/null +++ b/pkg/config/diff_impl.go @@ -0,0 +1,160 @@ +package config + +// DiffImpl is impl for DiffOptions +type DiffImpl struct { + *GlobalImpl + *DiffOptions +} + +// NewDiffImpl creates a new DiffImpl +func NewDiffImpl(g *GlobalImpl, t *DiffOptions) *DiffImpl { + return &DiffImpl{ + GlobalImpl: g, + DiffOptions: t, + } +} + +// Concurrency returns the concurrency +func (t *DiffImpl) Concurrency() int { + return t.DiffOptions.Concurrency +} + +// IncludeNeeds returns the include needs +func (t *DiffImpl) IncludeNeeds() bool { + return t.DiffOptions.IncludeNeeds || t.IncludeTransitiveNeeds() +} + +// IncludeTransitiveNeeds returns the include transitive needs +func (t *DiffImpl) IncludeTransitiveNeeds() bool { + return t.DiffOptions.IncludeTransitiveNeeds +} + +// Set returns the Set +func (t *DiffImpl) Set() []string { + return t.DiffOptions.Set +} + +// SkipNeeds returns the skip needs +func (t *DiffImpl) SkipNeeds() bool { + if !t.IncludeNeeds() { + return t.DiffOptions.SkipNeeds + } + + return false +} + +// Validate returns the validate +func (t *DiffImpl) Validate() bool { + return t.DiffOptions.Validate +} + +// Values returns the values +func (t *DiffImpl) Values() []string { + return t.DiffOptions.Values +} + +// Context returns the context +func (t *DiffImpl) Context() int { + return t.DiffOptions.Context +} + +// DetailedExitCode returns the detailed exit code +func (t *DiffImpl) DetailedExitcode() bool { + return t.DiffOptions.DetailedExitcode +} + +// StripTrailingCR is true if trailing carriage returns should be stripped during diffing +func (a *DiffImpl) StripTrailingCR() bool { + return a.DiffOptions.StripTrailingCR +} + +// Output returns the output +func (t *DiffImpl) DiffOutput() string { + return t.Output +} + +// IncludeTests returns the include tests +func (t *DiffImpl) IncludeTests() bool { + return t.DiffOptions.IncludeTests +} + +// ShowSecrets returns the show secrets +func (t *DiffImpl) ShowSecrets() bool { + return t.DiffOptions.ShowSecrets +} + +// NoHooks skips hooks. +func (t *DiffImpl) NoHooks() bool { + return t.DiffOptions.NoHooks +} + +// SkipCRDs returns the skip crds +func (t *DiffImpl) SkipCRDs() bool { + return t.DiffOptions.SkipCRDsFlag.Value() +} + +// IncludeCRDs returns the include crds +func (t *DiffImpl) IncludeCRDs() bool { + return t.DiffOptions.IncludeCRDsFlag.Value() +} + +// ShouldIncludeCRDs determines if CRDs should be included in the operation. +func (t *DiffImpl) ShouldIncludeCRDs() bool { + return ShouldIncludeCRDs(t.IncludeCRDsFlag, t.SkipCRDsFlag) +} + +// SkipDiffOnInstall returns the skip diff on install +func (t *DiffImpl) SkipDiffOnInstall() bool { + return t.DiffOptions.SkipDiffOnInstall +} + +// DiffArgs returns the list of arguments to pass to helm-diff. +func (t *DiffImpl) DiffArgs() string { + return t.DiffOptions.DiffArgs +} + +// Suppress returns the suppress +func (t *DiffImpl) Suppress() []string { + return t.DiffOptions.Suppress +} + +// SuppressDiff returns the suppress diff +func (t *DiffImpl) SuppressDiff() bool { + return false +} + +// SuppressSecrets returns the suppress secrets +func (t *DiffImpl) SuppressSecrets() bool { + return t.DiffOptions.SuppressSecrets +} + +// ReuseValues returns the ReuseValues. +func (t *DiffImpl) ReuseValues() bool { + if !t.ResetValues() { + return t.DiffOptions.ReuseValues + } + return false +} + +func (t *DiffImpl) ResetValues() bool { + return t.DiffOptions.ResetValues +} + +// PostRenderer returns the PostRenderer. +func (t *DiffImpl) PostRenderer() string { + return t.DiffOptions.PostRenderer +} + +// PostRendererArgs returns the PostRendererArgs. +func (t *DiffImpl) PostRendererArgs() []string { + return t.DiffOptions.PostRendererArgs +} + +// SuppressOutputLineRegex returns the SuppressOutputLineRegex. +func (t *DiffImpl) SuppressOutputLineRegex() []string { + return t.DiffOptions.SuppressOutputLineRegex +} + +func (t *DiffImpl) SkipSchemaValidation() bool { + return t.DiffOptions.SkipSchemaValidation +} diff --git a/pkg/config/diff_test.go b/pkg/config/diff_test.go new file mode 100644 index 00000000..d44cdd33 --- /dev/null +++ b/pkg/config/diff_test.go @@ -0,0 +1,17 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDiffOptions_HandleFlag(t *testing.T) { + options := NewDiffOptions() + + // Test handling include-crds flag + includeCRDs := true + handled := options.HandleFlag("include-crds", &includeCRDs, true) + assert.True(t, handled, "include-crds flag should be handled") + assert.True(t, options.IncludeCRDsFlag.Value()) +} diff --git a/pkg/config/fetch.go b/pkg/config/fetch.go index 462ecdf4..501d0f7d 100644 --- a/pkg/config/fetch.go +++ b/pkg/config/fetch.go @@ -14,32 +14,3 @@ type FetchOptions struct { func NewFetchOptions() *FetchOptions { return &FetchOptions{} } - -// FetchImpl is impl for applyOptions -type FetchImpl struct { - *GlobalImpl - *FetchOptions -} - -// NewFetchImpl creates a new FetchImpl -func NewFetchImpl(g *GlobalImpl, b *FetchOptions) *FetchImpl { - return &FetchImpl{ - GlobalImpl: g, - FetchOptions: b, - } -} - -// Concurrency returns the concurrency -func (c *FetchImpl) Concurrency() int { - return c.FetchOptions.Concurrency -} - -// OutputDir returns the args -func (c *FetchImpl) OutputDir() string { - return c.FetchOptions.OutputDir -} - -// OutputDirTemplate returns the go template to generate the path of output directory -func (c *FetchImpl) OutputDirTemplate() string { - return c.FetchOptions.OutputDirTemplate -} diff --git a/pkg/config/fetch_impl.go b/pkg/config/fetch_impl.go new file mode 100644 index 00000000..32fe454c --- /dev/null +++ b/pkg/config/fetch_impl.go @@ -0,0 +1,30 @@ +package config + +// FetchImpl is impl for FechtOptions +type FetchImpl struct { + *GlobalImpl + *FetchOptions +} + +// NewFetchImpl creates a new FetchImpl +func NewFetchImpl(g *GlobalImpl, b *FetchOptions) *FetchImpl { + return &FetchImpl{ + GlobalImpl: g, + FetchOptions: b, + } +} + +// Concurrency returns the concurrency +func (c *FetchImpl) Concurrency() int { + return c.FetchOptions.Concurrency +} + +// OutputDir returns the args +func (c *FetchImpl) OutputDir() string { + return c.FetchOptions.OutputDir +} + +// OutputDirTemplate returns the go template to generate the path of output directory +func (c *FetchImpl) OutputDirTemplate() string { + return c.FetchOptions.OutputDirTemplate +} diff --git a/pkg/config/flag_utils.go b/pkg/config/flag_utils.go new file mode 100644 index 00000000..be4af0e7 --- /dev/null +++ b/pkg/config/flag_utils.go @@ -0,0 +1,17 @@ +package config + +import "github.com/helmfile/helmfile/pkg/common" + +// ShouldIncludeCRDs determines if CRDs should be included in the operation. +// It returns true only when: +// - includeCRDs flag is explicitly provided on the command line and set to true +// - AND skipCRDs flag is not provided on the command line +// +// This ensures that CRDs are only included when explicitly requested and not +// contradicted by the skipCRDs flag. +func ShouldIncludeCRDs(includeCRDsFlag, skipCRDsFlag common.BoolFlag) bool { + includeCRDsExplicit := includeCRDsFlag.WasExplicitlySet() && includeCRDsFlag.Value() + skipCRDsProvided := skipCRDsFlag.WasExplicitlySet() + + return includeCRDsExplicit && !skipCRDsProvided +} diff --git a/pkg/config/global.go b/pkg/config/global.go index fe906195..504e18d2 100644 --- a/pkg/config/global.go +++ b/pkg/config/global.go @@ -1,17 +1,9 @@ package config import ( - "errors" - "fmt" "io" - "os" "go.uber.org/zap" - "golang.org/x/term" - - "github.com/helmfile/helmfile/pkg/envvar" - "github.com/helmfile/helmfile/pkg/maputil" - "github.com/helmfile/helmfile/pkg/state" ) // GlobalOptions is the global configuration for the Helmfile CLI. @@ -87,179 +79,3 @@ type GlobalImpl struct { *GlobalOptions set map[string]any } - -// NewGlobalImpl creates a new GlobalImpl. -func NewGlobalImpl(opts *GlobalOptions) *GlobalImpl { - return &GlobalImpl{ - GlobalOptions: opts, - set: make(map[string]any), - } -} - -// Setset sets the set -func (g *GlobalImpl) SetSet(set map[string]any) { - g.set = maputil.MergeMaps(g.set, set) -} - -// HelmBinary returns the path to the Helm binary. -func (g *GlobalImpl) HelmBinary() string { - return g.GlobalOptions.HelmBinary -} - -// KustomizeBinary returns the path to the Kustomize binary. -func (g *GlobalImpl) KustomizeBinary() string { - return g.GlobalOptions.KustomizeBinary -} - -// Kubeconfig returns the path to the kubeconfig file to use. -func (g *GlobalImpl) Kubeconfig() string { - return g.GlobalOptions.Kubeconfig -} - -// KubeContext returns the name of the kubectl context to use. -func (g *GlobalImpl) KubeContext() string { - return g.GlobalOptions.KubeContext -} - -// Namespace returns the namespace to use. -func (g *GlobalImpl) Namespace() string { - return g.GlobalOptions.Namespace -} - -// Chart returns the chart to use. -func (g *GlobalImpl) Chart() string { - return g.GlobalOptions.Chart -} - -// FileOrDir returns the path to the Helmfile. -func (g *GlobalImpl) FileOrDir() string { - file := g.File - if file == "" { - file = os.Getenv(envvar.FilePath) - } - - return file -} - -// Selectors returns the selectors to use. -func (g *GlobalImpl) Selectors() []string { - return g.Selector -} - -// StateValuesSet returns the set -func (g *GlobalImpl) StateValuesSet() map[string]any { - return g.set -} - -// StateValuesSet returns the set -func (g *GlobalImpl) RawStateValuesSet() []string { - return g.GlobalOptions.StateValuesSet -} - -// RawStateValuesSetString returns the set -func (g *GlobalImpl) RawStateValuesSetString() []string { - return g.StateValuesSetString -} - -// StateValuesFiles returns the state values files -func (g *GlobalImpl) StateValuesFiles() []string { - return g.StateValuesFile -} - -// EnableLiveOutput return when to pipe the stdout and stderr from Helm live to the helmfile stdout -func (g *GlobalImpl) EnableLiveOutput() bool { - return g.GlobalOptions.EnableLiveOutput -} - -// SkipDeps return if running "helm repo update" and "helm dependency build" should be skipped -func (g *GlobalImpl) SkipDeps() bool { - return g.GlobalOptions.SkipDeps -} - -// SkipRefresh return if running "helm repo update" -func (g *GlobalImpl) SkipRefresh() bool { - return g.GlobalOptions.SkipRefresh -} - -// StripArgsValuesOnExitError return if the ARGS output on exit error should be suppressed -func (g *GlobalImpl) StripArgsValuesOnExitError() bool { - return g.GlobalOptions.StripArgsValuesOnExitError -} - -// DisableForceUpdate return when to disable forcing updates to repos upon adding -func (g *GlobalImpl) DisableForceUpdate() bool { - return g.GlobalOptions.DisableForceUpdate -} - -// Logger returns the logger -func (g *GlobalImpl) Logger() *zap.SugaredLogger { - return g.logger -} - -func (g *GlobalImpl) Color() bool { - if c := g.GlobalOptions.Color; c { - return c - } - - if g.GlobalOptions.NoColor { - return false - } - - // We replicate the helm-diff behavior in helmfile - // because when helmfile calls helm-diff, helm-diff has no access to term and therefore - // we can't rely on helm-diff's ability to auto-detect term for color output. - // See https://github.com/roboll/helmfile/issues/2043 - - terminal := term.IsTerminal(int(os.Stdout.Fd())) - // https://github.com/databus23/helm-diff/issues/281 - dumb := os.Getenv("TERM") == "dumb" - return terminal && !dumb -} - -// NoColor returns the no color flag -func (g *GlobalImpl) NoColor() bool { - return g.GlobalOptions.NoColor -} - -// Env returns the environment to use. -func (g *GlobalImpl) Env() string { - var env string - - switch { - case g.Environment != "": - env = g.Environment - case os.Getenv("HELMFILE_ENVIRONMENT") != "": - env = os.Getenv("HELMFILE_ENVIRONMENT") - default: - env = state.DefaultEnv - } - return env -} - -// ValidateConfig validates the global options. -func (g *GlobalImpl) ValidateConfig() error { - if g.NoColor() && g.Color() { - return errors.New("--color and --no-color cannot be specified at the same time") - } - return nil -} - -// Interactive returns the Interactive -func (g *GlobalImpl) Interactive() bool { - if g.GlobalOptions.Interactive { - return true - } - return os.Getenv(envvar.Interactive) == "true" -} - -// Args returns the args to use for helm -func (g *GlobalImpl) Args() string { - args := g.GlobalOptions.Args - enableHelmDebug := g.Debug - - if enableHelmDebug { - args = fmt.Sprintf("%s %s", args, "--debug") - } - - return args -} diff --git a/pkg/config/global_impl.go b/pkg/config/global_impl.go new file mode 100644 index 00000000..6bb25e95 --- /dev/null +++ b/pkg/config/global_impl.go @@ -0,0 +1,190 @@ +package config + +import ( + "errors" + "fmt" + "os" + + "go.uber.org/zap" + "golang.org/x/term" + + "github.com/helmfile/helmfile/pkg/envvar" + "github.com/helmfile/helmfile/pkg/maputil" + "github.com/helmfile/helmfile/pkg/state" +) + +// NewGlobalImpl creates a new GlobalImpl. +func NewGlobalImpl(opts *GlobalOptions) *GlobalImpl { + return &GlobalImpl{ + GlobalOptions: opts, + set: make(map[string]any), + } +} + +// Setset sets the set +func (g *GlobalImpl) SetSet(set map[string]any) { + g.set = maputil.MergeMaps(g.set, set) +} + +// HelmBinary returns the path to the Helm binary. +func (g *GlobalImpl) HelmBinary() string { + return g.GlobalOptions.HelmBinary +} + +// KustomizeBinary returns the path to the Kustomize binary. +func (g *GlobalImpl) KustomizeBinary() string { + return g.GlobalOptions.KustomizeBinary +} + +// Kubeconfig returns the path to the kubeconfig file to use. +func (g *GlobalImpl) Kubeconfig() string { + return g.GlobalOptions.Kubeconfig +} + +// KubeContext returns the name of the kubectl context to use. +func (g *GlobalImpl) KubeContext() string { + return g.GlobalOptions.KubeContext +} + +// Namespace returns the namespace to use. +func (g *GlobalImpl) Namespace() string { + return g.GlobalOptions.Namespace +} + +// Chart returns the chart to use. +func (g *GlobalImpl) Chart() string { + return g.GlobalOptions.Chart +} + +// FileOrDir returns the path to the Helmfile. +func (g *GlobalImpl) FileOrDir() string { + file := g.File + if file == "" { + file = os.Getenv(envvar.FilePath) + } + + return file +} + +// Selectors returns the selectors to use. +func (g *GlobalImpl) Selectors() []string { + return g.Selector +} + +// StateValuesSet returns the set +func (g *GlobalImpl) StateValuesSet() map[string]any { + return g.set +} + +// StateValuesSet returns the set +func (g *GlobalImpl) RawStateValuesSet() []string { + return g.GlobalOptions.StateValuesSet +} + +// RawStateValuesSetString returns the set +func (g *GlobalImpl) RawStateValuesSetString() []string { + return g.StateValuesSetString +} + +// StateValuesFiles returns the state values files +func (g *GlobalImpl) StateValuesFiles() []string { + return g.StateValuesFile +} + +// EnableLiveOutput return when to pipe the stdout and stderr from Helm live to the helmfile stdout +func (g *GlobalImpl) EnableLiveOutput() bool { + return g.GlobalOptions.EnableLiveOutput +} + +// SkipDeps return if running "helm repo update" and "helm dependency build" should be skipped +func (g *GlobalImpl) SkipDeps() bool { + return g.GlobalOptions.SkipDeps +} + +// SkipRefresh return if running "helm repo update" +func (g *GlobalImpl) SkipRefresh() bool { + return g.GlobalOptions.SkipRefresh +} + +// StripArgsValuesOnExitError return if the ARGS output on exit error should be suppressed +func (g *GlobalImpl) StripArgsValuesOnExitError() bool { + return g.GlobalOptions.StripArgsValuesOnExitError +} + +// DisableForceUpdate return when to disable forcing updates to repos upon adding +func (g *GlobalImpl) DisableForceUpdate() bool { + return g.GlobalOptions.DisableForceUpdate +} + +// Logger returns the logger +func (g *GlobalImpl) Logger() *zap.SugaredLogger { + return g.logger +} + +func (g *GlobalImpl) Color() bool { + if c := g.GlobalOptions.Color; c { + return c + } + + if g.GlobalOptions.NoColor { + return false + } + + // We replicate the helm-diff behavior in helmfile + // because when helmfile calls helm-diff, helm-diff has no access to term and therefore + // we can't rely on helm-diff's ability to auto-detect term for color output. + // See https://github.com/roboll/helmfile/issues/2043 + + terminal := term.IsTerminal(int(os.Stdout.Fd())) + // https://github.com/databus23/helm-diff/issues/281 + dumb := os.Getenv("TERM") == "dumb" + return terminal && !dumb +} + +// NoColor returns the no color flag +func (g *GlobalImpl) NoColor() bool { + return g.GlobalOptions.NoColor +} + +// Env returns the environment to use. +func (g *GlobalImpl) Env() string { + var env string + + switch { + case g.Environment != "": + env = g.Environment + case os.Getenv("HELMFILE_ENVIRONMENT") != "": + env = os.Getenv("HELMFILE_ENVIRONMENT") + default: + env = state.DefaultEnv + } + return env +} + +// ValidateConfig validates the global options. +func (g *GlobalImpl) ValidateConfig() error { + if g.NoColor() && g.Color() { + return errors.New("--color and --no-color cannot be specified at the same time") + } + return nil +} + +// Interactive returns the Interactive +func (g *GlobalImpl) Interactive() bool { + if g.GlobalOptions.Interactive { + return true + } + return os.Getenv(envvar.Interactive) == "true" +} + +// Args returns the args to use for helm +func (g *GlobalImpl) Args() string { + args := g.GlobalOptions.Args + enableHelmDebug := g.Debug + + if enableHelmDebug { + args = fmt.Sprintf("%s %s", args, "--debug") + } + + return args +} diff --git a/pkg/config/init.go b/pkg/config/init.go index f5dde152..a164971a 100644 --- a/pkg/config/init.go +++ b/pkg/config/init.go @@ -9,22 +9,3 @@ type InitOptions struct { func NewInitOptions() *InitOptions { return &InitOptions{} } - -// InitImpl is impl for InitOptions -type InitImpl struct { - *GlobalImpl - *InitOptions -} - -// NewInitImpl creates a new InitImpl -func NewInitImpl(g *GlobalImpl, b *InitOptions) *InitImpl { - return &InitImpl{ - GlobalImpl: g, - InitOptions: b, - } -} - -// Force returns the Force. -func (b *InitImpl) Force() bool { - return b.InitOptions.Force -} diff --git a/pkg/config/init_impl.go b/pkg/config/init_impl.go new file mode 100644 index 00000000..8b0beebf --- /dev/null +++ b/pkg/config/init_impl.go @@ -0,0 +1,20 @@ +package config + +// InitImpl is impl for InitOptions +type InitImpl struct { + *GlobalImpl + *InitOptions +} + +// NewInitImpl creates a new InitImpl +func NewInitImpl(g *GlobalImpl, b *InitOptions) *InitImpl { + return &InitImpl{ + GlobalImpl: g, + InitOptions: b, + } +} + +// Force returns the Force. +func (b *InitImpl) Force() bool { + return b.InitOptions.Force +} diff --git a/pkg/config/linit_impl.go b/pkg/config/linit_impl.go new file mode 100644 index 00000000..43ad56f3 --- /dev/null +++ b/pkg/config/linit_impl.go @@ -0,0 +1,54 @@ +package config + +// LintImpl is impl for LintOptions +type LintImpl struct { + *GlobalImpl + *LintOptions +} + +// NewLintImpl creates a new LintImpl +func NewLintImpl(g *GlobalImpl, b *LintOptions) *LintImpl { + return &LintImpl{ + GlobalImpl: g, + LintOptions: b, + } +} + +// Concurrency returns the concurrency +func (l *LintImpl) Concurrency() int { + return l.LintOptions.Concurrency +} + +// Set returns the Set +func (l *LintImpl) Set() []string { + return l.LintOptions.Set +} + +// Values returns the Values +func (l *LintImpl) Values() []string { + return l.LintOptions.Values +} + +// SkipCleanUp returns the skip clean up +func (l *LintImpl) SkipCleanup() bool { + return false +} + +// IncludeNeeds returns the include needs +func (l *LintImpl) IncludeNeeds() bool { + return l.LintOptions.IncludeNeeds || l.IncludeTransitiveNeeds() +} + +// IncludeTransitiveNeeds returns the include transitive needs +func (l *LintImpl) IncludeTransitiveNeeds() bool { + return l.LintOptions.IncludeTransitiveNeeds +} + +// SkipNeeds returns the skip needs +func (l *LintImpl) SkipNeeds() bool { + if !l.IncludeNeeds() { + return l.LintOptions.SkipNeeds + } + + return false +} diff --git a/pkg/config/lint.go b/pkg/config/lint.go index 46cf02f8..b1c4b555 100644 --- a/pkg/config/lint.go +++ b/pkg/config/lint.go @@ -21,56 +21,3 @@ type LintOptions struct { func NewLintOptions() *LintOptions { return &LintOptions{} } - -// LintImpl is impl for applyOptions -type LintImpl struct { - *GlobalImpl - *LintOptions -} - -// NewLintImpl creates a new LintImpl -func NewLintImpl(g *GlobalImpl, b *LintOptions) *LintImpl { - return &LintImpl{ - GlobalImpl: g, - LintOptions: b, - } -} - -// Concurrency returns the concurrency -func (l *LintImpl) Concurrency() int { - return l.LintOptions.Concurrency -} - -// Set returns the Set -func (l *LintImpl) Set() []string { - return l.LintOptions.Set -} - -// Values returns the Values -func (l *LintImpl) Values() []string { - return l.LintOptions.Values -} - -// SkipCleanUp returns the skip clean up -func (l *LintImpl) SkipCleanup() bool { - return false -} - -// IncludeNeeds returns the include needs -func (l *LintImpl) IncludeNeeds() bool { - return l.LintOptions.IncludeNeeds || l.IncludeTransitiveNeeds() -} - -// IncludeTransitiveNeeds returns the include transitive needs -func (l *LintImpl) IncludeTransitiveNeeds() bool { - return l.LintOptions.IncludeTransitiveNeeds -} - -// SkipNeeds returns the skip needs -func (l *LintImpl) SkipNeeds() bool { - if !l.IncludeNeeds() { - return l.LintOptions.SkipNeeds - } - - return false -} diff --git a/pkg/config/list.go b/pkg/config/list.go index 0410a5ac..7834e593 100644 --- a/pkg/config/list.go +++ b/pkg/config/list.go @@ -14,27 +14,3 @@ type ListOptions struct { func NewListOptions() *ListOptions { return &ListOptions{} } - -// ListImpl is impl for applyOptions -type ListImpl struct { - *GlobalImpl - *ListOptions -} - -// NewListImpl creates a new ListImpl -func NewListImpl(g *GlobalImpl, b *ListOptions) *ListImpl { - return &ListImpl{ - GlobalImpl: g, - ListOptions: b, - } -} - -// Output returns the output -func (c *ListImpl) Output() string { - return c.ListOptions.Output -} - -// SkipCharts returns skipCharts flag -func (c *ListImpl) SkipCharts() bool { - return c.ListOptions.SkipCharts -} diff --git a/pkg/config/list_impl.go b/pkg/config/list_impl.go new file mode 100644 index 00000000..ef14b8ba --- /dev/null +++ b/pkg/config/list_impl.go @@ -0,0 +1,25 @@ +package config + +// ListImpl is impl for applyOptions +type ListImpl struct { + *GlobalImpl + *ListOptions +} + +// NewListImpl creates a new ListImpl +func NewListImpl(g *GlobalImpl, b *ListOptions) *ListImpl { + return &ListImpl{ + GlobalImpl: g, + ListOptions: b, + } +} + +// Output returns the output +func (c *ListImpl) Output() string { + return c.ListOptions.Output +} + +// SkipCharts returns skipCharts flag +func (c *ListImpl) SkipCharts() bool { + return c.ListOptions.SkipCharts +} diff --git a/pkg/config/options.go b/pkg/config/options.go index f22d7dfe..cd97ee15 100644 --- a/pkg/config/options.go +++ b/pkg/config/options.go @@ -1,65 +1,13 @@ package config -func (o *ApplyOptions) HandleFlag(name string, value interface{}, changed bool) { - if !changed { - return - } - - switch name { - case "include-crds": - if boolVal, ok := value.(*bool); ok { - o.IncludeCRDsFlag.Set(*boolVal) - } - case "skip-crds": - if boolVal, ok := value.(*bool); ok { - o.SkipCRDsFlag.Set(*boolVal) - } - // Handle other flags... - } +// Options is the base interface for all command options +type Options interface { + // Initialize sets default values for options + Initialize() } -func (o *DiffOptions) HandleFlag(name string, value interface{}, changed bool) { - if !changed { - return - } - - switch name { - case "include-crds": - if boolVal, ok := value.(*bool); ok { - o.IncludeCRDsFlag.Set(*boolVal) - } - // Handle other flags... - } -} - -func (o *SyncOptions) HandleFlag(name string, value interface{}, changed bool) { - if !changed { - return - } - - switch name { - case "include-crds": - if boolVal, ok := value.(*bool); ok { - o.IncludeCRDsFlag.Set(*boolVal) - } - case "skip-crds": - if boolVal, ok := value.(*bool); ok { - o.SkipCRDsFlag.Set(*boolVal) - } - // Handle other flags... - } -} - -func (o *TemplateOptions) HandleFlag(name string, value interface{}, changed bool) { - if !changed { - return - } - - switch name { - case "include-crds": - if boolVal, ok := value.(*bool); ok { - o.IncludeCRDsFlag.Set(*boolVal) - } - // Handle other flags... - } +// FlagHandler handles flag values from command line +type FlagHandler interface { + // HandleFlag processes a flag value + HandleFlag(name string, value interface{}, changed bool) } diff --git a/pkg/config/options_test.go b/pkg/config/options_test.go new file mode 100644 index 00000000..35fd8eaf --- /dev/null +++ b/pkg/config/options_test.go @@ -0,0 +1,61 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDiffOptions_Initialize(t *testing.T) { + options := &DiffOptions{} + options.Initialize() + + // Verify initialization + assert.False(t, options.DetailedExitcode) + assert.False(t, options.StripTrailingCR) + assert.False(t, options.IncludeTests) + assert.False(t, options.SuppressSecrets) + assert.False(t, options.ShowSecrets) + assert.False(t, options.NoHooks) + assert.False(t, options.IncludeCRDsFlag.Value()) + assert.False(t, options.SkipCRDsFlag.Value()) +} + +func TestApplyOptions_Initialize(t *testing.T) { + options := &ApplyOptions{} + options.Initialize() + + // Verify initialization + assert.False(t, options.DetailedExitcode) + assert.False(t, options.StripTrailingCR) + assert.False(t, options.IncludeTests) + assert.False(t, options.SuppressSecrets) + assert.False(t, options.ShowSecrets) + assert.False(t, options.NoHooks) + assert.False(t, options.SkipNeeds) + assert.False(t, options.IncludeCRDsFlag.Value()) + assert.False(t, options.SkipCRDsFlag.Value()) +} + +func TestSyncOptions_Initialize(t *testing.T) { + options := &SyncOptions{} + options.Initialize() + + // Verify initialization + assert.False(t, options.Validate) + assert.False(t, options.SkipNeeds) + assert.False(t, options.IncludeCRDsFlag.Value()) + assert.False(t, options.SkipCRDsFlag.Value()) +} + +func TestTemplateOptions_Initialize(t *testing.T) { + options := &TemplateOptions{} + options.Initialize() + + // Verify initialization + assert.False(t, options.SkipNeeds) + assert.False(t, options.SkipTests) + assert.False(t, options.NoHooks) + assert.False(t, options.IncludeCRDsFlag.Value()) + assert.False(t, options.SkipCRDsFlag.Value()) +} diff --git a/pkg/config/repos.go b/pkg/config/repos.go index 090b8cdf..5ed7f414 100644 --- a/pkg/config/repos.go +++ b/pkg/config/repos.go @@ -7,22 +7,3 @@ type ReposOptions struct{} func NewReposOptions() *ReposOptions { return &ReposOptions{} } - -// ReposImpl is impl for applyOptions -type ReposImpl struct { - *GlobalImpl - *ReposOptions -} - -// NewReposImpl creates a new ReposImpl -func NewReposImpl(g *GlobalImpl, b *ReposOptions) *ReposImpl { - return &ReposImpl{ - GlobalImpl: g, - ReposOptions: b, - } -} - -// IncludeTransitiveNeeds returns the include transitive needs -func (r *ReposImpl) IncludeTransitiveNeeds() bool { - return false -} diff --git a/pkg/config/repos_impl.go b/pkg/config/repos_impl.go new file mode 100644 index 00000000..986d15ac --- /dev/null +++ b/pkg/config/repos_impl.go @@ -0,0 +1,20 @@ +package config + +// ReposImpl is impl for applyOptions +type ReposImpl struct { + *GlobalImpl + *ReposOptions +} + +// NewReposImpl creates a new ReposImpl +func NewReposImpl(g *GlobalImpl, b *ReposOptions) *ReposImpl { + return &ReposImpl{ + GlobalImpl: g, + ReposOptions: b, + } +} + +// IncludeTransitiveNeeds returns the include transitive needs +func (r *ReposImpl) IncludeTransitiveNeeds() bool { + return false +} diff --git a/pkg/config/show-dag.go b/pkg/config/show-dag.go index 4c0bfe4d..83a7dea3 100644 --- a/pkg/config/show-dag.go +++ b/pkg/config/show-dag.go @@ -8,17 +8,3 @@ type ShowDAGOptions struct { func NewShowDAGOptions() *ShowDAGOptions { return &ShowDAGOptions{} } - -// ShowDAGImpl is impl for applyOptions -type ShowDAGImpl struct { - *GlobalImpl - *ShowDAGOptions -} - -// NewShowDAGImpl creates a new ShowDAGImpl -func NewShowDAGImpl(g *GlobalImpl, b *ShowDAGOptions) *ShowDAGImpl { - return &ShowDAGImpl{ - GlobalImpl: g, - ShowDAGOptions: b, - } -} diff --git a/pkg/config/show-dag_impl.go b/pkg/config/show-dag_impl.go new file mode 100644 index 00000000..4eeaa30a --- /dev/null +++ b/pkg/config/show-dag_impl.go @@ -0,0 +1,15 @@ +package config + +// ShowDAGImpl is impl for applyOptions +type ShowDAGImpl struct { + *GlobalImpl + *ShowDAGOptions +} + +// NewShowDAGImpl creates a new ShowDAGImpl +func NewShowDAGImpl(g *GlobalImpl, b *ShowDAGOptions) *ShowDAGImpl { + return &ShowDAGImpl{ + GlobalImpl: g, + ShowDAGOptions: b, + } +} diff --git a/pkg/config/status.go b/pkg/config/status.go index d7b5b772..e4b23e94 100644 --- a/pkg/config/status.go +++ b/pkg/config/status.go @@ -10,27 +10,3 @@ type StatusOptions struct { func NewStatusOptions() *StatusOptions { return &StatusOptions{} } - -// StatusImpl is impl for applyOptions -type StatusImpl struct { - *GlobalImpl - *StatusOptions -} - -// NewStatusImpl creates a new StatusImpl -func NewStatusImpl(g *GlobalImpl, b *StatusOptions) *StatusImpl { - return &StatusImpl{ - GlobalImpl: g, - StatusOptions: b, - } -} - -// IncludeTransitiveNeeds returns the include transitive needs -func (s *StatusImpl) IncludeTransitiveNeeds() bool { - return false -} - -// Concurrency returns the concurrency -func (s *StatusImpl) Concurrency() int { - return s.StatusOptions.Concurrency -} diff --git a/pkg/config/status_impl.go b/pkg/config/status_impl.go new file mode 100644 index 00000000..bd66497f --- /dev/null +++ b/pkg/config/status_impl.go @@ -0,0 +1,25 @@ +package config + +// StatusImpl is impl for applyOptions +type StatusImpl struct { + *GlobalImpl + *StatusOptions +} + +// NewStatusImpl creates a new StatusImpl +func NewStatusImpl(g *GlobalImpl, b *StatusOptions) *StatusImpl { + return &StatusImpl{ + GlobalImpl: g, + StatusOptions: b, + } +} + +// IncludeTransitiveNeeds returns the include transitive needs +func (s *StatusImpl) IncludeTransitiveNeeds() bool { + return false +} + +// Concurrency returns the concurrency +func (s *StatusImpl) Concurrency() int { + return s.StatusOptions.Concurrency +} diff --git a/pkg/config/sync.go b/pkg/config/sync.go index 681f3dd4..b7454064 100644 --- a/pkg/config/sync.go +++ b/pkg/config/sync.go @@ -1,6 +1,9 @@ package config -import "github.com/helmfile/helmfile/pkg/common" +import ( + "github.com/helmfile/helmfile/pkg/common" + "github.com/helmfile/helmfile/pkg/flags" +) // SyncOptions is the options for the build command type SyncOptions struct { @@ -50,148 +53,36 @@ type SyncOptions struct { SyncReleaseLabels bool } -// NewSyncOptions creates a new Apply +// NewSyncOptions creates a new SyncOption func NewSyncOptions() *SyncOptions { - newOptions := &SyncOptions{ - IncludeCRDsFlag: common.NewBoolFlag(false), - SkipCRDsFlag: common.NewBoolFlag(false), - } + newOptions := &SyncOptions{} + newOptions.Initialize() return newOptions } -// SyncImpl is impl for applyOptions -type SyncImpl struct { - *GlobalImpl - *SyncOptions +func (o *SyncOptions) Initialize() { + flags.EnsureBoolFlag(&o.IncludeCRDsFlag, false) + flags.EnsureBoolFlag(&o.SkipCRDsFlag, false) } -// NewSyncImpl creates a new SyncImpl -func NewSyncImpl(g *GlobalImpl, t *SyncOptions) *SyncImpl { - return &SyncImpl{ - GlobalImpl: g, - SyncOptions: t, - } -} - -// Concurrency returns the concurrency -func (t *SyncImpl) Concurrency() int { - return t.SyncOptions.Concurrency -} - -// IncludeNeeds returns the include needs -func (t *SyncImpl) IncludeNeeds() bool { - return t.SyncOptions.IncludeNeeds || t.IncludeTransitiveNeeds() -} - -// IncludeTransitiveNeeds returns the include transitive needs -func (t *SyncImpl) IncludeTransitiveNeeds() bool { - return t.SyncOptions.IncludeTransitiveNeeds -} - -// Set returns the Set -func (t *SyncImpl) Set() []string { - return t.SyncOptions.Set -} - -// SkipNeeds returns the skip needs -func (t *SyncImpl) SkipNeeds() bool { - if !t.IncludeNeeds() { - return t.SyncOptions.SkipNeeds +func (o *SyncOptions) HandleFlag(name string, value interface{}, changed bool) bool { + switch name { + case "include-crds": + if changed { + if boolVal, ok := value.(*bool); ok { + o.IncludeCRDsFlag.Set(*boolVal) + } + } + return true + case "skip-crds": + if changed { + if boolVal, ok := value.(*bool); ok { + o.SkipCRDsFlag.Set(*boolVal) + } + } + return true } return false } - -// Validate returns the validate -func (t *SyncImpl) Validate() bool { - return t.SyncOptions.Validate -} - -// Values returns the values -func (t *SyncImpl) Values() []string { - return t.SyncOptions.Values -} - -// SkipCRDs returns the skip crds -func (t *SyncImpl) SkipCRDs() bool { - return t.SyncOptions.SkipCRDsFlag.Value() -} - -// IncludeCRDs returns the include crds -func (t *SyncImpl) IncludeCRDs() bool { - return t.SyncOptions.IncludeCRDsFlag.Value() -} - -// ShouldIncludeCRDs returns true if CRDs should be included -func (t *SyncImpl) ShouldIncludeCRDs() bool { - includeCRDsExplicit := t.IncludeCRDsFlag.WasExplicitlySet() && t.IncludeCRDsFlag.Value() - skipCRDsExplicit := t.SkipCRDsFlag.WasExplicitlySet() && !t.SkipCRDsFlag.Value() - - return includeCRDsExplicit || skipCRDsExplicit -} - -// Wait returns the wait -func (t *SyncImpl) Wait() bool { - return t.SyncOptions.Wait -} - -// WaitRetries returns the wait retries -func (t *SyncImpl) WaitRetries() int { - return t.SyncOptions.WaitRetries -} - -// WaitForJobs returns the wait for jobs -func (t *SyncImpl) WaitForJobs() bool { - return t.SyncOptions.WaitForJobs -} - -// ReuseValues returns the ReuseValues. -func (t *SyncImpl) ReuseValues() bool { - if !t.ResetValues() { - return t.SyncOptions.ReuseValues - } - return false -} -func (t *SyncImpl) ResetValues() bool { - return t.SyncOptions.ResetValues -} - -// PostRenderer returns the PostRenderer. -func (t *SyncImpl) PostRenderer() string { - return t.SyncOptions.PostRenderer -} - -// PostRendererArgs returns the PostRendererArgs. -func (t *SyncImpl) PostRendererArgs() []string { - return t.SyncOptions.PostRendererArgs -} - -// SkipSchemaValidation returns the SkipSchemaValidation. -func (t *SyncImpl) SkipSchemaValidation() bool { - return t.SyncOptions.SkipSchemaValidation -} - -// Cascade returns cascade flag -func (t *SyncImpl) Cascade() string { - return t.SyncOptions.Cascade -} - -// SyncArgs returns the sync args -func (t *SyncImpl) SyncArgs() string { - return t.SyncOptions.SyncArgs -} - -// HideNotes returns the hide notes -func (t *SyncImpl) HideNotes() bool { - return t.SyncOptions.HideNotes -} - -// TakeOwnership returns the take ownership -func (t *SyncImpl) TakeOwnership() bool { - return t.SyncOptions.TakeOwnership -} - -func (t *SyncImpl) SyncReleaseLabels() bool { - return t.SyncOptions.SyncReleaseLabels -} diff --git a/pkg/config/sync_impl.go b/pkg/config/sync_impl.go new file mode 100644 index 00000000..d5417b74 --- /dev/null +++ b/pkg/config/sync_impl.go @@ -0,0 +1,134 @@ +package config + +// SyncImpl is impl for SyncOptions +type SyncImpl struct { + *GlobalImpl + *SyncOptions +} + +// NewSyncImpl creates a new SyncImpl +func NewSyncImpl(g *GlobalImpl, t *SyncOptions) *SyncImpl { + return &SyncImpl{ + GlobalImpl: g, + SyncOptions: t, + } +} + +// Concurrency returns the concurrency +func (t *SyncImpl) Concurrency() int { + return t.SyncOptions.Concurrency +} + +// IncludeNeeds returns the include needs +func (t *SyncImpl) IncludeNeeds() bool { + return t.SyncOptions.IncludeNeeds || t.IncludeTransitiveNeeds() +} + +// IncludeTransitiveNeeds returns the include transitive needs +func (t *SyncImpl) IncludeTransitiveNeeds() bool { + return t.SyncOptions.IncludeTransitiveNeeds +} + +// Set returns the Set +func (t *SyncImpl) Set() []string { + return t.SyncOptions.Set +} + +// SkipNeeds returns the skip needs +func (t *SyncImpl) SkipNeeds() bool { + if !t.IncludeNeeds() { + return t.SyncOptions.SkipNeeds + } + + return false +} + +// Validate returns the validate +func (t *SyncImpl) Validate() bool { + return t.SyncOptions.Validate +} + +// Values returns the values +func (t *SyncImpl) Values() []string { + return t.SyncOptions.Values +} + +// SkipCRDs returns the skip crds +func (t *SyncImpl) SkipCRDs() bool { + return t.SyncOptions.SkipCRDsFlag.Value() +} + +// IncludeCRDs returns the include crds +func (t *SyncImpl) IncludeCRDs() bool { + return t.SyncOptions.IncludeCRDsFlag.Value() +} + +// ShouldIncludeCRDs determines if CRDs should be included in the operation. +func (t *SyncImpl) ShouldIncludeCRDs() bool { + return ShouldIncludeCRDs(t.IncludeCRDsFlag, t.SkipCRDsFlag) +} + +// Wait returns the wait +func (t *SyncImpl) Wait() bool { + return t.SyncOptions.Wait +} + +// WaitRetries returns the wait retries +func (t *SyncImpl) WaitRetries() int { + return t.SyncOptions.WaitRetries +} + +// WaitForJobs returns the wait for jobs +func (t *SyncImpl) WaitForJobs() bool { + return t.SyncOptions.WaitForJobs +} + +// ReuseValues returns the ReuseValues. +func (t *SyncImpl) ReuseValues() bool { + if !t.ResetValues() { + return t.SyncOptions.ReuseValues + } + return false +} +func (t *SyncImpl) ResetValues() bool { + return t.SyncOptions.ResetValues +} + +// PostRenderer returns the PostRenderer. +func (t *SyncImpl) PostRenderer() string { + return t.SyncOptions.PostRenderer +} + +// PostRendererArgs returns the PostRendererArgs. +func (t *SyncImpl) PostRendererArgs() []string { + return t.SyncOptions.PostRendererArgs +} + +// SkipSchemaValidation returns the SkipSchemaValidation. +func (t *SyncImpl) SkipSchemaValidation() bool { + return t.SyncOptions.SkipSchemaValidation +} + +// Cascade returns cascade flag +func (t *SyncImpl) Cascade() string { + return t.SyncOptions.Cascade +} + +// SyncArgs returns the sync args +func (t *SyncImpl) SyncArgs() string { + return t.SyncOptions.SyncArgs +} + +// HideNotes returns the hide notes +func (t *SyncImpl) HideNotes() bool { + return t.SyncOptions.HideNotes +} + +// TakeOwnership returns the take ownership +func (t *SyncImpl) TakeOwnership() bool { + return t.SyncOptions.TakeOwnership +} + +func (t *SyncImpl) SyncReleaseLabels() bool { + return t.SyncOptions.SyncReleaseLabels +} diff --git a/pkg/config/sync_test.go b/pkg/config/sync_test.go new file mode 100644 index 00000000..c4e70454 --- /dev/null +++ b/pkg/config/sync_test.go @@ -0,0 +1,23 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSyncOptions_HandleFlag(t *testing.T) { + options := NewSyncOptions() + + // Test handling include-crds flag + includeCRDs := true + handled := options.HandleFlag("include-crds", &includeCRDs, true) + assert.True(t, handled, "include-crds flag should be handled") + assert.True(t, options.IncludeCRDsFlag.Value()) + + // Test handling skip-crds flag + skipCRDs := true + handled = options.HandleFlag("skip-crds", &skipCRDs, true) + assert.True(t, handled, "skip-crds flag should be handled") + assert.True(t, options.SkipCRDsFlag.Value()) +} diff --git a/pkg/config/template.go b/pkg/config/template.go index 6ce7902b..92e6ea4d 100644 --- a/pkg/config/template.go +++ b/pkg/config/template.go @@ -1,11 +1,8 @@ package config import ( - "fmt" - "os" - "strings" - "github.com/helmfile/helmfile/pkg/common" + "github.com/helmfile/helmfile/pkg/flags" ) // TemplateOptions is the options for the build command @@ -51,132 +48,28 @@ type TemplateOptions struct { ShowOnly []string } -// NewTemplateOptions creates a new Apply +// NewTemplateOptions creates a new TemplateOption func NewTemplateOptions() *TemplateOptions { - newOptions := &TemplateOptions{ - SkipCRDsFlag: common.NewBoolFlag(false), - IncludeCRDsFlag: common.NewBoolFlag(false), - } - return newOptions + options := &TemplateOptions{} + options.Initialize() + return options } -// TemplateImpl is impl for applyOptions -type TemplateImpl struct { - *GlobalImpl - *TemplateOptions +func (o *TemplateOptions) Initialize() { + flags.EnsureBoolFlag(&o.IncludeCRDsFlag, false) + flags.EnsureBoolFlag(&o.SkipCRDsFlag, false) // not exposed as cli flag but needed for ShouldIncludeCRDs() until skip-crds is removed } -// NewTemplateImpl creates a new TemplateImpl -func NewTemplateImpl(g *GlobalImpl, t *TemplateOptions) *TemplateImpl { - return &TemplateImpl{ - GlobalImpl: g, - TemplateOptions: t, - } -} - -// Concurrency returns the concurrency -func (t *TemplateImpl) Concurrency() int { - return t.TemplateOptions.Concurrency -} - -// SkipCRDs returns the skip crds -func (t *TemplateImpl) SkipCRDs() bool { - return t.TemplateOptions.SkipCRDsFlag.Value() -} - -// IncludeCRDs returns the include crds -func (t *TemplateImpl) IncludeCRDs() bool { - return t.TemplateOptions.IncludeCRDsFlag.Value() -} - -// ShouldIncludeCRDs returns whether to include crds -func (t *TemplateImpl) ShouldIncludeCRDs() bool { - includeCRDsExplicit := t.IncludeCRDsFlag.WasExplicitlySet() && t.IncludeCRDsFlag.Value() - skipCRDsExplicit := t.SkipCRDsFlag.WasExplicitlySet() && !t.SkipCRDsFlag.Value() - - return includeCRDsExplicit || skipCRDsExplicit -} - -// NoHooks returns the no hooks -func (t *TemplateImpl) NoHooks() bool { - return t.TemplateOptions.NoHooks -} - -// IncludeNeeds returns the include needs -func (t *TemplateImpl) IncludeNeeds() bool { - return t.TemplateOptions.IncludeNeeds || t.IncludeTransitiveNeeds() -} - -// IncludeTransitiveNeeds returns the include transitive needs -func (t *TemplateImpl) IncludeTransitiveNeeds() bool { - return t.TemplateOptions.IncludeTransitiveNeeds -} - -// OutputDir returns the output dir -func (t *TemplateImpl) OutputDir() string { - return strings.TrimRight(t.TemplateOptions.OutputDir, fmt.Sprintf("%c", os.PathSeparator)) -} - -// OutputDirTemplate returns the output dir template -func (t *TemplateImpl) OutputDirTemplate() string { - return t.TemplateOptions.OutputDirTemplate -} - -// Set returns the Set -func (t *TemplateImpl) Set() []string { - return t.TemplateOptions.Set -} - -// SkipCleanup returns the skip cleanup -func (t *TemplateImpl) SkipCleanup() bool { - return t.TemplateOptions.SkipCleanup -} - -// SkipNeeds returns the skip needs -func (t *TemplateImpl) SkipNeeds() bool { - if !t.IncludeNeeds() { - return t.TemplateOptions.SkipNeeds +func (o *TemplateOptions) HandleFlag(name string, value interface{}, changed bool) bool { + switch name { + case "include-crds": + if changed { + if boolVal, ok := value.(*bool); ok { + o.IncludeCRDsFlag.Set(*boolVal) + } + } + return true } return false } - -// SkipTests returns the skip tests -func (t *TemplateImpl) SkipTests() bool { - return t.TemplateOptions.SkipTests -} - -// Validate returns the validate -func (t *TemplateImpl) Validate() bool { - return t.TemplateOptions.Validate -} - -// Values returns the values -func (t *TemplateImpl) Values() []string { - return t.TemplateOptions.Values -} - -// PostRenderer returns the PostRenderer. -func (t *TemplateImpl) PostRenderer() string { - return t.TemplateOptions.PostRenderer -} - -// PostRendererArgs returns the PostRendererArgs. -func (t *TemplateImpl) PostRendererArgs() []string { - return t.TemplateOptions.PostRendererArgs -} - -// SkipSchemaValidation returns the SkipSchemaValidation. -func (t *TemplateImpl) SkipSchemaValidation() bool { - return t.TemplateOptions.SkipSchemaValidation -} - -// KubeVersion returns the the KubeVersion. -func (t *TemplateImpl) KubeVersion() string { - return t.TemplateOptions.KubeVersion -} - -// ShowOnly returns the ShowOnly. -func (t *TemplateImpl) ShowOnly() []string { - return t.TemplateOptions.ShowOnly -} diff --git a/pkg/config/template_impl.go b/pkg/config/template_impl.go new file mode 100644 index 00000000..af9086e1 --- /dev/null +++ b/pkg/config/template_impl.go @@ -0,0 +1,125 @@ +package config + +import ( + "fmt" + "os" + "strings" +) + +// TemplateImpl is impl for applyOptions +type TemplateImpl struct { + *GlobalImpl + *TemplateOptions +} + +// NewTemplateImpl creates a new TemplateImpl +func NewTemplateImpl(g *GlobalImpl, t *TemplateOptions) *TemplateImpl { + return &TemplateImpl{ + GlobalImpl: g, + TemplateOptions: t, + } +} + +// Concurrency returns the concurrency +func (t *TemplateImpl) Concurrency() int { + return t.TemplateOptions.Concurrency +} + +// SkipCRDs returns the skip crds +func (t *TemplateImpl) SkipCRDs() bool { + return t.TemplateOptions.SkipCRDsFlag.Value() +} + +// IncludeCRDs returns the include crds +func (t *TemplateImpl) IncludeCRDs() bool { + return t.TemplateOptions.IncludeCRDsFlag.Value() +} + +// ShouldIncludeCRDs determines if CRDs should be included in the operation. +func (t *TemplateImpl) ShouldIncludeCRDs() bool { + return ShouldIncludeCRDs(t.IncludeCRDsFlag, t.SkipCRDsFlag) +} + +// NoHooks returns the no hooks +func (t *TemplateImpl) NoHooks() bool { + return t.TemplateOptions.NoHooks +} + +// IncludeNeeds returns the include needs +func (t *TemplateImpl) IncludeNeeds() bool { + return t.TemplateOptions.IncludeNeeds || t.IncludeTransitiveNeeds() +} + +// IncludeTransitiveNeeds returns the include transitive needs +func (t *TemplateImpl) IncludeTransitiveNeeds() bool { + return t.TemplateOptions.IncludeTransitiveNeeds +} + +// OutputDir returns the output dir +func (t *TemplateImpl) OutputDir() string { + return strings.TrimRight(t.TemplateOptions.OutputDir, fmt.Sprintf("%c", os.PathSeparator)) +} + +// OutputDirTemplate returns the output dir template +func (t *TemplateImpl) OutputDirTemplate() string { + return t.TemplateOptions.OutputDirTemplate +} + +// Set returns the Set +func (t *TemplateImpl) Set() []string { + return t.TemplateOptions.Set +} + +// SkipCleanup returns the skip cleanup +func (t *TemplateImpl) SkipCleanup() bool { + return t.TemplateOptions.SkipCleanup +} + +// SkipNeeds returns the skip needs +func (t *TemplateImpl) SkipNeeds() bool { + if !t.IncludeNeeds() { + return t.TemplateOptions.SkipNeeds + } + + return false +} + +// SkipTests returns the skip tests +func (t *TemplateImpl) SkipTests() bool { + return t.TemplateOptions.SkipTests +} + +// Validate returns the validate +func (t *TemplateImpl) Validate() bool { + return t.TemplateOptions.Validate +} + +// Values returns the values +func (t *TemplateImpl) Values() []string { + return t.TemplateOptions.Values +} + +// PostRenderer returns the PostRenderer. +func (t *TemplateImpl) PostRenderer() string { + return t.TemplateOptions.PostRenderer +} + +// PostRendererArgs returns the PostRendererArgs. +func (t *TemplateImpl) PostRendererArgs() []string { + return t.TemplateOptions.PostRendererArgs +} + +// SkipSchemaValidation returns the SkipSchemaValidation. +func (t *TemplateImpl) SkipSchemaValidation() bool { + return t.TemplateOptions.SkipSchemaValidation +} + +// KubeVersion returns the the KubeVersion. +func (t *TemplateImpl) KubeVersion() string { + return t.TemplateOptions.KubeVersion +} + +// ShowOnly returns the ShowOnly. +func (t *TemplateImpl) ShowOnly() []string { + return t.TemplateOptions.ShowOnly +} diff --git a/pkg/config/template_test.go b/pkg/config/template_test.go new file mode 100644 index 00000000..41cbbd06 --- /dev/null +++ b/pkg/config/template_test.go @@ -0,0 +1,17 @@ +package config + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTemplateOptions_HandleFlag(t *testing.T) { + options := NewTemplateOptions() + + // Test handling include-crds flag + includeCRDs := true + handled := options.HandleFlag("include-crds", &includeCRDs, true) + assert.True(t, handled, "include-crds flag should be handled") + assert.True(t, options.IncludeCRDsFlag.Value()) +} diff --git a/pkg/config/test.go b/pkg/config/test.go index 74a9a97a..98bcfdfe 100644 --- a/pkg/config/test.go +++ b/pkg/config/test.go @@ -1,11 +1,5 @@ package config -import ( - "github.com/spf13/cobra" - - "github.com/helmfile/helmfile/pkg/state" -) - // TestOptions is the options for the build command type TestOptions struct { // Concurrency is the maximum number of concurrent helm processes to run, 0 is unlimited @@ -22,41 +16,3 @@ type TestOptions struct { func NewTestOptions() *TestOptions { return &TestOptions{} } - -// TestImpl is impl for applyOptions -type TestImpl struct { - *GlobalImpl - *TestOptions - Cmd *cobra.Command -} - -// NewTestImpl creates a new TestImpl -func NewTestImpl(g *GlobalImpl, t *TestOptions) *TestImpl { - return &TestImpl{ - GlobalImpl: g, - TestOptions: t, - } -} - -// Concurrency returns the concurrency -func (t *TestImpl) Concurrency() int { - return t.TestOptions.Concurrency -} - -// Cleanup returns the cleanup -func (t *TestImpl) Cleanup() bool { - return t.TestOptions.Cleanup -} - -// Logs returns the logs -func (t *TestImpl) Logs() bool { - return t.TestOptions.Logs -} - -// Timeout returns the timeout -func (t *TestImpl) Timeout() int { - if !t.Cmd.Flags().Changed("timeout") { - return state.EmptyTimeout - } - return t.TestOptions.Timeout -} diff --git a/pkg/config/test_impl.go b/pkg/config/test_impl.go new file mode 100644 index 00000000..1246011d --- /dev/null +++ b/pkg/config/test_impl.go @@ -0,0 +1,45 @@ +package config + +import ( + "github.com/spf13/cobra" + + "github.com/helmfile/helmfile/pkg/state" +) + +// TestImpl is impl for applyOptions +type TestImpl struct { + *GlobalImpl + *TestOptions + Cmd *cobra.Command +} + +// NewTestImpl creates a new TestImpl +func NewTestImpl(g *GlobalImpl, t *TestOptions) *TestImpl { + return &TestImpl{ + GlobalImpl: g, + TestOptions: t, + } +} + +// Concurrency returns the concurrency +func (t *TestImpl) Concurrency() int { + return t.TestOptions.Concurrency +} + +// Cleanup returns the cleanup +func (t *TestImpl) Cleanup() bool { + return t.TestOptions.Cleanup +} + +// Logs returns the logs +func (t *TestImpl) Logs() bool { + return t.TestOptions.Logs +} + +// Timeout returns the timeout +func (t *TestImpl) Timeout() int { + if !t.Cmd.Flags().Changed("timeout") { + return state.EmptyTimeout + } + return t.TestOptions.Timeout +} diff --git a/pkg/config/write-values.go b/pkg/config/write-values.go index 5e5c2ffe..99a7e6dd 100644 --- a/pkg/config/write-values.go +++ b/pkg/config/write-values.go @@ -16,47 +16,3 @@ type WriteValuesOptions struct { func NewWriteValuesOptions() *WriteValuesOptions { return &WriteValuesOptions{} } - -// WriteValuesImpl is impl for applyOptions -type WriteValuesImpl struct { - *GlobalImpl - *WriteValuesOptions -} - -// NewWriteValuesImpl creates a new WriteValuesImpl -func NewWriteValuesImpl(g *GlobalImpl, b *WriteValuesOptions) *WriteValuesImpl { - return &WriteValuesImpl{ - GlobalImpl: g, - WriteValuesOptions: b, - } -} - -// Concurrency returns the concurrency -func (c *WriteValuesImpl) Concurrency() int { - return c.WriteValuesOptions.Concurrency -} - -// Set returns the Set -func (c *WriteValuesImpl) Set() []string { - return c.WriteValuesOptions.Set -} - -// Values returns the Values -func (c *WriteValuesImpl) Values() []string { - return c.WriteValuesOptions.Values -} - -// SkipCleanUp returns the skip clean up -func (c *WriteValuesImpl) SkipCleanup() bool { - return false -} - -// IncludeTransitiveNeeds returns the include transitive needs -func (c *WriteValuesImpl) IncludeTransitiveNeeds() bool { - return false -} - -// OutputFileTemplate returns the output file template -func (c *WriteValuesImpl) OutputFileTemplate() string { - return c.WriteValuesOptions.OutputFileTemplate -} diff --git a/pkg/config/write-values_impl.go b/pkg/config/write-values_impl.go new file mode 100644 index 00000000..2861197e --- /dev/null +++ b/pkg/config/write-values_impl.go @@ -0,0 +1,45 @@ +package config + +// WriteValuesImpl is impl for applyOptions +type WriteValuesImpl struct { + *GlobalImpl + *WriteValuesOptions +} + +// NewWriteValuesImpl creates a new WriteValuesImpl +func NewWriteValuesImpl(g *GlobalImpl, b *WriteValuesOptions) *WriteValuesImpl { + return &WriteValuesImpl{ + GlobalImpl: g, + WriteValuesOptions: b, + } +} + +// Concurrency returns the concurrency +func (c *WriteValuesImpl) Concurrency() int { + return c.WriteValuesOptions.Concurrency +} + +// Set returns the Set +func (c *WriteValuesImpl) Set() []string { + return c.WriteValuesOptions.Set +} + +// Values returns the Values +func (c *WriteValuesImpl) Values() []string { + return c.WriteValuesOptions.Values +} + +// SkipCleanUp returns the skip clean up +func (c *WriteValuesImpl) SkipCleanup() bool { + return false +} + +// IncludeTransitiveNeeds returns the include transitive needs +func (c *WriteValuesImpl) IncludeTransitiveNeeds() bool { + return false +} + +// OutputFileTemplate returns the output file template +func (c *WriteValuesImpl) OutputFileTemplate() string { + return c.WriteValuesOptions.OutputFileTemplate +}