feat: `helmfile --log-level=debug apply --retain-values-files` (#1127)
`--retain-values-files` prevents temporary values files that were passed to Helm commands run by Helmfile for debugging purpose. With that, you can manually rerun helm commands that were logged when `--log-level=debug` is enabled. Resolves ##1117
This commit is contained in:
		
							parent
							
								
									0186254e79
								
							
						
					
					
						commit
						af44965949
					
				
							
								
								
									
										8
									
								
								main.go
								
								
								
								
							
							
						
						
									
										8
									
								
								main.go
								
								
								
								
							| 
						 | 
					@ -338,6 +338,10 @@ func main() {
 | 
				
			||||||
					Value: "",
 | 
										Value: "",
 | 
				
			||||||
					Usage: "pass args to helm exec",
 | 
										Usage: "pass args to helm exec",
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
 | 
									cli.BoolFlag{
 | 
				
			||||||
 | 
										Name:  "retain-values-files",
 | 
				
			||||||
 | 
										Usage: "Stop cleaning up values files passed to Helm. Together with --log-level=debug, you can manually rerun helm commands as Helmfile did for debugging purpose",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
				cli.BoolFlag{
 | 
									cli.BoolFlag{
 | 
				
			||||||
					Name:  "suppress-secrets",
 | 
										Name:  "suppress-secrets",
 | 
				
			||||||
					Usage: "suppress secrets in the diff output. highly recommended to specify on CI/CD use-cases",
 | 
										Usage: "suppress secrets in the diff output. highly recommended to specify on CI/CD use-cases",
 | 
				
			||||||
| 
						 | 
					@ -542,6 +546,10 @@ func (c configImpl) DetailedExitcode() bool {
 | 
				
			||||||
	return c.c.Bool("detailed-exitcode")
 | 
						return c.c.Bool("detailed-exitcode")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c configImpl) RetainValuesFiles() bool {
 | 
				
			||||||
 | 
						return c.c.Bool("retain-values-files")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c configImpl) SuppressSecrets() bool {
 | 
					func (c configImpl) SuppressSecrets() bool {
 | 
				
			||||||
	return c.c.Bool("suppress-secrets")
 | 
						return c.c.Bool("suppress-secrets")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -155,7 +155,7 @@ func (a *App) Apply(c ApplyConfigProvider) error {
 | 
				
			||||||
		mut.Unlock()
 | 
							mut.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return matched, errs
 | 
							return matched, errs
 | 
				
			||||||
	})
 | 
						}, c.RetainValuesFiles())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
| 
						 | 
					@ -343,7 +343,7 @@ func (a *App) visitStates(fileOrDir string, defOpts LoadOpts, converge func(*sta
 | 
				
			||||||
			sig := <-sigs
 | 
								sig := <-sigs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			errs := []error{fmt.Errorf("Received [%s] to shutdown ", sig)}
 | 
								errs := []error{fmt.Errorf("Received [%s] to shutdown ", sig)}
 | 
				
			||||||
			_ = context{a, st}.clean(errs)
 | 
								_ = context{app: a, st: st, retainValues: defOpts.RetainValuesFiles}.clean(errs)
 | 
				
			||||||
			// See http://tldp.org/LDP/abs/html/exitcodes.html
 | 
								// See http://tldp.org/LDP/abs/html/exitcodes.html
 | 
				
			||||||
			switch sig {
 | 
								switch sig {
 | 
				
			||||||
			case syscall.SIGINT:
 | 
								case syscall.SIGINT:
 | 
				
			||||||
| 
						 | 
					@ -353,7 +353,7 @@ func (a *App) visitStates(fileOrDir string, defOpts LoadOpts, converge func(*sta
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}()
 | 
							}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ctx := context{a, st}
 | 
							ctx := context{app: a, st: st, retainValues: defOpts.RetainValuesFiles}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		helm := a.helmExecer
 | 
							helm := a.helmExecer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -409,7 +409,7 @@ func (a *App) visitStates(fileOrDir string, defOpts LoadOpts, converge func(*sta
 | 
				
			||||||
		processed, errs := converge(templated, helm)
 | 
							processed, errs := converge(templated, helm)
 | 
				
			||||||
		noMatchInHelmfiles = noMatchInHelmfiles && !processed
 | 
							noMatchInHelmfiles = noMatchInHelmfiles && !processed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return context{a, templated}.clean(errs)
 | 
							return context{app: a, st: templated, retainValues: defOpts.RetainValuesFiles}.clean(errs)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -434,12 +434,12 @@ func (a *App) ForEachStateFiltered(do func(*Run) []error) error {
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a *App) ForEachState(do func(*Run) (bool, []error)) error {
 | 
					func (a *App) ForEachState(do func(*Run) (bool, []error), retainValues ...bool) error {
 | 
				
			||||||
	ctx := NewContext()
 | 
						ctx := NewContext()
 | 
				
			||||||
	err := a.visitStatesWithSelectorsAndRemoteSupport(a.FileOrDir, func(st *state.HelmState, helm helmexec.Interface) (bool, []error) {
 | 
						err := a.visitStatesWithSelectorsAndRemoteSupport(a.FileOrDir, func(st *state.HelmState, helm helmexec.Interface) (bool, []error) {
 | 
				
			||||||
		run := NewRun(st, helm, ctx)
 | 
							run := NewRun(st, helm, ctx)
 | 
				
			||||||
		return do(run)
 | 
							return do(run)
 | 
				
			||||||
	})
 | 
						}, retainValues...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -511,11 +511,15 @@ type Opts struct {
 | 
				
			||||||
	DAGEnabled bool
 | 
						DAGEnabled bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a *App) visitStatesWithSelectorsAndRemoteSupport(fileOrDir string, converge func(*state.HelmState, helmexec.Interface) (bool, []error)) error {
 | 
					func (a *App) visitStatesWithSelectorsAndRemoteSupport(fileOrDir string, converge func(*state.HelmState, helmexec.Interface) (bool, []error), retainValues ...bool) error {
 | 
				
			||||||
	opts := LoadOpts{
 | 
						opts := LoadOpts{
 | 
				
			||||||
		Selectors: a.Selectors,
 | 
							Selectors: a.Selectors,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(retainValues) > 0 {
 | 
				
			||||||
 | 
							opts.RetainValuesFiles = retainValues[0]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	envvals := []interface{}{}
 | 
						envvals := []interface{}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if a.ValuesFiles != nil {
 | 
						if a.ValuesFiles != nil {
 | 
				
			||||||
| 
						 | 
					@ -1222,9 +1226,11 @@ func (c context) clean(errs []error) error {
 | 
				
			||||||
		errs = []error{}
 | 
							errs = []error{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cleanErrs := c.st.Clean()
 | 
						if !c.retainValues {
 | 
				
			||||||
	if cleanErrs != nil {
 | 
							cleanErrs := c.st.Clean()
 | 
				
			||||||
		errs = append(errs, cleanErrs...)
 | 
							if cleanErrs != nil {
 | 
				
			||||||
 | 
								errs = append(errs, cleanErrs...)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return c.wrapErrs(errs...)
 | 
						return c.wrapErrs(errs...)
 | 
				
			||||||
| 
						 | 
					@ -1233,6 +1239,8 @@ func (c context) clean(errs []error) error {
 | 
				
			||||||
type context struct {
 | 
					type context struct {
 | 
				
			||||||
	app *App
 | 
						app *App
 | 
				
			||||||
	st  *state.HelmState
 | 
						st  *state.HelmState
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						retainValues bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c context) wrapErrs(errs ...error) error {
 | 
					func (c context) wrapErrs(errs ...error) error {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1890,18 +1890,19 @@ func (c configImpl) Concurrency() int {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type applyConfig struct {
 | 
					type applyConfig struct {
 | 
				
			||||||
	args             string
 | 
						args              string
 | 
				
			||||||
	values           []string
 | 
						values            []string
 | 
				
			||||||
	set              []string
 | 
						retainValuesFiles bool
 | 
				
			||||||
	skipDeps         bool
 | 
						set               []string
 | 
				
			||||||
	suppressSecrets  bool
 | 
						skipDeps          bool
 | 
				
			||||||
	suppressDiff     bool
 | 
						suppressSecrets   bool
 | 
				
			||||||
	noColor          bool
 | 
						suppressDiff      bool
 | 
				
			||||||
	context          int
 | 
						noColor           bool
 | 
				
			||||||
	concurrency      int
 | 
						context           int
 | 
				
			||||||
	detailedExitcode bool
 | 
						concurrency       int
 | 
				
			||||||
	interactive      bool
 | 
						detailedExitcode  bool
 | 
				
			||||||
	logger           *zap.SugaredLogger
 | 
						interactive       bool
 | 
				
			||||||
 | 
						logger            *zap.SugaredLogger
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a applyConfig) Args() string {
 | 
					func (a applyConfig) Args() string {
 | 
				
			||||||
| 
						 | 
					@ -1952,6 +1953,10 @@ func (a applyConfig) Logger() *zap.SugaredLogger {
 | 
				
			||||||
	return a.logger
 | 
						return a.logger
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (a applyConfig) RetainValuesFiles() bool {
 | 
				
			||||||
 | 
						return a.retainValuesFiles
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Mocking the command-line runner
 | 
					// Mocking the command-line runner
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type mockRunner struct {
 | 
					type mockRunner struct {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,6 +48,8 @@ type ApplyConfigProvider interface {
 | 
				
			||||||
	NoColor() bool
 | 
						NoColor() bool
 | 
				
			||||||
	Context() int
 | 
						Context() int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RetainValuesFiles() bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	concurrencyConfig
 | 
						concurrencyConfig
 | 
				
			||||||
	interactive
 | 
						interactive
 | 
				
			||||||
	loggingConfig
 | 
						loggingConfig
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,8 @@ type LoadOpts struct {
 | 
				
			||||||
	Selectors   []string
 | 
						Selectors   []string
 | 
				
			||||||
	Environment state.SubhelmfileEnvironmentSpec
 | 
						Environment state.SubhelmfileEnvironmentSpec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RetainValuesFiles bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// CalleePath is the absolute path to the file being loaded
 | 
						// CalleePath is the absolute path to the file being loaded
 | 
				
			||||||
	CalleePath string
 | 
						CalleePath string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue