Add support for transitive dependencies. (#1983)
Co-authored-by: Peter Aichinger <petera@topdesk.com>
This commit is contained in:
parent
9a0ce53608
commit
77e6268bcb
24
main.go
24
main.go
|
|
@ -201,7 +201,7 @@ func main() {
|
||||||
},
|
},
|
||||||
cli.BoolTFlag{
|
cli.BoolTFlag{
|
||||||
Name: "skip-needs",
|
Name: "skip-needs",
|
||||||
Usage: `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided. Defaults to true when --include-needs is not provided`,
|
Usage: `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided. Defaults to true when --include-needs or --include-transitive-needs is not provided`,
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "include-needs",
|
Name: "include-needs",
|
||||||
|
|
@ -286,6 +286,10 @@ func main() {
|
||||||
Name: "include-needs",
|
Name: "include-needs",
|
||||||
Usage: `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided`,
|
Usage: `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided`,
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "include-transitive-needs",
|
||||||
|
Usage: `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`,
|
||||||
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "skip-deps",
|
Name: "skip-deps",
|
||||||
Usage: `skip running "helm repo update" and "helm dependency build"`,
|
Usage: `skip running "helm repo update" and "helm dependency build"`,
|
||||||
|
|
@ -414,12 +418,16 @@ func main() {
|
||||||
},
|
},
|
||||||
cli.BoolTFlag{
|
cli.BoolTFlag{
|
||||||
Name: "skip-needs",
|
Name: "skip-needs",
|
||||||
Usage: `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided. Defaults to true when --include-needs is not provided`,
|
Usage: `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided. Defaults to true when --include-needs or --include-transitive-needs is not provided`,
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "include-needs",
|
Name: "include-needs",
|
||||||
Usage: `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided`,
|
Usage: `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided`,
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "include-transitive-needs",
|
||||||
|
Usage: `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`,
|
||||||
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "wait",
|
Name: "wait",
|
||||||
Usage: `Override helmDefaults.wait setting "helm upgrade --install --wait"`,
|
Usage: `Override helmDefaults.wait setting "helm upgrade --install --wait"`,
|
||||||
|
|
@ -487,12 +495,16 @@ func main() {
|
||||||
},
|
},
|
||||||
cli.BoolTFlag{
|
cli.BoolTFlag{
|
||||||
Name: "skip-needs",
|
Name: "skip-needs",
|
||||||
Usage: `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided. Defaults to true when --include-needs is not provided`,
|
Usage: `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided. Defaults to true when --include-needs or --include-transitive-needs is not provided`,
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "include-needs",
|
Name: "include-needs",
|
||||||
Usage: `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided`,
|
Usage: `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when when --selector/-l flag is not provided`,
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "include-transitive-needs",
|
||||||
|
Usage: `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`,
|
||||||
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "skip-diff-on-install",
|
Name: "skip-diff-on-install",
|
||||||
Usage: "Skips running helm-diff on releases being newly installed on this apply. Useful when the release manifests are too huge to be reviewed, or it's too time-consuming to diff at all",
|
Usage: "Skips running helm-diff on releases being newly installed on this apply. Useful when the release manifests are too huge to be reviewed, or it's too time-consuming to diff at all",
|
||||||
|
|
@ -782,7 +794,11 @@ func (c configImpl) SkipNeeds() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c configImpl) IncludeNeeds() bool {
|
func (c configImpl) IncludeNeeds() bool {
|
||||||
return c.c.Bool("include-needs")
|
return c.c.Bool("include-needs") || c.IncludeTransitiveNeeds()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c configImpl) IncludeTransitiveNeeds() bool {
|
||||||
|
return c.c.Bool("include-transitive-needs")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiffConfig
|
// DiffConfig
|
||||||
|
|
|
||||||
126
pkg/app/app.go
126
pkg/app/app.go
|
|
@ -120,7 +120,7 @@ func (a *App) Deps(c DepsConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetFilter(true))
|
}, c.IncludeTransitiveNeeds(), SetFilter(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Repos(c ReposConfigProvider) error {
|
func (a *App) Repos(c ReposConfigProvider) error {
|
||||||
|
|
@ -132,7 +132,7 @@ func (a *App) Repos(c ReposConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetFilter(true))
|
}, c.IncludeTransitiveNeeds(), SetFilter(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) DeprecatedSyncCharts(c DeprecatedChartsConfigProvider) error {
|
func (a *App) DeprecatedSyncCharts(c DeprecatedChartsConfigProvider) error {
|
||||||
|
|
@ -149,7 +149,7 @@ func (a *App) DeprecatedSyncCharts(c DeprecatedChartsConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetFilter(true))
|
}, c.IncludeTransitiveNeeds(), SetFilter(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Diff(c DiffConfigProvider) error {
|
func (a *App) Diff(c DiffConfigProvider) error {
|
||||||
|
|
@ -203,7 +203,7 @@ func (a *App) Diff(c DiffConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return matched, criticalErrs
|
return matched, criticalErrs
|
||||||
})
|
}, false)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -225,9 +225,6 @@ func (a *App) Diff(c DiffConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Template(c TemplateConfigProvider) error {
|
func (a *App) Template(c TemplateConfigProvider) error {
|
||||||
|
|
||||||
opts := []LoadOption{SetRetainValuesFiles(c.SkipCleanup())}
|
|
||||||
|
|
||||||
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||||
includeCRDs := c.IncludeCRDs()
|
includeCRDs := c.IncludeCRDs()
|
||||||
|
|
||||||
|
|
@ -249,7 +246,7 @@ func (a *App) Template(c TemplateConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, opts...)
|
}, c.IncludeTransitiveNeeds())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) WriteValues(c WriteValuesConfigProvider) error {
|
func (a *App) WriteValues(c WriteValuesConfigProvider) error {
|
||||||
|
|
@ -269,7 +266,7 @@ func (a *App) WriteValues(c WriteValuesConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetFilter(true))
|
}, c.IncludeTransitiveNeeds(), SetFilter(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
type MultiError struct {
|
type MultiError struct {
|
||||||
|
|
@ -322,7 +319,7 @@ func (a *App) Lint(c LintConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetFilter(true))
|
}, false, SetFilter(true))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -350,7 +347,7 @@ func (a *App) Fetch(c FetchConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetFilter(true))
|
}, false, SetFilter(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Sync(c SyncConfigProvider) error {
|
func (a *App) Sync(c SyncConfigProvider) error {
|
||||||
|
|
@ -358,11 +355,12 @@ func (a *App) Sync(c SyncConfigProvider) error {
|
||||||
includeCRDs := !c.SkipCRDs()
|
includeCRDs := !c.SkipCRDs()
|
||||||
|
|
||||||
prepErr := run.withPreparedCharts("sync", state.ChartPrepareOptions{
|
prepErr := run.withPreparedCharts("sync", state.ChartPrepareOptions{
|
||||||
SkipRepos: c.SkipDeps(),
|
SkipRepos: c.SkipDeps(),
|
||||||
SkipDeps: c.SkipDeps(),
|
SkipDeps: c.SkipDeps(),
|
||||||
Wait: c.Wait(),
|
Wait: c.Wait(),
|
||||||
WaitForJobs: c.WaitForJobs(),
|
WaitForJobs: c.WaitForJobs(),
|
||||||
IncludeCRDs: &includeCRDs,
|
IncludeCRDs: &includeCRDs,
|
||||||
|
IncludeTransitiveNeeds: c.IncludeTransitiveNeeds(),
|
||||||
}, func() {
|
}, func() {
|
||||||
ok, errs = a.sync(run, c)
|
ok, errs = a.sync(run, c)
|
||||||
})
|
})
|
||||||
|
|
@ -372,7 +370,7 @@ func (a *App) Sync(c SyncConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
})
|
}, c.IncludeTransitiveNeeds())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Apply(c ApplyConfigProvider) error {
|
func (a *App) Apply(c ApplyConfigProvider) error {
|
||||||
|
|
@ -410,7 +408,7 @@ func (a *App) Apply(c ApplyConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, opts...)
|
}, c.IncludeTransitiveNeeds(), opts...)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -439,7 +437,7 @@ func (a *App) Status(c StatusesConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetFilter(true))
|
}, false, SetFilter(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Delete(c DeleteConfigProvider) error {
|
func (a *App) Delete(c DeleteConfigProvider) error {
|
||||||
|
|
@ -456,7 +454,7 @@ func (a *App) Delete(c DeleteConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetReverse(true))
|
}, false, SetReverse(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Destroy(c DestroyConfigProvider) error {
|
func (a *App) Destroy(c DestroyConfigProvider) error {
|
||||||
|
|
@ -473,7 +471,7 @@ func (a *App) Destroy(c DestroyConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetReverse(true))
|
}, false, SetReverse(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Test(c TestConfigProvider) error {
|
func (a *App) Test(c TestConfigProvider) error {
|
||||||
|
|
@ -496,7 +494,7 @@ func (a *App) Test(c TestConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetFilter(true))
|
}, false, SetFilter(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) PrintState(c StateConfigProvider) error {
|
func (a *App) PrintState(c StateConfigProvider) error {
|
||||||
|
|
@ -543,7 +541,7 @@ func (a *App) PrintState(c StateConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetFilter(true))
|
}, false, SetFilter(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) ListReleases(c ListConfigProvider) error {
|
func (a *App) ListReleases(c ListConfigProvider) error {
|
||||||
|
|
@ -594,7 +592,7 @@ func (a *App) ListReleases(c ListConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}, SetFilter(true))
|
}, false, SetFilter(true))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -883,14 +881,14 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *App) ForEachState(do func(*Run) (bool, []error), o ...LoadOption) error {
|
func (a *App) ForEachState(do func(*Run) (bool, []error), includeTransitiveNeeds bool, o ...LoadOption) error {
|
||||||
ctx := NewContext()
|
ctx := NewContext()
|
||||||
err := a.visitStatesWithSelectorsAndRemoteSupport(a.FileOrDir, func(st *state.HelmState) (bool, []error) {
|
err := a.visitStatesWithSelectorsAndRemoteSupport(a.FileOrDir, func(st *state.HelmState) (bool, []error) {
|
||||||
helm := a.getHelm(st)
|
helm := a.getHelm(st)
|
||||||
|
|
||||||
run := NewRun(st, helm, ctx)
|
run := NewRun(st, helm, ctx)
|
||||||
return do(run)
|
return do(run)
|
||||||
}, o...)
|
}, includeTransitiveNeeds, o...)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -966,7 +964,7 @@ type Opts struct {
|
||||||
DAGEnabled bool
|
DAGEnabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) visitStatesWithSelectorsAndRemoteSupport(fileOrDir string, converge func(*state.HelmState) (bool, []error), opt ...LoadOption) error {
|
func (a *App) visitStatesWithSelectorsAndRemoteSupport(fileOrDir string, converge func(*state.HelmState) (bool, []error), includeTransitiveNeeds bool, opt ...LoadOption) error {
|
||||||
opts := LoadOpts{
|
opts := LoadOpts{
|
||||||
Selectors: a.Selectors,
|
Selectors: a.Selectors,
|
||||||
}
|
}
|
||||||
|
|
@ -1004,16 +1002,17 @@ func (a *App) visitStatesWithSelectorsAndRemoteSupport(fileOrDir string, converg
|
||||||
return processFilteredReleases(st, a.getHelm(st), func(st *state.HelmState) []error {
|
return processFilteredReleases(st, a.getHelm(st), func(st *state.HelmState) []error {
|
||||||
_, err := converge(st)
|
_, err := converge(st)
|
||||||
return err
|
return err
|
||||||
})
|
},
|
||||||
|
includeTransitiveNeeds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.visitStates(fileOrDir, opts, f)
|
return a.visitStates(fileOrDir, opts, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func processFilteredReleases(st *state.HelmState, helm helmexec.Interface, converge func(st *state.HelmState) []error) (bool, []error) {
|
func processFilteredReleases(st *state.HelmState, helm helmexec.Interface, converge func(st *state.HelmState) []error, includeTransitiveNeeds bool) (bool, []error) {
|
||||||
if len(st.Selectors) > 0 {
|
if len(st.Selectors) > 0 {
|
||||||
err := st.FilterReleases()
|
err := st.FilterReleases(includeTransitiveNeeds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, []error{err}
|
return false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1066,11 +1065,11 @@ func checkDuplicates(helm helmexec.Interface, st *state.HelmState, releases []st
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Wrap(converge func(*state.HelmState, helmexec.Interface) []error) func(st *state.HelmState, helm helmexec.Interface) (bool, []error) {
|
func (a *App) Wrap(converge func(*state.HelmState, helmexec.Interface) []error) func(st *state.HelmState, helm helmexec.Interface, includeTransitiveNeeds bool) (bool, []error) {
|
||||||
return func(st *state.HelmState, helm helmexec.Interface) (bool, []error) {
|
return func(st *state.HelmState, helm helmexec.Interface, includeTransitiveNeeds bool) (bool, []error) {
|
||||||
return processFilteredReleases(st, helm, func(st *state.HelmState) []error {
|
return processFilteredReleases(st, helm, func(st *state.HelmState) []error {
|
||||||
return converge(st, helm)
|
return converge(st, helm)
|
||||||
})
|
}, includeTransitiveNeeds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1144,8 +1143,8 @@ func (a *App) findDesiredStateFiles(specifiedPath string, opts LoadOpts) ([]stri
|
||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) getSelectedReleases(r *Run) ([]state.ReleaseSpec, []state.ReleaseSpec, error) {
|
func (a *App) getSelectedReleases(r *Run, includeTransitiveNeeds bool) ([]state.ReleaseSpec, []state.ReleaseSpec, error) {
|
||||||
selected, err := r.state.GetSelectedReleasesWithOverrides()
|
selected, err := r.state.GetSelectedReleasesWithOverrides(includeTransitiveNeeds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1159,12 +1158,7 @@ func (a *App) getSelectedReleases(r *Run) ([]state.ReleaseSpec, []state.ReleaseS
|
||||||
|
|
||||||
needed := map[string]struct{}{}
|
needed := map[string]struct{}{}
|
||||||
for _, r := range selected {
|
for _, r := range selected {
|
||||||
for _, id := range r.Needs {
|
collectNeeds(r, selectedIds, needed, allReleases, includeTransitiveNeeds)
|
||||||
// Avoids duplicating a release that is selected AND also needed by another selected release
|
|
||||||
if _, ok := selectedIds[id]; !ok {
|
|
||||||
needed[id] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var releases []state.ReleaseSpec
|
var releases []state.ReleaseSpec
|
||||||
|
|
@ -1192,11 +1186,29 @@ func (a *App) getSelectedReleases(r *Run) ([]state.ReleaseSpec, []state.ReleaseS
|
||||||
return selected, releases, nil
|
return selected, releases, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func collectNeeds(release state.ReleaseSpec, selectedIds map[string]struct{}, needed map[string]struct{}, allReleases []state.ReleaseSpec, includeTransitiveNeeds bool) {
|
||||||
|
for _, id := range release.Needs {
|
||||||
|
// Avoids duplicating a release that is selected AND also needed by another selected release
|
||||||
|
if _, ok := selectedIds[id]; !ok {
|
||||||
|
needed[id] = struct{}{}
|
||||||
|
if includeTransitiveNeeds {
|
||||||
|
releaseParts := strings.Split(id, "/")
|
||||||
|
releaseName := releaseParts[len(releaseParts)-1]
|
||||||
|
for _, r := range allReleases {
|
||||||
|
if r.Name == releaseName {
|
||||||
|
collectNeeds(r, selectedIds, needed, allReleases, includeTransitiveNeeds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, bool, []error) {
|
func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, bool, []error) {
|
||||||
st := r.state
|
st := r.state
|
||||||
helm := r.helm
|
helm := r.helm
|
||||||
|
|
||||||
selectedReleases, selectedAndNeededReleases, err := a.getSelectedReleases(r)
|
selectedReleases, selectedAndNeededReleases, err := a.getSelectedReleases(r, c.IncludeTransitiveNeeds())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, []error{err}
|
return false, false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1210,7 +1222,7 @@ func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, bool, []error) {
|
||||||
// See https://github.com/roboll/helmfile/issues/1818 for more context.
|
// See https://github.com/roboll/helmfile/issues/1818 for more context.
|
||||||
st.Releases = selectedAndNeededReleases
|
st.Releases = selectedAndNeededReleases
|
||||||
|
|
||||||
plan, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, SkipNeeds: c.SkipNeeds(), IncludeNeeds: c.IncludeNeeds()})
|
plan, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, SkipNeeds: c.SkipNeeds(), IncludeNeeds: c.IncludeNeeds(), IncludeTransitiveNeeds: c.IncludeTransitiveNeeds()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, []error{err}
|
return false, false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1320,7 +1332,7 @@ Do you really want to apply?
|
||||||
|
|
||||||
// We upgrade releases by traversing the DAG
|
// We upgrade releases by traversing the DAG
|
||||||
if len(releasesToBeUpdated) > 0 {
|
if len(releasesToBeUpdated) > 0 {
|
||||||
_, updateErrs := withDAG(st, helm, a.Logger, state.PlanOptions{SelectedReleases: toUpdate, Reverse: false, SkipNeeds: true}, a.WrapWithoutSelector(func(subst *state.HelmState, helm helmexec.Interface) []error {
|
_, updateErrs := withDAG(st, helm, a.Logger, state.PlanOptions{SelectedReleases: toUpdate, Reverse: false, SkipNeeds: true, IncludeTransitiveNeeds: c.IncludeTransitiveNeeds()}, a.WrapWithoutSelector(func(subst *state.HelmState, helm helmexec.Interface) []error {
|
||||||
var rs []state.ReleaseSpec
|
var rs []state.ReleaseSpec
|
||||||
|
|
||||||
for _, r := range subst.Releases {
|
for _, r := range subst.Releases {
|
||||||
|
|
@ -1357,7 +1369,7 @@ func (a *App) delete(r *Run, purge bool, c DestroyConfigProvider) (bool, []error
|
||||||
|
|
||||||
affectedReleases := state.AffectedReleases{}
|
affectedReleases := state.AffectedReleases{}
|
||||||
|
|
||||||
toSync, _, err := a.getSelectedReleases(r)
|
toSync, _, err := a.getSelectedReleases(r, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, []error{err}
|
return false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1429,7 +1441,7 @@ Do you really want to delete?
|
||||||
func (a *App) diff(r *Run, c DiffConfigProvider) (*string, bool, bool, []error) {
|
func (a *App) diff(r *Run, c DiffConfigProvider) (*string, bool, bool, []error) {
|
||||||
st := r.state
|
st := r.state
|
||||||
|
|
||||||
selectedReleases, selectedAndNeededReleases, err := a.getSelectedReleases(r)
|
selectedReleases, selectedAndNeededReleases, err := a.getSelectedReleases(r, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, false, []error{err}
|
return nil, false, false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1450,7 +1462,7 @@ func (a *App) diff(r *Run, c DiffConfigProvider) (*string, bool, bool, []error)
|
||||||
|
|
||||||
st.Releases = selectedAndNeededReleases
|
st.Releases = selectedAndNeededReleases
|
||||||
|
|
||||||
plan, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, SkipNeeds: c.SkipNeeds(), IncludeNeeds: c.IncludeNeeds()})
|
plan, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, SkipNeeds: c.SkipNeeds(), IncludeNeeds: c.IncludeNeeds(), IncludeTransitiveNeeds: false})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, false, []error{err}
|
return nil, false, false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1485,7 +1497,7 @@ func (a *App) lint(r *Run, c LintConfigProvider) (bool, []error, []error) {
|
||||||
|
|
||||||
allReleases := st.GetReleasesWithOverrides()
|
allReleases := st.GetReleasesWithOverrides()
|
||||||
|
|
||||||
selectedReleases, _, err := a.getSelectedReleases(r)
|
selectedReleases, _, err := a.getSelectedReleases(r, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, []error{err}
|
return false, nil, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1553,7 +1565,7 @@ func (a *App) status(r *Run, c StatusesConfigProvider) (bool, []error) {
|
||||||
|
|
||||||
allReleases := st.GetReleasesWithOverrides()
|
allReleases := st.GetReleasesWithOverrides()
|
||||||
|
|
||||||
selectedReleases, selectedAndNeededReleases, err := a.getSelectedReleases(r)
|
selectedReleases, selectedAndNeededReleases, err := a.getSelectedReleases(r, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, []error{err}
|
return false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1603,7 +1615,7 @@ func (a *App) sync(r *Run, c SyncConfigProvider) (bool, []error) {
|
||||||
st := r.state
|
st := r.state
|
||||||
helm := r.helm
|
helm := r.helm
|
||||||
|
|
||||||
selectedReleases, selectedAndNeededReleases, err := a.getSelectedReleases(r)
|
selectedReleases, selectedAndNeededReleases, err := a.getSelectedReleases(r, c.IncludeTransitiveNeeds())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, []error{err}
|
return false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1617,7 +1629,7 @@ func (a *App) sync(r *Run, c SyncConfigProvider) (bool, []error) {
|
||||||
// See https://github.com/roboll/helmfile/issues/1818 for more context.
|
// See https://github.com/roboll/helmfile/issues/1818 for more context.
|
||||||
st.Releases = selectedAndNeededReleases
|
st.Releases = selectedAndNeededReleases
|
||||||
|
|
||||||
batches, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, IncludeNeeds: c.IncludeNeeds(), SkipNeeds: c.SkipNeeds()})
|
batches, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, IncludeNeeds: c.IncludeNeeds(), IncludeTransitiveNeeds: c.IncludeTransitiveNeeds(), SkipNeeds: c.SkipNeeds()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, []error{err}
|
return false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1727,7 +1739,7 @@ func (a *App) sync(r *Run, c SyncConfigProvider) (bool, []error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(releasesToUpdate) > 0 {
|
if len(releasesToUpdate) > 0 {
|
||||||
_, syncErrs := withDAG(st, helm, a.Logger, state.PlanOptions{SelectedReleases: toUpdate, SkipNeeds: true}, a.WrapWithoutSelector(func(subst *state.HelmState, helm helmexec.Interface) []error {
|
_, syncErrs := withDAG(st, helm, a.Logger, state.PlanOptions{SelectedReleases: toUpdate, SkipNeeds: true, IncludeTransitiveNeeds: c.IncludeTransitiveNeeds()}, a.WrapWithoutSelector(func(subst *state.HelmState, helm helmexec.Interface) []error {
|
||||||
var rs []state.ReleaseSpec
|
var rs []state.ReleaseSpec
|
||||||
|
|
||||||
for _, r := range subst.Releases {
|
for _, r := range subst.Releases {
|
||||||
|
|
@ -1759,7 +1771,7 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {
|
||||||
st := r.state
|
st := r.state
|
||||||
helm := r.helm
|
helm := r.helm
|
||||||
|
|
||||||
selectedReleases, selectedAndNeededReleases, err := a.getSelectedReleases(r)
|
selectedReleases, selectedAndNeededReleases, err := a.getSelectedReleases(r, c.IncludeTransitiveNeeds())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, []error{err}
|
return false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1773,7 +1785,7 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {
|
||||||
// See https://github.com/roboll/helmfile/issues/1818 for more context.
|
// See https://github.com/roboll/helmfile/issues/1818 for more context.
|
||||||
st.Releases = selectedAndNeededReleases
|
st.Releases = selectedAndNeededReleases
|
||||||
|
|
||||||
batches, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, IncludeNeeds: c.IncludeNeeds(), SkipNeeds: !c.IncludeNeeds()})
|
batches, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, IncludeNeeds: c.IncludeNeeds(), IncludeTransitiveNeeds: c.IncludeTransitiveNeeds(), SkipNeeds: !c.IncludeNeeds()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, []error{err}
|
return false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1813,7 +1825,7 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(toRender) > 0 {
|
if len(toRender) > 0 {
|
||||||
_, templateErrs := withDAG(st, helm, a.Logger, state.PlanOptions{SelectedReleases: toRender, Reverse: false, SkipNeeds: true}, a.WrapWithoutSelector(func(subst *state.HelmState, helm helmexec.Interface) []error {
|
_, templateErrs := withDAG(st, helm, a.Logger, state.PlanOptions{SelectedReleases: toRender, Reverse: false, SkipNeeds: true, IncludeTransitiveNeeds: c.IncludeTransitiveNeeds()}, a.WrapWithoutSelector(func(subst *state.HelmState, helm helmexec.Interface) []error {
|
||||||
opts := &state.TemplateOpts{
|
opts := &state.TemplateOpts{
|
||||||
Set: c.Set(),
|
Set: c.Set(),
|
||||||
IncludeCRDs: c.IncludeCRDs(),
|
IncludeCRDs: c.IncludeCRDs(),
|
||||||
|
|
@ -1837,7 +1849,7 @@ func (a *App) test(r *Run, c TestConfigProvider) []error {
|
||||||
|
|
||||||
st := r.state
|
st := r.state
|
||||||
|
|
||||||
toTest, _, err := a.getSelectedReleases(r)
|
toTest, _, err := a.getSelectedReleases(r, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []error{err}
|
return []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -1859,7 +1871,7 @@ func (a *App) writeValues(r *Run, c WriteValuesConfigProvider) (bool, []error) {
|
||||||
st := r.state
|
st := r.state
|
||||||
helm := r.helm
|
helm := r.helm
|
||||||
|
|
||||||
toRender, _, err := a.getSelectedReleases(r)
|
toRender, _, err := a.getSelectedReleases(r, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, []error{err}
|
return false, []error{err}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,9 @@ import (
|
||||||
|
|
||||||
func TestApply_3(t *testing.T) {
|
func TestApply_3(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
skipNeeds bool
|
skipNeeds bool
|
||||||
includeNeeds bool
|
includeNeeds bool
|
||||||
|
includeTransitiveNeeds bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
|
|
@ -109,11 +110,12 @@ func TestApply_3(t *testing.T) {
|
||||||
|
|
||||||
syncErr := app.Apply(applyConfig{
|
syncErr := app.Apply(applyConfig{
|
||||||
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
|
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
|
||||||
concurrency: tc.concurrency,
|
concurrency: tc.concurrency,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
skipDiffOnInstall: tc.skipDiffOnInstall,
|
skipDiffOnInstall: tc.skipDiffOnInstall,
|
||||||
skipNeeds: tc.fields.skipNeeds,
|
skipNeeds: tc.fields.skipNeeds,
|
||||||
includeNeeds: tc.fields.includeNeeds,
|
includeNeeds: tc.fields.includeNeeds,
|
||||||
|
includeTransitiveNeeds: tc.fields.includeTransitiveNeeds,
|
||||||
})
|
})
|
||||||
|
|
||||||
var gotErr string
|
var gotErr string
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,9 @@ import (
|
||||||
|
|
||||||
func TestApply_2(t *testing.T) {
|
func TestApply_2(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
skipNeeds bool
|
skipNeeds bool
|
||||||
includeNeeds bool
|
includeNeeds bool
|
||||||
|
includeTransitiveNeeds bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
|
|
@ -109,11 +110,12 @@ func TestApply_2(t *testing.T) {
|
||||||
|
|
||||||
syncErr := app.Apply(applyConfig{
|
syncErr := app.Apply(applyConfig{
|
||||||
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
|
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
|
||||||
concurrency: tc.concurrency,
|
concurrency: tc.concurrency,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
skipDiffOnInstall: tc.skipDiffOnInstall,
|
skipDiffOnInstall: tc.skipDiffOnInstall,
|
||||||
skipNeeds: tc.fields.skipNeeds,
|
skipNeeds: tc.fields.skipNeeds,
|
||||||
includeNeeds: tc.fields.includeNeeds,
|
includeNeeds: tc.fields.includeNeeds,
|
||||||
|
includeTransitiveNeeds: tc.fields.includeTransitiveNeeds,
|
||||||
})
|
})
|
||||||
|
|
||||||
var gotErr string
|
var gotErr string
|
||||||
|
|
@ -960,6 +962,128 @@ NAME CHART VERSION
|
||||||
external-secrets incubator/raw
|
external-secrets incubator/raw
|
||||||
my-release incubator/raw
|
my-release incubator/raw
|
||||||
|
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("include-transitive-needs=true", func(t *testing.T) {
|
||||||
|
check(t, testcase{
|
||||||
|
fields: fields{
|
||||||
|
skipNeeds: false,
|
||||||
|
includeNeeds: true,
|
||||||
|
includeTransitiveNeeds: true,
|
||||||
|
},
|
||||||
|
error: ``,
|
||||||
|
files: map[string]string{
|
||||||
|
"/path/to/helmfile.yaml": `
|
||||||
|
{{ $mark := "a" }}
|
||||||
|
|
||||||
|
releases:
|
||||||
|
- name: serviceA
|
||||||
|
chart: my/chart
|
||||||
|
needs:
|
||||||
|
- serviceB
|
||||||
|
|
||||||
|
- name: serviceB
|
||||||
|
chart: my/chart
|
||||||
|
needs:
|
||||||
|
- serviceC
|
||||||
|
|
||||||
|
- name: serviceC
|
||||||
|
chart: my/chart
|
||||||
|
|
||||||
|
- name: serviceD
|
||||||
|
chart: my/chart
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
selectors: []string{"name=serviceA"},
|
||||||
|
upgraded: []exectest.Release{},
|
||||||
|
diffs: map[exectest.DiffKey]error{
|
||||||
|
exectest.DiffKey{Name: "serviceA", Chart: "my/chart", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||||
|
exectest.DiffKey{Name: "serviceB", Chart: "my/chart", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||||
|
exectest.DiffKey{Name: "serviceC", Chart: "my/chart", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||||
|
},
|
||||||
|
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
|
||||||
|
concurrency: 1,
|
||||||
|
log: `processing file "helmfile.yaml" in directory "."
|
||||||
|
first-pass rendering starting for "helmfile.yaml.part.0": inherited=&{default map[] map[]}, overrode=<nil>
|
||||||
|
first-pass uses: &{default map[] map[]}
|
||||||
|
first-pass rendering output of "helmfile.yaml.part.0":
|
||||||
|
0:
|
||||||
|
1:
|
||||||
|
2:
|
||||||
|
3: releases:
|
||||||
|
4: - name: serviceA
|
||||||
|
5: chart: my/chart
|
||||||
|
6: needs:
|
||||||
|
7: - serviceB
|
||||||
|
8:
|
||||||
|
9: - name: serviceB
|
||||||
|
10: chart: my/chart
|
||||||
|
11: needs:
|
||||||
|
12: - serviceC
|
||||||
|
13:
|
||||||
|
14: - name: serviceC
|
||||||
|
15: chart: my/chart
|
||||||
|
16:
|
||||||
|
17: - name: serviceD
|
||||||
|
18: chart: my/chart
|
||||||
|
19:
|
||||||
|
|
||||||
|
first-pass produced: &{default map[] map[]}
|
||||||
|
first-pass rendering result of "helmfile.yaml.part.0": {default map[] map[]}
|
||||||
|
vals:
|
||||||
|
map[]
|
||||||
|
defaultVals:[]
|
||||||
|
second-pass rendering result of "helmfile.yaml.part.0":
|
||||||
|
0:
|
||||||
|
1:
|
||||||
|
2:
|
||||||
|
3: releases:
|
||||||
|
4: - name: serviceA
|
||||||
|
5: chart: my/chart
|
||||||
|
6: needs:
|
||||||
|
7: - serviceB
|
||||||
|
8:
|
||||||
|
9: - name: serviceB
|
||||||
|
10: chart: my/chart
|
||||||
|
11: needs:
|
||||||
|
12: - serviceC
|
||||||
|
13:
|
||||||
|
14: - name: serviceC
|
||||||
|
15: chart: my/chart
|
||||||
|
16:
|
||||||
|
17: - name: serviceD
|
||||||
|
18: chart: my/chart
|
||||||
|
19:
|
||||||
|
|
||||||
|
merged environment: &{default map[] map[]}
|
||||||
|
3 release(s) matching name=serviceA found in helmfile.yaml
|
||||||
|
|
||||||
|
Affected releases are:
|
||||||
|
serviceA (my/chart) UPDATED
|
||||||
|
serviceB (my/chart) UPDATED
|
||||||
|
serviceC (my/chart) UPDATED
|
||||||
|
|
||||||
|
processing 3 groups of releases in this order:
|
||||||
|
GROUP RELEASES
|
||||||
|
1 default//serviceC
|
||||||
|
2 default//serviceB
|
||||||
|
3 default//serviceA
|
||||||
|
|
||||||
|
processing releases in group 1/3: default//serviceC
|
||||||
|
getting deployed release version failed:unexpected list key: {^serviceC$ --kube-contextdefault--deleting--deployed--failed--pending}
|
||||||
|
processing releases in group 2/3: default//serviceB
|
||||||
|
getting deployed release version failed:unexpected list key: {^serviceB$ --kube-contextdefault--deleting--deployed--failed--pending}
|
||||||
|
processing releases in group 3/3: default//serviceA
|
||||||
|
getting deployed release version failed:unexpected list key: {^serviceA$ --kube-contextdefault--deleting--deployed--failed--pending}
|
||||||
|
|
||||||
|
UPDATED RELEASES:
|
||||||
|
NAME CHART VERSION
|
||||||
|
serviceC my/chart
|
||||||
|
serviceB my/chart
|
||||||
|
serviceA my/chart
|
||||||
|
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,9 @@ import (
|
||||||
|
|
||||||
func TestSync(t *testing.T) {
|
func TestSync(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
skipNeeds bool
|
skipNeeds bool
|
||||||
includeNeeds bool
|
includeNeeds bool
|
||||||
|
includeTransitiveNeeds bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
|
|
@ -107,11 +108,12 @@ func TestSync(t *testing.T) {
|
||||||
|
|
||||||
syncErr := app.Sync(applyConfig{
|
syncErr := app.Sync(applyConfig{
|
||||||
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
|
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
|
||||||
concurrency: tc.concurrency,
|
concurrency: tc.concurrency,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
skipDiffOnInstall: tc.skipDiffOnInstall,
|
skipDiffOnInstall: tc.skipDiffOnInstall,
|
||||||
skipNeeds: tc.fields.skipNeeds,
|
skipNeeds: tc.fields.skipNeeds,
|
||||||
includeNeeds: tc.fields.includeNeeds,
|
includeNeeds: tc.fields.includeNeeds,
|
||||||
|
includeTransitiveNeeds: tc.fields.includeTransitiveNeeds,
|
||||||
})
|
})
|
||||||
|
|
||||||
var gotErr string
|
var gotErr string
|
||||||
|
|
@ -412,6 +414,122 @@ kubernetes-external-secrets incubator/raw
|
||||||
external-secrets incubator/raw
|
external-secrets incubator/raw
|
||||||
my-release incubator/raw
|
my-release incubator/raw
|
||||||
|
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("include-transitive-needs=true", func(t *testing.T) {
|
||||||
|
check(t, testcase{
|
||||||
|
fields: fields{
|
||||||
|
skipNeeds: false,
|
||||||
|
includeTransitiveNeeds: true,
|
||||||
|
},
|
||||||
|
error: ``,
|
||||||
|
files: map[string]string{
|
||||||
|
"/path/to/helmfile.yaml": `
|
||||||
|
{{ $mark := "a" }}
|
||||||
|
|
||||||
|
releases:
|
||||||
|
- name: serviceA
|
||||||
|
chart: my/chart
|
||||||
|
needs:
|
||||||
|
- serviceB
|
||||||
|
|
||||||
|
- name: serviceB
|
||||||
|
chart: my/chart
|
||||||
|
needs:
|
||||||
|
- serviceC
|
||||||
|
|
||||||
|
- name: serviceC
|
||||||
|
chart: my/chart
|
||||||
|
|
||||||
|
- name: serviceD
|
||||||
|
chart: my/chart
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
selectors: []string{"name=serviceA"},
|
||||||
|
upgraded: []exectest.Release{},
|
||||||
|
// as we check for log output, set concurrency to 1 to avoid non-deterministic test result
|
||||||
|
concurrency: 1,
|
||||||
|
log: `processing file "helmfile.yaml" in directory "."
|
||||||
|
first-pass rendering starting for "helmfile.yaml.part.0": inherited=&{default map[] map[]}, overrode=<nil>
|
||||||
|
first-pass uses: &{default map[] map[]}
|
||||||
|
first-pass rendering output of "helmfile.yaml.part.0":
|
||||||
|
0:
|
||||||
|
1:
|
||||||
|
2:
|
||||||
|
3: releases:
|
||||||
|
4: - name: serviceA
|
||||||
|
5: chart: my/chart
|
||||||
|
6: needs:
|
||||||
|
7: - serviceB
|
||||||
|
8:
|
||||||
|
9: - name: serviceB
|
||||||
|
10: chart: my/chart
|
||||||
|
11: needs:
|
||||||
|
12: - serviceC
|
||||||
|
13:
|
||||||
|
14: - name: serviceC
|
||||||
|
15: chart: my/chart
|
||||||
|
16:
|
||||||
|
17: - name: serviceD
|
||||||
|
18: chart: my/chart
|
||||||
|
19:
|
||||||
|
|
||||||
|
first-pass produced: &{default map[] map[]}
|
||||||
|
first-pass rendering result of "helmfile.yaml.part.0": {default map[] map[]}
|
||||||
|
vals:
|
||||||
|
map[]
|
||||||
|
defaultVals:[]
|
||||||
|
second-pass rendering result of "helmfile.yaml.part.0":
|
||||||
|
0:
|
||||||
|
1:
|
||||||
|
2:
|
||||||
|
3: releases:
|
||||||
|
4: - name: serviceA
|
||||||
|
5: chart: my/chart
|
||||||
|
6: needs:
|
||||||
|
7: - serviceB
|
||||||
|
8:
|
||||||
|
9: - name: serviceB
|
||||||
|
10: chart: my/chart
|
||||||
|
11: needs:
|
||||||
|
12: - serviceC
|
||||||
|
13:
|
||||||
|
14: - name: serviceC
|
||||||
|
15: chart: my/chart
|
||||||
|
16:
|
||||||
|
17: - name: serviceD
|
||||||
|
18: chart: my/chart
|
||||||
|
19:
|
||||||
|
|
||||||
|
merged environment: &{default map[] map[]}
|
||||||
|
3 release(s) matching name=serviceA found in helmfile.yaml
|
||||||
|
|
||||||
|
Affected releases are:
|
||||||
|
serviceA (my/chart) UPDATED
|
||||||
|
serviceB (my/chart) UPDATED
|
||||||
|
serviceC (my/chart) UPDATED
|
||||||
|
|
||||||
|
processing 3 groups of releases in this order:
|
||||||
|
GROUP RELEASES
|
||||||
|
1 default//serviceC
|
||||||
|
2 default//serviceB
|
||||||
|
3 default//serviceA
|
||||||
|
|
||||||
|
processing releases in group 1/3: default//serviceC
|
||||||
|
getting deployed release version failed:unexpected list key: {^serviceC$ --kube-contextdefault--deleting--deployed--failed--pending}
|
||||||
|
processing releases in group 2/3: default//serviceB
|
||||||
|
getting deployed release version failed:unexpected list key: {^serviceB$ --kube-contextdefault--deleting--deployed--failed--pending}
|
||||||
|
processing releases in group 3/3: default//serviceA
|
||||||
|
getting deployed release version failed:unexpected list key: {^serviceA$ --kube-contextdefault--deleting--deployed--failed--pending}
|
||||||
|
|
||||||
|
UPDATED RELEASES:
|
||||||
|
NAME CHART VERSION
|
||||||
|
serviceC my/chart
|
||||||
|
serviceB my/chart
|
||||||
|
serviceA my/chart
|
||||||
|
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -419,8 +537,9 @@ my-release incubator/raw
|
||||||
t.Run("skip-needs=false include-needs=true with installed but disabled release", func(t *testing.T) {
|
t.Run("skip-needs=false include-needs=true with installed but disabled release", func(t *testing.T) {
|
||||||
check(t, testcase{
|
check(t, testcase{
|
||||||
fields: fields{
|
fields: fields{
|
||||||
skipNeeds: false,
|
skipNeeds: false,
|
||||||
includeNeeds: true,
|
includeNeeds: true,
|
||||||
|
includeTransitiveNeeds: false,
|
||||||
},
|
},
|
||||||
error: ``,
|
error: ``,
|
||||||
files: map[string]string{
|
files: map[string]string{
|
||||||
|
|
@ -561,8 +680,9 @@ kubernetes-external-secrets
|
||||||
t.Run("skip-needs=false include-needs=true with not installed and disabled release", func(t *testing.T) {
|
t.Run("skip-needs=false include-needs=true with not installed and disabled release", func(t *testing.T) {
|
||||||
check(t, testcase{
|
check(t, testcase{
|
||||||
fields: fields{
|
fields: fields{
|
||||||
skipNeeds: false,
|
skipNeeds: false,
|
||||||
includeNeeds: true,
|
includeTransitiveNeeds: false,
|
||||||
|
includeNeeds: true,
|
||||||
},
|
},
|
||||||
error: ``,
|
error: ``,
|
||||||
files: map[string]string{
|
files: map[string]string{
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
noop,
|
noop,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -157,6 +158,7 @@ BAZ: 4
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
Noop,
|
Noop,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -198,6 +200,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
Noop,
|
Noop,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
@ -242,6 +245,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
Noop,
|
Noop,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -293,6 +297,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
Noop,
|
Noop,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if testcase.expectErr && err == nil {
|
if testcase.expectErr && err == nil {
|
||||||
|
|
@ -359,6 +364,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
Noop,
|
Noop,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if testcase.expectErr && err == nil {
|
if testcase.expectErr && err == nil {
|
||||||
|
|
@ -413,6 +419,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
Noop,
|
Noop,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if testcase.expectErr && err == nil {
|
if testcase.expectErr && err == nil {
|
||||||
|
|
@ -531,6 +538,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if testcase.expectErr {
|
if testcase.expectErr {
|
||||||
|
|
@ -774,6 +782,7 @@ func runFilterSubHelmFilesTests(testcases []struct {
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if testcase.expectErr {
|
if testcase.expectErr {
|
||||||
|
|
@ -869,6 +878,7 @@ tillerNs: INLINE_TILLER_NS_2
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -970,6 +980,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetReverse(testcase.reverse),
|
SetReverse(testcase.reverse),
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
|
|
@ -1035,6 +1046,7 @@ bar: "bar1"
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1157,6 +1169,7 @@ x:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1209,6 +1222,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1266,6 +1280,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1316,6 +1331,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1364,6 +1380,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1407,6 +1424,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1450,6 +1468,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1497,6 +1516,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -2246,8 +2266,9 @@ type configImpl struct {
|
||||||
skipCRDs bool
|
skipCRDs bool
|
||||||
skipDeps bool
|
skipDeps bool
|
||||||
|
|
||||||
skipNeeds bool
|
skipNeeds bool
|
||||||
includeNeeds bool
|
includeNeeds bool
|
||||||
|
includeTransitiveNeeds bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a configImpl) Selectors() []string {
|
func (a configImpl) Selectors() []string {
|
||||||
|
|
@ -2290,6 +2311,10 @@ func (c configImpl) IncludeNeeds() bool {
|
||||||
return c.includeNeeds
|
return c.includeNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c configImpl) IncludeTransitiveNeeds() bool {
|
||||||
|
return c.includeTransitiveNeeds
|
||||||
|
}
|
||||||
|
|
||||||
func (c configImpl) OutputDir() string {
|
func (c configImpl) OutputDir() string {
|
||||||
return "output/subdir"
|
return "output/subdir"
|
||||||
}
|
}
|
||||||
|
|
@ -2315,30 +2340,31 @@ func (c configImpl) Output() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
type applyConfig struct {
|
type applyConfig struct {
|
||||||
args string
|
args string
|
||||||
values []string
|
values []string
|
||||||
retainValuesFiles bool
|
retainValuesFiles bool
|
||||||
set []string
|
set []string
|
||||||
validate bool
|
validate bool
|
||||||
skipCleanup bool
|
skipCleanup bool
|
||||||
skipCRDs bool
|
skipCRDs bool
|
||||||
skipDeps bool
|
skipDeps bool
|
||||||
skipNeeds bool
|
skipNeeds bool
|
||||||
includeNeeds bool
|
includeNeeds bool
|
||||||
includeTests bool
|
includeTransitiveNeeds bool
|
||||||
suppressSecrets bool
|
includeTests bool
|
||||||
showSecrets bool
|
suppressSecrets bool
|
||||||
suppressDiff bool
|
showSecrets bool
|
||||||
noColor bool
|
suppressDiff bool
|
||||||
context int
|
noColor bool
|
||||||
diffOutput string
|
context int
|
||||||
concurrency int
|
diffOutput string
|
||||||
detailedExitcode bool
|
concurrency int
|
||||||
interactive bool
|
detailedExitcode bool
|
||||||
skipDiffOnInstall bool
|
interactive bool
|
||||||
logger *zap.SugaredLogger
|
skipDiffOnInstall bool
|
||||||
wait bool
|
logger *zap.SugaredLogger
|
||||||
waitForJobs bool
|
wait bool
|
||||||
|
waitForJobs bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Args() string {
|
func (a applyConfig) Args() string {
|
||||||
|
|
@ -2385,6 +2411,10 @@ func (c applyConfig) IncludeNeeds() bool {
|
||||||
return c.includeNeeds
|
return c.includeNeeds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c applyConfig) IncludeTransitiveNeeds() bool {
|
||||||
|
return c.includeTransitiveNeeds
|
||||||
|
}
|
||||||
|
|
||||||
func (a applyConfig) IncludeTests() bool {
|
func (a applyConfig) IncludeTests() bool {
|
||||||
return a.includeTests
|
return a.includeTests
|
||||||
}
|
}
|
||||||
|
|
@ -2438,13 +2468,18 @@ func (a applyConfig) SkipDiffOnInstall() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type depsConfig struct {
|
type depsConfig struct {
|
||||||
skipRepos bool
|
skipRepos bool
|
||||||
|
includeTransitiveNeeds bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d depsConfig) SkipRepos() bool {
|
func (d depsConfig) SkipRepos() bool {
|
||||||
return d.skipRepos
|
return d.skipRepos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d depsConfig) IncludeTransitiveNeeds() bool {
|
||||||
|
return d.includeTransitiveNeeds
|
||||||
|
}
|
||||||
|
|
||||||
func (d depsConfig) Args() string {
|
func (d depsConfig) Args() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
@ -4482,7 +4517,8 @@ See https://github.com/roboll/helmfile/issues/878 for more information.
|
||||||
}, tc.files)
|
}, tc.files)
|
||||||
|
|
||||||
depsErr := app.Deps(depsConfig{
|
depsErr := app.Deps(depsConfig{
|
||||||
skipRepos: false,
|
skipRepos: false,
|
||||||
|
includeTransitiveNeeds: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
if tc.error == "" && depsErr != nil {
|
if tc.error == "" && depsErr != nil {
|
||||||
|
|
@ -4777,6 +4813,7 @@ releases:
|
||||||
|
|
||||||
err := app.ForEachState(
|
err := app.ForEachState(
|
||||||
collectReleases,
|
collectReleases,
|
||||||
|
false,
|
||||||
SetFilter(true),
|
SetFilter(true),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -23,15 +23,18 @@ type DeprecatedChartsConfigProvider interface {
|
||||||
|
|
||||||
concurrencyConfig
|
concurrencyConfig
|
||||||
loggingConfig
|
loggingConfig
|
||||||
|
IncludeTransitiveNeeds() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type DepsConfigProvider interface {
|
type DepsConfigProvider interface {
|
||||||
Args() string
|
Args() string
|
||||||
SkipRepos() bool
|
SkipRepos() bool
|
||||||
|
IncludeTransitiveNeeds() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReposConfigProvider interface {
|
type ReposConfigProvider interface {
|
||||||
Args() string
|
Args() string
|
||||||
|
IncludeTransitiveNeeds() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApplyConfigProvider interface {
|
type ApplyConfigProvider interface {
|
||||||
|
|
@ -63,6 +66,7 @@ type ApplyConfigProvider interface {
|
||||||
|
|
||||||
SkipNeeds() bool
|
SkipNeeds() bool
|
||||||
IncludeNeeds() bool
|
IncludeNeeds() bool
|
||||||
|
IncludeTransitiveNeeds() bool
|
||||||
|
|
||||||
concurrencyConfig
|
concurrencyConfig
|
||||||
interactive
|
interactive
|
||||||
|
|
@ -81,6 +85,7 @@ type SyncConfigProvider interface {
|
||||||
|
|
||||||
SkipNeeds() bool
|
SkipNeeds() bool
|
||||||
IncludeNeeds() bool
|
IncludeNeeds() bool
|
||||||
|
IncludeTransitiveNeeds() bool
|
||||||
|
|
||||||
concurrencyConfig
|
concurrencyConfig
|
||||||
loggingConfig
|
loggingConfig
|
||||||
|
|
@ -174,6 +179,7 @@ type TemplateConfigProvider interface {
|
||||||
OutputDir() string
|
OutputDir() string
|
||||||
IncludeCRDs() bool
|
IncludeCRDs() bool
|
||||||
IncludeNeeds() bool
|
IncludeNeeds() bool
|
||||||
|
IncludeTransitiveNeeds() bool
|
||||||
|
|
||||||
concurrencyConfig
|
concurrencyConfig
|
||||||
}
|
}
|
||||||
|
|
@ -183,6 +189,7 @@ type WriteValuesConfigProvider interface {
|
||||||
Set() []string
|
Set() []string
|
||||||
OutputFileTemplate() string
|
OutputFileTemplate() string
|
||||||
SkipDeps() bool
|
SkipDeps() bool
|
||||||
|
IncludeTransitiveNeeds() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatusesConfigProvider interface {
|
type StatusesConfigProvider interface {
|
||||||
|
|
|
||||||
|
|
@ -103,8 +103,9 @@ func TestDestroy_2(t *testing.T) {
|
||||||
|
|
||||||
destroyErr := app.Destroy(destroyConfig{
|
destroyErr := app.Destroy(destroyConfig{
|
||||||
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
|
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
|
||||||
concurrency: tc.concurrency,
|
concurrency: tc.concurrency,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
includeTransitiveNeeds: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
if tc.error == "" && destroyErr != nil {
|
if tc.error == "" && destroyErr != nil {
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,12 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type destroyConfig struct {
|
type destroyConfig struct {
|
||||||
args string
|
args string
|
||||||
concurrency int
|
concurrency int
|
||||||
interactive bool
|
interactive bool
|
||||||
skipDeps bool
|
skipDeps bool
|
||||||
logger *zap.SugaredLogger
|
logger *zap.SugaredLogger
|
||||||
|
includeTransitiveNeeds bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d destroyConfig) Args() string {
|
func (d destroyConfig) Args() string {
|
||||||
|
|
@ -50,6 +51,10 @@ func (d destroyConfig) SkipDeps() bool {
|
||||||
return d.skipDeps
|
return d.skipDeps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d destroyConfig) IncludeTransitiveNeeds() bool {
|
||||||
|
return d.includeTransitiveNeeds
|
||||||
|
}
|
||||||
|
|
||||||
func TestDestroy(t *testing.T) {
|
func TestDestroy(t *testing.T) {
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
helm3 bool
|
helm3 bool
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ func (r *Run) withPreparedCharts(helmfileCommand string, opts state.ChartPrepare
|
||||||
func (r *Run) Deps(c DepsConfigProvider) []error {
|
func (r *Run) Deps(c DepsConfigProvider) []error {
|
||||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||||
|
|
||||||
return r.state.UpdateDeps(r.helm)
|
return r.state.UpdateDeps(r.helm, c.IncludeTransitiveNeeds())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Run) Repos(c ReposConfigProvider) error {
|
func (r *Run) Repos(c ReposConfigProvider) error {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSelectReleasesWithOverrides(t *testing.T) {
|
func TestSelectReleasesWithOverrides(t *testing.T) {
|
||||||
|
|
@ -79,7 +80,76 @@ func TestSelectReleasesWithOverrides(t *testing.T) {
|
||||||
for _, tc := range testcases {
|
for _, tc := range testcases {
|
||||||
state.Selectors = tc.selector
|
state.Selectors = tc.selector
|
||||||
|
|
||||||
rs, err := state.GetSelectedReleasesWithOverrides()
|
rs, err := state.GetSelectedReleasesWithOverrides(false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s %s: %v", tc.selector, tc.subject, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var got []string
|
||||||
|
|
||||||
|
for _, r := range rs {
|
||||||
|
got = append(got, r.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if d := cmp.Diff(tc.want, got); d != "" {
|
||||||
|
t.Errorf("%s %s: %s", tc.selector, tc.subject, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSelectReleasesWithOverridesWithIncludedTransitives(t *testing.T) {
|
||||||
|
type testcase struct {
|
||||||
|
subject string
|
||||||
|
selector []string
|
||||||
|
want []string
|
||||||
|
includeTransitiveNeeds bool
|
||||||
|
}
|
||||||
|
|
||||||
|
testcases := []testcase{
|
||||||
|
{
|
||||||
|
subject: "include transitives",
|
||||||
|
selector: []string{"name=serviceA"},
|
||||||
|
want: []string{"serviceA"},
|
||||||
|
includeTransitiveNeeds: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
subject: "include transitives",
|
||||||
|
selector: []string{"name=serviceA"},
|
||||||
|
want: []string{"serviceA", "serviceB", "serviceC"},
|
||||||
|
includeTransitiveNeeds: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
example := []byte(`releases:
|
||||||
|
- name: serviceA
|
||||||
|
namespace: default
|
||||||
|
chart: stable/testchart
|
||||||
|
needs:
|
||||||
|
- serviceB
|
||||||
|
- name: serviceB
|
||||||
|
namespace: default
|
||||||
|
chart: stable/testchart
|
||||||
|
needs:
|
||||||
|
- serviceC
|
||||||
|
- name: serviceC
|
||||||
|
namespace: default
|
||||||
|
chart: stable/testchart
|
||||||
|
- name: serviceD
|
||||||
|
namespace: default
|
||||||
|
chart: stable/testchart
|
||||||
|
`)
|
||||||
|
|
||||||
|
state := stateTestEnv{
|
||||||
|
Files: map[string]string{
|
||||||
|
"/helmfile.yaml": string(example),
|
||||||
|
},
|
||||||
|
WorkDir: "/",
|
||||||
|
}.MustLoadState(t, "/helmfile.yaml", "default")
|
||||||
|
|
||||||
|
for _, tc := range testcases {
|
||||||
|
state.Selectors = tc.selector
|
||||||
|
|
||||||
|
rs, err := state.GetSelectedReleasesWithOverrides(tc.includeTransitiveNeeds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s %s: %v", tc.selector, tc.subject, err)
|
t.Fatalf("%s %s: %v", tc.selector, tc.subject, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -398,36 +398,6 @@ type RepoUpdater interface {
|
||||||
RegistryLogin(name string, username string, password string) error
|
RegistryLogin(name string, username string, password string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRepositoriesToSync returns the names of repositories to be updated
|
|
||||||
func (st *HelmState) getRepositoriesToSync() (map[string]bool, error) {
|
|
||||||
releases, err := st.GetSelectedReleasesWithOverrides()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
repositoriesToUpdate := map[string]bool{}
|
|
||||||
|
|
||||||
if len(releases) == 0 {
|
|
||||||
for _, repo := range st.Repositories {
|
|
||||||
repositoriesToUpdate[repo.Name] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return repositoriesToUpdate, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, release := range releases {
|
|
||||||
if release.Installed == nil || *release.Installed {
|
|
||||||
chart := strings.Split(release.Chart, "/")
|
|
||||||
if len(chart) == 1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
repositoriesToUpdate[chart[0]] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return repositoriesToUpdate, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (st *HelmState) SyncRepos(helm RepoUpdater, shouldSkip map[string]bool) ([]string, error) {
|
func (st *HelmState) SyncRepos(helm RepoUpdater, shouldSkip map[string]bool) ([]string, error) {
|
||||||
var updated []string
|
var updated []string
|
||||||
|
|
||||||
|
|
@ -968,11 +938,12 @@ type ChartPrepareOptions struct {
|
||||||
SkipCleanup bool
|
SkipCleanup bool
|
||||||
// Validate is a helm-3-only option. When it is set to true, it configures chartify to pass --validate to helm-template run by it.
|
// Validate is a helm-3-only option. When it is set to true, it configures chartify to pass --validate to helm-template run by it.
|
||||||
// It's required when one of your chart relies on Capabilities.APIVersions in a template
|
// It's required when one of your chart relies on Capabilities.APIVersions in a template
|
||||||
Validate bool
|
Validate bool
|
||||||
IncludeCRDs *bool
|
IncludeCRDs *bool
|
||||||
Wait bool
|
Wait bool
|
||||||
WaitForJobs bool
|
WaitForJobs bool
|
||||||
OutputDir string
|
OutputDir string
|
||||||
|
IncludeTransitiveNeeds bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type chartPrepareResult struct {
|
type chartPrepareResult struct {
|
||||||
|
|
@ -1026,7 +997,7 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
|
||||||
|
|
||||||
// This and releasesNeedCharts ensures that we run operations like helm-dep-build and prepare-hook calls only on
|
// This and releasesNeedCharts ensures that we run operations like helm-dep-build and prepare-hook calls only on
|
||||||
// releases that are (1) selected by the selectors and (2) to be installed.
|
// releases that are (1) selected by the selectors and (2) to be installed.
|
||||||
selected, err = st.GetSelectedReleasesWithOverrides()
|
selected, err = st.GetSelectedReleasesWithOverrides(opts.IncludeTransitiveNeeds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, []error{err}
|
return nil, []error{err}
|
||||||
}
|
}
|
||||||
|
|
@ -2047,16 +2018,16 @@ func (st *HelmState) GetReleasesWithOverrides() []ReleaseSpec {
|
||||||
return rs
|
return rs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *HelmState) SelectReleasesWithOverrides() ([]Release, error) {
|
func (st *HelmState) SelectReleasesWithOverrides(includeTransitiveNeeds bool) ([]Release, error) {
|
||||||
values := st.Values()
|
values := st.Values()
|
||||||
rs, err := markExcludedReleases(st.GetReleasesWithOverrides(), st.Selectors, st.CommonLabels, values)
|
rs, err := markExcludedReleases(st.GetReleasesWithOverrides(), st.Selectors, st.CommonLabels, values, includeTransitiveNeeds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return rs, nil
|
return rs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func markExcludedReleases(releases []ReleaseSpec, selectors []string, commonLabels map[string]string, values map[string]interface{}) ([]Release, error) {
|
func markExcludedReleases(releases []ReleaseSpec, selectors []string, commonLabels map[string]string, values map[string]interface{}, includeTransitiveNeeds bool) ([]Release, error) {
|
||||||
var filteredReleases []Release
|
var filteredReleases []Release
|
||||||
filters := []ReleaseFilter{}
|
filters := []ReleaseFilter{}
|
||||||
for _, label := range selectors {
|
for _, label := range selectors {
|
||||||
|
|
@ -2113,12 +2084,52 @@ func markExcludedReleases(releases []ReleaseSpec, selectors []string, commonLabe
|
||||||
}
|
}
|
||||||
filteredReleases = append(filteredReleases, res)
|
filteredReleases = append(filteredReleases, res)
|
||||||
}
|
}
|
||||||
|
if includeTransitiveNeeds {
|
||||||
|
unmarkNeedsAndTransitives(filteredReleases, releases)
|
||||||
|
}
|
||||||
return filteredReleases, nil
|
return filteredReleases, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *HelmState) GetSelectedReleasesWithOverrides() ([]ReleaseSpec, error) {
|
func unmarkNeedsAndTransitives(filteredReleases []Release, allReleases []ReleaseSpec) {
|
||||||
filteredReleases, err := st.SelectReleasesWithOverrides()
|
needsWithTranstives := collectAllNeedsWithTransitives(filteredReleases, allReleases)
|
||||||
|
unmarkReleases(needsWithTranstives, filteredReleases)
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectAllNeedsWithTransitives(filteredReleases []Release, allReleases []ReleaseSpec) map[string]struct{} {
|
||||||
|
needsWithTranstives := map[string]struct{}{}
|
||||||
|
for _, r := range filteredReleases {
|
||||||
|
if !r.Filtered {
|
||||||
|
collectNeedsWithTransitives(r.ReleaseSpec, allReleases, needsWithTranstives)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return needsWithTranstives
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarkReleases(toUnmark map[string]struct{}, releases []Release) {
|
||||||
|
for i, r := range releases {
|
||||||
|
if _, ok := toUnmark[ReleaseToID(&r.ReleaseSpec)]; ok {
|
||||||
|
releases[i].Filtered = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectNeedsWithTransitives(release ReleaseSpec, allReleases []ReleaseSpec, needsWithTranstives map[string]struct{}) {
|
||||||
|
for _, id := range release.Needs {
|
||||||
|
if _, exists := needsWithTranstives[id]; !exists {
|
||||||
|
needsWithTranstives[id] = struct{}{}
|
||||||
|
releaseParts := strings.Split(id, "/")
|
||||||
|
releaseName := releaseParts[len(releaseParts)-1]
|
||||||
|
for _, r := range allReleases {
|
||||||
|
if r.Name == releaseName {
|
||||||
|
collectNeedsWithTransitives(r, allReleases, needsWithTranstives)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *HelmState) GetSelectedReleasesWithOverrides(includeTransitiveNeeds bool) ([]ReleaseSpec, error) {
|
||||||
|
filteredReleases, err := st.SelectReleasesWithOverrides(includeTransitiveNeeds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -2133,8 +2144,8 @@ func (st *HelmState) GetSelectedReleasesWithOverrides() ([]ReleaseSpec, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterReleases allows for the execution of helm commands against a subset of the releases in the helmfile.
|
// FilterReleases allows for the execution of helm commands against a subset of the releases in the helmfile.
|
||||||
func (st *HelmState) FilterReleases() error {
|
func (st *HelmState) FilterReleases(includeTransitiveNeeds bool) error {
|
||||||
releases, err := st.GetSelectedReleasesWithOverrides()
|
releases, err := st.GetSelectedReleasesWithOverrides(includeTransitiveNeeds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -2209,7 +2220,7 @@ func (st *HelmState) ResolveDeps() (*HelmState, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateDeps wrapper for updating dependencies on the releases
|
// UpdateDeps wrapper for updating dependencies on the releases
|
||||||
func (st *HelmState) UpdateDeps(helm helmexec.Interface) []error {
|
func (st *HelmState) UpdateDeps(helm helmexec.Interface, includeTransitiveNeeds bool) []error {
|
||||||
var selected []ReleaseSpec
|
var selected []ReleaseSpec
|
||||||
|
|
||||||
if len(st.Selectors) > 0 {
|
if len(st.Selectors) > 0 {
|
||||||
|
|
@ -2217,7 +2228,7 @@ func (st *HelmState) UpdateDeps(helm helmexec.Interface) []error {
|
||||||
|
|
||||||
// This and releasesNeedCharts ensures that we run operations like helm-dep-build and prepare-hook calls only on
|
// This and releasesNeedCharts ensures that we run operations like helm-dep-build and prepare-hook calls only on
|
||||||
// releases that are (1) selected by the selectors and (2) to be installed.
|
// releases that are (1) selected by the selectors and (2) to be installed.
|
||||||
selected, err = st.GetSelectedReleasesWithOverrides()
|
selected, err = st.GetSelectedReleasesWithOverrides(includeTransitiveNeeds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []error{err}
|
return []error{err}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,14 +100,15 @@ func (st *HelmState) iterateOnReleases(helm helmexec.Interface, concurrency int,
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlanOptions struct {
|
type PlanOptions struct {
|
||||||
Reverse bool
|
Reverse bool
|
||||||
IncludeNeeds bool
|
IncludeNeeds bool
|
||||||
SkipNeeds bool
|
IncludeTransitiveNeeds bool
|
||||||
SelectedReleases []ReleaseSpec
|
SkipNeeds bool
|
||||||
|
SelectedReleases []ReleaseSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *HelmState) PlanReleases(opts PlanOptions) ([][]Release, error) {
|
func (st *HelmState) PlanReleases(opts PlanOptions) ([][]Release, error) {
|
||||||
marked, err := st.SelectReleasesWithOverrides()
|
marked, err := st.SelectReleasesWithOverrides(opts.IncludeTransitiveNeeds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1848,7 +1848,7 @@ generated: 2019-05-16T15:42:45.50486+09:00
|
||||||
})
|
})
|
||||||
fs.Cwd = basePath
|
fs.Cwd = basePath
|
||||||
state = injectFs(state, fs)
|
state = injectFs(state, fs)
|
||||||
errs := state.UpdateDeps(helm)
|
errs := state.UpdateDeps(helm, false)
|
||||||
|
|
||||||
want := []string{"/example", "./example", generatedDir}
|
want := []string{"/example", "./example", generatedDir}
|
||||||
if !reflect.DeepEqual(helm.Charts, want) {
|
if !reflect.DeepEqual(helm.Charts, want) {
|
||||||
|
|
@ -2141,7 +2141,7 @@ func TestHelmState_NoReleaseMatched(t *testing.T) {
|
||||||
RenderedValues: map[string]interface{}{},
|
RenderedValues: map[string]interface{}{},
|
||||||
}
|
}
|
||||||
state.Selectors = []string{tt.labels}
|
state.Selectors = []string{tt.labels}
|
||||||
errs := state.FilterReleases()
|
errs := state.FilterReleases(false)
|
||||||
if (errs != nil) != tt.wantErr {
|
if (errs != nil) != tt.wantErr {
|
||||||
t.Errorf("ReleaseStatuses() for %s error = %v, wantErr %v", tt.name, errs, tt.wantErr)
|
t.Errorf("ReleaseStatuses() for %s error = %v, wantErr %v", tt.name, errs, tt.wantErr)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue