Repository: roboll/helmfile
Pull request #1744 (2021-03-29 13:34:30)

Add .StateValues as alias of .Values in releaseTemplateDataRelease
ralates #1743 


Patch:
diff --git a/main.go b/main.go
index 2ea7c1f..a708e4b 100644
--- a/main.go
+++ b/main.go
@@ -200,6 +200,10 @@ func main() {
 					Name:  "suppress-secrets",
 					Usage: "suppress secrets in the output. highly recommended to specify on CI/CD use-cases",
 				},
+				cli.BoolFlag{
+					Name:  "show-secrets",
+					Usage: "do not redact secret values in the output. should be used for debug purpose only",
+				},
 				cli.IntFlag{
 					Name:  "concurrency",
 					Value: 0,
@@ -327,6 +331,28 @@ func main() {
 				return run.Lint(c)
 			}),
 		},
+		{
+			Name:  "fetch",
+			Usage: "fetch charts from state file",
+			Flags: []cli.Flag{
+				cli.IntFlag{
+					Name:  "concurrency",
+					Value: 0,
+					Usage: "maximum number of concurrent downloads of release charts",
+				},
+				cli.BoolFlag{
+					Name:  "skip-deps",
+					Usage: `skip running "helm repo update" and "helm dependency build"`,
+				},
+				cli.StringFlag{
+					Name:  "output-dir",
+					Usage: "directory to store charts (default: temporary directory which is deleted when the command terminates)",
+				},
+			},
+			Action: action(func(a *app.App, c configImpl) error {
+				return a.Fetch(c)
+			}),
+		},
 		{
 			Name:  "sync",
 			Usage: "sync all resources from state file (repos, releases and chart deps)",
@@ -417,6 +443,10 @@ func main() {
 					Name:  "suppress-secrets",
 					Usage: "suppress secrets in the diff output. highly recommended to specify on CI/CD use-cases",
 				},
+				cli.BoolFlag{
+					Name:  "show-secrets",
+					Usage: "do not redact secret values in the diff output. should be used for debug purpose only",
+				},
 				cli.BoolFlag{
 					Name:  "suppress-diff",
 					Usage: "suppress diff in the output. Usable in new installs",
@@ -553,6 +583,10 @@ func main() {
 					Value: "",
 					Usage: "output releases list as a json string",
 				},
+				cli.BoolFlag{
+					Name:  "keep-temp-dir",
+					Usage: "Keep temporary directory",
+				},
 			},
 			Action: action(func(run *app.App, c configImpl) error {
 				return run.ListReleases(c)
@@ -687,6 +721,10 @@ func (c configImpl) SuppressSecrets() bool {
 	return c.c.Bool("suppress-secrets")
 }
 
+func (c configImpl) ShowSecrets() bool {
+	return c.c.Bool("show-secrets")
+}
+
 func (c configImpl) SuppressDiff() bool {
 	return c.c.Bool("suppress-diff")
 }
@@ -720,6 +758,10 @@ func (c configImpl) Output() string {
 	return c.c.String("output")
 }
 
+func (c configImpl) KeepTempDir() bool {
+	return c.c.Bool("keep-temp-dir")
+}
+
 // GlobalConfig
 
 func (c configImpl) HelmBinary() string {
diff --git a/pkg/app/app.go b/pkg/app/app.go
index 8a78c9c..70cc254 100644
--- a/pkg/app/app.go
+++ b/pkg/app/app.go
@@ -291,6 +291,24 @@ func (a *App) Lint(c LintConfigProvider) error {
 	}, SetFilter(true))
 }
 
+func (a *App) Fetch(c FetchConfigProvider) error {
+	return a.ForEachState(func(run *Run) (ok bool, errs []error) {
+		prepErr := run.withPreparedCharts("pull", state.ChartPrepareOptions{
+			ForceDownload: true,
+			SkipRepos:     c.SkipDeps(),
+			SkipDeps:      c.SkipDeps(),
+			OutputDir:     c.OutputDir(),
+		}, func() {
+		})
+
+		if prepErr != nil {
+			errs = append(errs, prepErr)
+		}
+
+		return
+	}, SetFilter(true))
+}
+
 func (a *App) Sync(c SyncConfigProvider) error {
 	return a.ForEachState(func(run *Run) (ok bool, errs []error) {
 		prepErr := run.withPreparedCharts("sync", state.ChartPrepareOptions{
diff --git a/pkg/app/config.go b/pkg/app/config.go
index edfa461..2bbe240 100644
--- a/pkg/app/config.go
+++ b/pkg/app/config.go
@@ -45,6 +45,7 @@ type ApplyConfigProvider interface {
 	IncludeTests() bool
 
 	SuppressSecrets() bool
+	ShowSecrets() bool
 	SuppressDiff() bool
 
 	DetailedExitcode() bool
@@ -84,6 +85,7 @@ type DiffConfigProvider interface {
 	IncludeTests() bool
 
 	SuppressSecrets() bool
+	ShowSecrets() bool
 	SuppressDiff() bool
 
 	DetailedExitcode() bool
@@ -131,6 +133,13 @@ type LintConfigProvider interface {
 	concurrencyConfig
 }
 
+type FetchConfigProvider interface {
+	SkipDeps() bool
+	OutputDir() string
+
+	concurrencyConfig
+}
+
 type TemplateConfigProvider interface {
 	Args() string
 
diff --git a/pkg/app/desired_state_file_loader.go b/pkg/app/desired_state_file_loader.go
index 401228e..c106d80 100644
--- a/pkg/app/desired_state_file_loader.go
+++ b/pkg/app/desired_state_file_loader.go
@@ -72,9 +72,6 @@ func (ld *desiredStateLoader) Load(f string, opts LoadOpts) (*state.HelmState, e
 	}
 
 	if ld.overrideKubeContext != "" {
-		if st.HelmDefaults.KubeContext != "" {
-			return nil, errors.New("err: Cannot use option --kube-context and set attribute helmDefaults.kubeContext.")
-		}
 		st.HelmDefaults.KubeContext = ld.overrideKubeContext
 	}
 
diff --git a/pkg/app/run.go b/pkg/app/run.go
index 221ba09..298bcb2 100644
--- a/pkg/app/run.go
+++ b/pkg/app/run.go
@@ -2,13 +2,14 @@ package app
 
 import (
 	"fmt"
-	"github.com/roboll/helmfile/pkg/argparser"
-	"github.com/roboll/helmfile/pkg/helmexec"
-	"github.com/roboll/helmfile/pkg/state"
 	"io/ioutil"
 	"os"
 	"sort"
 	"strings"
+
+	"github.com/roboll/helmfile/pkg/argparser"
+	"github.com/roboll/helmfile/pkg/helmexec"
+	"github.com/roboll/helmfile/pkg/state"
 )
 
 type Run struct {
@@ -49,13 +50,20 @@ func (r *Run) withPreparedCharts(helmfileCommand string, opts state.ChartPrepare
 	}
 
 	// Create tmp directory and bail immediately if it fails
-	dir, err := ioutil.TempDir("", "")
-	if err != nil {
-		return err
+	var dir string
+	if len(opts.OutputDir) == 0 {
+		tempDir, err := ioutil.TempDir("", "helmfile*")
+		if err != nil {
+			return err
+		}
+		defer os.RemoveAll(tempDir)
+		dir = tempDir
+	} else {
+		dir = opts.OutputDir
+		fmt.Printf("Charts will be downloaded to: %s\n", dir)
 	}
-	defer os.RemoveAll(dir)
 
-	if _, err = r.state.TriggerGlobalPrepareEvent(helmfileCommand); err != nil {
+	if _, err := r.state.TriggerGlobalPrepareEvent(helmfileCommand); err != nil {
 		return err
 	}
 
@@ -82,7 +90,7 @@ func (r *Run) withPreparedCharts(helmfileCommand string, opts state.ChartPrepare
 
 	f()
 
-	_, err = r.state.TriggerGlobalCleanupEvent(helmfileCommand)
+	_, err := r.state.TriggerGlobalCleanupEvent(helmfileCommand)
 
 	return err
 }
@@ -214,7 +222,7 @@ func (run *Run) diff(triggerCleanupEvent bool, detailedExitCode bool, c DiffConf
 
 	// TODO Better way to detect diff on only filtered releases
 	{
-		changedReleases, planningErrs = st.DiffReleases(helm, c.Values(), c.Concurrency(), detailedExitCode, c.IncludeTests(), c.SuppressSecrets(), c.SuppressDiff(), triggerCleanupEvent, diffOpts)
+		changedReleases, planningErrs = st.DiffReleases(helm, c.Values(), c.Concurrency(), detailedExitCode, c.IncludeTests(), c.SuppressSecrets(), c.ShowSecrets(), c.SuppressDiff(), triggerCleanupEvent, diffOpts)
 
 		var err error
 		deletingReleases, err = st.DetectReleasesToBeDeletedForSync(helm, st.Releases)
diff --git a/pkg/state/state.go b/pkg/state/state.go
index 491ab54..066832f 100644
--- a/pkg/state/state.go
+++ b/pkg/state/state.go
@@ -896,6 +896,7 @@ type ChartPrepareOptions struct {
 	SkipResolve   bool
 	Wait          bool
 	WaitForJobs   bool
+	OutputDir     string
 }
 
 type chartPrepareResult struct {
@@ -1524,7 +1525,7 @@ type diffPrepareResult struct {
 	upgradeDueToSkippedDiff bool
 }
 
-func (st *HelmState) prepareDiffReleases(helm helmexec.Interface, additionalValues []string, concurrency int, detailedExitCode, includeTests, suppressSecrets bool, opt ...DiffOpt) ([]diffPrepareResult, []error) {
+func (st *HelmState) prepareDiffReleases(helm helmexec.Interface, additionalValues []string, concurrency int, detailedExitCode, includeTests, suppressSecrets bool, showSecrets bool, opt ...DiffOpt) ([]diffPrepareResult, []error) {
 	opts := &DiffOpts{}
 	for _, o := range opt {
 		o.Apply(opts)
@@ -1629,6 +1630,10 @@ func (st *HelmState) prepareDiffReleases(helm helmexec.Interface, additionalValu
 					flags = append(flags, "--suppress-secrets")
 				}
 
+				if showSecrets {
+					flags = append(flags, "--show-secrets")
+				}
+
 				if opts.NoColor {
 					flags = append(flags, "--no-color")
 				}
@@ -1734,13 +1739,13 @@ type DiffOpt interface{ Apply(*DiffOpts) }
 // For example, terraform-provider-helmfile runs a helmfile-diff on `terraform plan` and another on `terraform apply`.
 // `terraform`, by design, fails when helmfile-diff outputs were not equivalent.
 // Stabilized helmfile-diff output rescues that.
-func (st *HelmState) DiffReleases(helm helmexec.Interface, additionalValues []string, workerLimit int, detailedExitCode, includeTests, suppressSecrets, suppressDiff, triggerCleanupEvents bool, opt ...DiffOpt) ([]ReleaseSpec, []error) {
+func (st *HelmState) DiffReleases(helm helmexec.Interface, additionalValues []string, workerLimit int, detailedExitCode, includeTests, suppressSecrets, showSecrets, suppressDiff, triggerCleanupEvents bool, opt ...DiffOpt) ([]ReleaseSpec, []error) {
 	opts := &DiffOpts{}
 	for _, o := range opt {
 		o.Apply(opts)
 	}
 
-	preps, prepErrs := st.prepareDiffReleases(helm, additionalValues, workerLimit, detailedExitCode, includeTests, suppressSecrets, opts)
+	preps, prepErrs := st.prepareDiffReleases(helm, additionalValues, workerLimit, detailedExitCode, includeTests, suppressSecrets, showSecrets, opts)
 
 	defer func() {
 		if opts.SkipCleanup {
diff --git a/pkg/state/state_exec_tmpl.go b/pkg/state/state_exec_tmpl.go
index 7c62717..023287f 100644
--- a/pkg/state/state_exec_tmpl.go
+++ b/pkg/state/state_exec_tmpl.go
@@ -17,7 +17,7 @@ func (st *HelmState) Values() map[string]interface{} {
 }
 
 func (st *HelmState) createReleaseTemplateData(release *ReleaseSpec, vals map[string]interface{}) releaseTemplateData {
-	return releaseTemplateData{
+	tmplData := releaseTemplateData{
 		Environment: st.Env,
 		Namespace:   st.OverrideNamespace,
 		Values:      vals,
@@ -28,6 +28,8 @@ func (st *HelmState) createReleaseTemplateData(release *ReleaseSpec, vals map[st
 			Labels:    release.Labels,
 		},
 	}
+	tmplData.StateValues = &tmplData.Values
+	return tmplData
 }
 
 func getBoolRefFromStringTemplate(templateRef string) (*bool, error) {
diff --git a/pkg/state/types.go b/pkg/state/types.go
index 2b76b8e..9e28c84 100644
--- a/pkg/state/types.go
+++ b/pkg/state/types.go
@@ -28,7 +28,8 @@ type releaseTemplateData struct {
 	// It contains a subset of ReleaseSpec that is known to be useful to dynamically render values.
 	Release releaseTemplateDataRelease
 	// Values is accessible as `.Values` and it contains default state values overrode by environment values and override values.
-	Values map[string]interface{}
+	Values      map[string]interface{}
+	StateValues *map[string]interface{}
 	// Namespace is HelmState.OverrideNamespace.
 	// You should better use Release.Namespace as it might work as you'd expect even if OverrideNamespace is not set.
 	// See releaseTemplateDataRelease.Namespace for more information.


Test patch:
diff --git a/pkg/app/app_test.go b/pkg/app/app_test.go
index b1c2e97..213ae93 100644
--- a/pkg/app/app_test.go
+++ b/pkg/app/app_test.go
@@ -2308,6 +2308,7 @@ type applyConfig struct {
 	skipDeps          bool
 	includeTests      bool
 	suppressSecrets   bool
+	showSecrets       bool
 	suppressDiff      bool
 	noColor           bool
 	context           int
@@ -2360,6 +2361,10 @@ func (a applyConfig) SuppressSecrets() bool {
 	return a.suppressSecrets
 }
 
+func (a applyConfig) ShowSecrets() bool {
+	return a.showSecrets
+}
+
 func (a applyConfig) SuppressDiff() bool {
 	return a.suppressDiff
 }
diff --git a/pkg/app/diff_test.go b/pkg/app/diff_test.go
index 8b5127e..90eade1 100644
--- a/pkg/app/diff_test.go
+++ b/pkg/app/diff_test.go
@@ -23,6 +23,7 @@ type diffConfig struct {
 	skipDeps          bool
 	includeTests      bool
 	suppressSecrets   bool
+	showSecrets       bool
 	suppressDiff      bool
 	noColor           bool
 	context           int
@@ -60,6 +61,10 @@ func (a diffConfig) SuppressSecrets() bool {
 	return a.suppressSecrets
 }
 
+func (a diffConfig) ShowSecrets() bool {
+	return a.showSecrets
+}
+
 func (a diffConfig) SuppressDiff() bool {
 	return a.suppressDiff
 }
diff --git a/pkg/state/state_test.go b/pkg/state/state_test.go
index 4e426fe..06db9c2 100644
--- a/pkg/state/state_test.go
+++ b/pkg/state/state_test.go
@@ -1570,7 +1570,7 @@ func TestHelmState_DiffReleases(t *testing.T) {
 				valsRuntime:    valsRuntime,
 				RenderedValues: map[string]interface{}{},
 			}
-			_, errs := state.DiffReleases(tt.helm, []string{}, 1, false, false, false, false, false)
+			_, errs := state.DiffReleases(tt.helm, []string{}, 1, false, false, false, false, false, false)
 			if errs != nil && len(errs) > 0 {
 				t.Errorf("unexpected error: %v", errs)
 			}
@@ -1741,7 +1741,7 @@ func TestHelmState_DiffReleasesCleanup(t *testing.T) {
 `,
 			})
 			state = injectFs(state, testfs)
-			if _, errs := state.DiffReleases(tt.helm, []string{}, 1, false, false, false, false, false); errs != nil && len(errs) > 0 {
+			if _, errs := state.DiffReleases(tt.helm, []string{}, 1, false, false, false, false, false, false); errs != nil && len(errs) > 0 {
 				t.Errorf("unexpected errors: %v", errs)
 			}
 
diff --git a/pkg/state/temp_test.go b/pkg/state/temp_test.go
index c19f562..ffb609b 100644
--- a/pkg/state/temp_test.go
+++ b/pkg/state/temp_test.go
@@ -1,8 +1,9 @@
 package state
 
 import (
-	"github.com/google/go-cmp/cmp"
 	"testing"
+
+	"github.com/google/go-cmp/cmp"
 )
 
 func TestGenerateID(t *testing.T) {