Port the `needs` fix for `helmfile apply` to `sync`, and make `template` DAG-aware (#940)
This ports the fix for `helfmile apply` to `sync`, so that specifying `--selector` doesn't break `helmfile sync`. Also make `helmfile template` DAG-aware, so that the manifests are rendered in the order of dependency. Ref #919
This commit is contained in:
		
							parent
							
								
									35adb8ae22
								
							
						
					
					
						commit
						ed7a6d9051
					
				
							
								
								
									
										159
									
								
								pkg/app/app.go
								
								
								
								
							
							
						
						
									
										159
									
								
								pkg/app/app.go
								
								
								
								
							| 
						 | 
					@ -128,8 +128,8 @@ func (a *App) Diff(c DiffConfigProvider) error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a *App) Template(c TemplateConfigProvider) error {
 | 
					func (a *App) Template(c TemplateConfigProvider) error {
 | 
				
			||||||
	return a.ForEachStateFiltered(func(run *Run) []error {
 | 
						return a.ForEachState(func(run *Run) (bool, []error) {
 | 
				
			||||||
		return run.Template(c)
 | 
							return a.template(run, c)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,8 +140,8 @@ func (a *App) Lint(c LintConfigProvider) error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a *App) Sync(c SyncConfigProvider) error {
 | 
					func (a *App) Sync(c SyncConfigProvider) error {
 | 
				
			||||||
	return a.ForEachStateFiltered(func(run *Run) []error {
 | 
						return a.ForEachState(func(run *Run) (bool, []error) {
 | 
				
			||||||
		return run.Sync(c)
 | 
							return a.sync(run, c)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -901,6 +901,157 @@ Do you really want to delete?
 | 
				
			||||||
	return any, errs
 | 
						return any, errs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (a *App) sync(r *Run, c SyncConfigProvider) (bool, []error) {
 | 
				
			||||||
 | 
						st := r.state
 | 
				
			||||||
 | 
						helm := r.helm
 | 
				
			||||||
 | 
						ctx := r.ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						affectedReleases := state.AffectedReleases{}
 | 
				
			||||||
 | 
						if !c.SkipDeps() {
 | 
				
			||||||
 | 
							if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
 | 
				
			||||||
 | 
								return false, errs
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
 | 
				
			||||||
 | 
								return false, errs
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if errs := st.PrepareReleases(helm, "sync"); errs != nil && len(errs) > 0 {
 | 
				
			||||||
 | 
							return false, errs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var syncedReleases []state.ReleaseSpec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(st.Selectors) > 0 {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
							syncedReleases, err = st.GetFilteredReleases()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return false, []error{err}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(syncedReleases) == 0 {
 | 
				
			||||||
 | 
								return false, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							syncedReleases = st.Releases
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						releasesToBeSynced := map[string]state.ReleaseSpec{}
 | 
				
			||||||
 | 
						for _, r := range syncedReleases {
 | 
				
			||||||
 | 
							id := state.ReleaseToID(&r)
 | 
				
			||||||
 | 
							releasesToBeSynced[id] = r
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						names := make([]string, len(syncedReleases))
 | 
				
			||||||
 | 
						for i, r := range syncedReleases {
 | 
				
			||||||
 | 
							names[i] = fmt.Sprintf("  %s (%s)", r.Name, r.Chart)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var errs []error
 | 
				
			||||||
 | 
						var any bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(releasesToBeSynced) > 0 {
 | 
				
			||||||
 | 
							synced, syncErrs := withDAG(st, helm, a.Logger, false, a.Wrap(func(subst *state.HelmState, helm helmexec.Interface) []error {
 | 
				
			||||||
 | 
								var rs []state.ReleaseSpec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for _, r := range subst.Releases {
 | 
				
			||||||
 | 
									if _, ok := releasesToBeSynced[state.ReleaseToID(&r)]; ok {
 | 
				
			||||||
 | 
										rs = append(rs, r)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								subst.Releases = rs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								opts := &state.SyncOpts{
 | 
				
			||||||
 | 
									Set: c.Set(),
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return subst.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency(), opts)
 | 
				
			||||||
 | 
							}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							any = any || synced
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if syncErrs != nil && len(syncErrs) > 0 {
 | 
				
			||||||
 | 
								errs = append(errs, syncErrs...)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						affectedReleases.DisplayAffectedReleases(c.Logger())
 | 
				
			||||||
 | 
						return any, errs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {
 | 
				
			||||||
 | 
						st := r.state
 | 
				
			||||||
 | 
						helm := r.helm
 | 
				
			||||||
 | 
						ctx := r.ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !c.SkipDeps() {
 | 
				
			||||||
 | 
							if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
 | 
				
			||||||
 | 
								return false, errs
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
 | 
				
			||||||
 | 
								return false, errs
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if errs := st.PrepareReleases(helm, "template"); errs != nil && len(errs) > 0 {
 | 
				
			||||||
 | 
							return false, errs
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var templatedReleases []state.ReleaseSpec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(st.Selectors) > 0 {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
							templatedReleases, err = st.GetFilteredReleases()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return false, []error{err}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(templatedReleases) == 0 {
 | 
				
			||||||
 | 
								return false, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							templatedReleases = st.Releases
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						releasesToBeTemplated := map[string]state.ReleaseSpec{}
 | 
				
			||||||
 | 
						for _, r := range templatedReleases {
 | 
				
			||||||
 | 
							id := state.ReleaseToID(&r)
 | 
				
			||||||
 | 
							releasesToBeTemplated[id] = r
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						names := make([]string, len(templatedReleases))
 | 
				
			||||||
 | 
						for i, r := range templatedReleases {
 | 
				
			||||||
 | 
							names[i] = fmt.Sprintf("  %s (%s)", r.Name, r.Chart)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var errs []error
 | 
				
			||||||
 | 
						var any bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(releasesToBeTemplated) > 0 {
 | 
				
			||||||
 | 
							synced, templateErrs := withDAG(st, helm, a.Logger, false, a.Wrap(func(subst *state.HelmState, helm helmexec.Interface) []error {
 | 
				
			||||||
 | 
								var rs []state.ReleaseSpec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for _, r := range subst.Releases {
 | 
				
			||||||
 | 
									if _, ok := releasesToBeTemplated[state.ReleaseToID(&r)]; ok {
 | 
				
			||||||
 | 
										rs = append(rs, r)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								subst.Releases = rs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								args := argparser.GetArgs(c.Args(), st)
 | 
				
			||||||
 | 
								opts := &state.TemplateOpts{
 | 
				
			||||||
 | 
									Set: c.Set(),
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return subst.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), opts)
 | 
				
			||||||
 | 
							}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							any = any || synced
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if templateErrs != nil && len(templateErrs) > 0 {
 | 
				
			||||||
 | 
								errs = append(errs, templateErrs...)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return any, errs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func fileExistsAt(path string) bool {
 | 
					func fileExistsAt(path string) bool {
 | 
				
			||||||
	fileInfo, err := os.Stat(path)
 | 
						fileInfo, err := os.Stat(path)
 | 
				
			||||||
	return err == nil && fileInfo.Mode().IsRegular()
 | 
						return err == nil && fileInfo.Mode().IsRegular()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,58 +89,6 @@ func (r *Run) Diff(c DiffConfigProvider) []error {
 | 
				
			||||||
	return errs
 | 
						return errs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *Run) Sync(c SyncConfigProvider) []error {
 | 
					 | 
				
			||||||
	st := r.state
 | 
					 | 
				
			||||||
	helm := r.helm
 | 
					 | 
				
			||||||
	ctx := r.ctx
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	affectedReleases := state.AffectedReleases{}
 | 
					 | 
				
			||||||
	if !c.SkipDeps() {
 | 
					 | 
				
			||||||
		if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
 | 
					 | 
				
			||||||
			return errs
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
 | 
					 | 
				
			||||||
			return errs
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if errs := st.PrepareReleases(helm, "sync"); errs != nil && len(errs) > 0 {
 | 
					 | 
				
			||||||
		return errs
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	opts := &state.SyncOpts{
 | 
					 | 
				
			||||||
		Set: c.Set(),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	errs := st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency(), opts)
 | 
					 | 
				
			||||||
	affectedReleases.DisplayAffectedReleases(c.Logger())
 | 
					 | 
				
			||||||
	return errs
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (r *Run) Template(c TemplateConfigProvider) []error {
 | 
					 | 
				
			||||||
	st := r.state
 | 
					 | 
				
			||||||
	helm := r.helm
 | 
					 | 
				
			||||||
	ctx := r.ctx
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !c.SkipDeps() {
 | 
					 | 
				
			||||||
		if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
 | 
					 | 
				
			||||||
			return errs
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
 | 
					 | 
				
			||||||
			return errs
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if errs := st.PrepareReleases(helm, "template"); errs != nil && len(errs) > 0 {
 | 
					 | 
				
			||||||
		return errs
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	args := argparser.GetArgs(c.Args(), st)
 | 
					 | 
				
			||||||
	opts := &state.TemplateOpts{
 | 
					 | 
				
			||||||
		Set: c.Set(),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return st.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), opts)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (r *Run) Test(c TestConfigProvider) []error {
 | 
					func (r *Run) Test(c TestConfigProvider) []error {
 | 
				
			||||||
	cleanup := c.Cleanup()
 | 
						cleanup := c.Cleanup()
 | 
				
			||||||
	timeout := c.Timeout()
 | 
						timeout := c.Timeout()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue