Do fail on a possible typo in `needs` entries (#2026)
* Do fail on a possible typo in `needs` entries Helmfile kindly fails with a friendly error when you made a typo in a `needs` entry, i.e. a `needs` entry included a reference to a release that is not defined in the helmfile config. Example Output: ``` in ./helmfile.needs.yaml: release(s) "app" depend(s) on an undefined release "infrastructure/cert-manager2". Perhaps you made a typo in `needs` or forgot defining a release named "cert-manager2" with appropriate `namespace` and `kubeContext`? ``` This prevents issues like #1959 * Fix regression in helmfile-diff (This may break when you had two or more duplicated releases that are intended to be de-duplicated before DAG calculation using selectors * Fix regression when you used selector to deduplicate releases before DAG calculation * Comments * Fix regressions in helmfile-apply and helmfile-sync * Fix regression in duplicate release detection
This commit is contained in:
parent
3d7b4287b3
commit
9efb7afb47
2
go.mod
2
go.mod
|
|
@ -29,7 +29,7 @@ require (
|
|||
github.com/tatsushid/go-prettytable v0.0.0-20141013043238-ed2d14c29939
|
||||
github.com/urfave/cli v1.22.5
|
||||
github.com/variantdev/chartify v0.9.1
|
||||
github.com/variantdev/dag v1.0.0
|
||||
github.com/variantdev/dag v1.1.0
|
||||
github.com/variantdev/vals v0.14.0
|
||||
go.uber.org/multierr v1.6.0
|
||||
go.uber.org/zap v1.16.0
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -602,6 +602,8 @@ github.com/variantdev/chartify v0.9.1 h1:Mkq2BvtHr42BYf2a14YWkfeSoY/+d1wL2xfap4q
|
|||
github.com/variantdev/chartify v0.9.1/go.mod h1:qF4XzQlkfH/6k2jAi1hLas+lK4zSCa8kY+r5JdmLA68=
|
||||
github.com/variantdev/dag v1.0.0 h1:7SFjATxHtrYV20P3tx53yNDBMegz6RT4jv8JPHqAHdM=
|
||||
github.com/variantdev/dag v1.0.0/go.mod h1:pH1TQsNSLj2uxMo9NNl9zdGy01Wtn+/2MT96BrKmVyE=
|
||||
github.com/variantdev/dag v1.1.0 h1:xodYlSng33KWGvIGMpKUyLcIZRXKiNUx612mZJqYrDg=
|
||||
github.com/variantdev/dag v1.1.0/go.mod h1:pH1TQsNSLj2uxMo9NNl9zdGy01Wtn+/2MT96BrKmVyE=
|
||||
github.com/variantdev/vals v0.14.0 h1:J+zX1DDLTQ35A198HChVkCwLfA/4OeKhSuZ5zjmgV0Q=
|
||||
github.com/variantdev/vals v0.14.0/go.mod h1:zoPna6p+fM7pC2Lo17dl5sRpamAV2a0j2VDslkMLW0M=
|
||||
github.com/vektra/mockery v1.1.2/go.mod h1:VcfZjKaFOPO+MpN4ZvwPjs4c48lkq1o3Ym8yHZJu0jU=
|
||||
|
|
|
|||
108
pkg/app/app.go
108
pkg/app/app.go
|
|
@ -1149,29 +1149,61 @@ func (a *App) getSelectedReleases(r *Run, includeTransitiveNeeds bool) ([]state.
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
selectedIds := map[string]struct{}{}
|
||||
selectedIds := map[string]state.ReleaseSpec{}
|
||||
selectedCounts := map[string]int{}
|
||||
for _, r := range selected {
|
||||
selectedIds[state.ReleaseToID(&r)] = struct{}{}
|
||||
r := r
|
||||
id := state.ReleaseToID(&r)
|
||||
selectedIds[id] = r
|
||||
selectedCounts[id]++
|
||||
|
||||
if dupCount := selectedCounts[id]; dupCount > 1 {
|
||||
return nil, nil, fmt.Errorf("found %d duplicate releases with ID %q", dupCount, id)
|
||||
}
|
||||
}
|
||||
|
||||
allReleases := r.state.GetReleasesWithOverrides()
|
||||
|
||||
needed := map[string]struct{}{}
|
||||
for _, r := range selected {
|
||||
collectNeeds(r, selectedIds, needed, allReleases, includeTransitiveNeeds)
|
||||
}
|
||||
|
||||
var releases []state.ReleaseSpec
|
||||
|
||||
releases = append(releases, selected...)
|
||||
|
||||
groupsByID := map[string][]*state.ReleaseSpec{}
|
||||
for _, r := range allReleases {
|
||||
if _, ok := needed[state.ReleaseToID(&r)]; ok {
|
||||
releases = append(releases, r)
|
||||
}
|
||||
r := r
|
||||
groupsByID[state.ReleaseToID(&r)] = append(groupsByID[state.ReleaseToID(&r)], &r)
|
||||
}
|
||||
|
||||
if err := checkDuplicates(r.helm, r.state, releases); err != nil {
|
||||
var deduplicated []state.ReleaseSpec
|
||||
|
||||
dedupedBefore := map[string]struct{}{}
|
||||
|
||||
// We iterate over allReleases rather than groupsByID
|
||||
// to preserve the order of releases
|
||||
for _, seq := range allReleases {
|
||||
id := state.ReleaseToID(&seq)
|
||||
|
||||
rs := groupsByID[id]
|
||||
|
||||
if len(rs) == 1 {
|
||||
deduplicated = append(deduplicated, *rs[0])
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := dedupedBefore[id]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// We keep the selected one only when there were two or more duplicate
|
||||
// releases in the helmfile config.
|
||||
// Otherwise we can't compute the DAG of releases correctly.
|
||||
r, deduped := selectedIds[id]
|
||||
if !deduped {
|
||||
panic(fmt.Errorf("assertion error: release %q has never been selected. This shouldn't happen!", id))
|
||||
}
|
||||
|
||||
deduplicated = append(deduplicated, r)
|
||||
|
||||
dedupedBefore[id] = struct{}{}
|
||||
}
|
||||
|
||||
if err := checkDuplicates(r.helm, r.state, deduplicated); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
|
|
@ -1183,42 +1215,7 @@ func (a *App) getSelectedReleases(r *Run, includeTransitiveNeeds bool) ([]state.
|
|||
|
||||
a.Logger.Debugf("%d release(s)%s found in %s\n", len(selected), extra, r.state.FilePath)
|
||||
|
||||
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 {
|
||||
if _, ok := needed[id]; !ok {
|
||||
needed[id] = struct{}{}
|
||||
if includeTransitiveNeeds {
|
||||
releaseParts := strings.Split(id, "/")
|
||||
releasePartsCount := len(releaseParts)
|
||||
releaseName := releaseParts[releasePartsCount-1]
|
||||
releaseNamespace := ""
|
||||
releaseKubeContext := ""
|
||||
if releasePartsCount > 1 {
|
||||
releaseNamespace = releaseParts[releasePartsCount-2]
|
||||
}
|
||||
if releasePartsCount > 2 {
|
||||
releaseKubeContext = releaseParts[releasePartsCount-3]
|
||||
}
|
||||
for _, r := range allReleases {
|
||||
if len(releaseNamespace) > 0 && r.Namespace != releaseNamespace {
|
||||
continue
|
||||
}
|
||||
if len(releaseKubeContext) > 0 && r.KubeContext != releaseKubeContext {
|
||||
continue
|
||||
}
|
||||
if r.Name == releaseName {
|
||||
collectNeeds(r, selectedIds, needed, allReleases, includeTransitiveNeeds)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return selected, deduplicated, nil
|
||||
}
|
||||
|
||||
func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, bool, []error) {
|
||||
|
|
@ -1323,6 +1320,9 @@ Do you really want to apply?
|
|||
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
|
||||
// Traverse DAG of all the releases so that we don't suffer from false-positive missing dependencies
|
||||
st.Releases = selectedAndNeededReleases
|
||||
|
||||
if !interactive || interactive && r.askForConfirmation(confMsg) {
|
||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
|
|
@ -1458,7 +1458,7 @@ Do you really want to delete?
|
|||
func (a *App) diff(r *Run, c DiffConfigProvider) (*string, bool, bool, []error) {
|
||||
st := r.state
|
||||
|
||||
selectedReleases, selectedAndNeededReleases, err := a.getSelectedReleases(r, false)
|
||||
selectedReleases, deduplicatedReleases, err := a.getSelectedReleases(r, false)
|
||||
if err != nil {
|
||||
return nil, false, false, []error{err}
|
||||
}
|
||||
|
|
@ -1477,7 +1477,7 @@ func (a *App) diff(r *Run, c DiffConfigProvider) (*string, bool, bool, []error)
|
|||
SkipDiffOnInstall: c.SkipDiffOnInstall(),
|
||||
}
|
||||
|
||||
st.Releases = selectedAndNeededReleases
|
||||
st.Releases = deduplicatedReleases
|
||||
|
||||
plan, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, SkipNeeds: c.SkipNeeds(), IncludeNeeds: c.IncludeNeeds(), IncludeTransitiveNeeds: false})
|
||||
if err != nil {
|
||||
|
|
@ -1731,7 +1731,7 @@ func (a *App) sync(r *Run, c SyncConfigProvider) (bool, []error) {
|
|||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
// Traverse DAG of all the releases so that we don't suffer from false-positive missing dependencies
|
||||
st.Releases = toSyncWithNeeds
|
||||
st.Releases = selectedAndNeededReleases
|
||||
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
|
||||
|
|
|
|||
|
|
@ -4213,6 +4213,69 @@ merged environment: &{default map[] map[]}
|
|||
//
|
||||
// error cases
|
||||
//
|
||||
{
|
||||
name: "unselected release in needs",
|
||||
loc: location(),
|
||||
selectors: []string{"name=foo"},
|
||||
files: map[string]string{
|
||||
"/path/to/helmfile.yaml": `
|
||||
releases:
|
||||
- name: bar
|
||||
namespace: ns1
|
||||
chart: mychart3
|
||||
- name: foo
|
||||
chart: mychart1
|
||||
needs:
|
||||
- ns1/bar
|
||||
`,
|
||||
},
|
||||
diffs: map[exectest.DiffKey]error{
|
||||
exectest.DiffKey{Name: "baz", Chart: "mychart3", Flags: "--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||
},
|
||||
lists: map[exectest.ListKey]string{},
|
||||
upgraded: []exectest.Release{},
|
||||
deleted: []exectest.Release{},
|
||||
concurrency: 1,
|
||||
error: `in ./helmfile.yaml: release "default//foo" depends on "default/ns1/bar" which does not match the selectors. Please add a selector like "--selector name=bar", or indicate whether to skip (--skip-needs) or include (--include-needs) these dependencies`,
|
||||
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: releases:
|
||||
2: - name: bar
|
||||
3: namespace: ns1
|
||||
4: chart: mychart3
|
||||
5: - name: foo
|
||||
6: chart: mychart1
|
||||
7: needs:
|
||||
8: - ns1/bar
|
||||
9:
|
||||
|
||||
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: releases:
|
||||
2: - name: bar
|
||||
3: namespace: ns1
|
||||
4: chart: mychart3
|
||||
5: - name: foo
|
||||
6: chart: mychart1
|
||||
7: needs:
|
||||
8: - ns1/bar
|
||||
9:
|
||||
|
||||
merged environment: &{default map[] map[]}
|
||||
1 release(s) matching name=foo found in helmfile.yaml
|
||||
|
||||
err: release "default//foo" depends on "default/ns1/bar" which does not match the selectors. Please add a selector like "--selector name=bar", or indicate whether to skip (--skip-needs) or include (--include-needs) these dependencies
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "non-existent release in needs",
|
||||
loc: location(),
|
||||
|
|
@ -4225,18 +4288,18 @@ releases:
|
|||
- name: foo
|
||||
chart: mychart1
|
||||
needs:
|
||||
- bar
|
||||
- ns1/bar
|
||||
`,
|
||||
},
|
||||
diffs: map[exectest.DiffKey]error{
|
||||
exectest.DiffKey{Name: "baz", Chart: "mychart3", Flags: "--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||
exectest.DiffKey{Name: "bar", Chart: "mychart3", Flags: "--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||
},
|
||||
lists: map[exectest.ListKey]string{},
|
||||
upgraded: []exectest.Release{},
|
||||
deleted: []exectest.Release{},
|
||||
concurrency: 1,
|
||||
error: `in ./helmfile.yaml: release "default//foo" depends on "default//bar" which does not match the selectors. Please add a selector like "--selector name=bar", or indicate whether to skip (--skip-needs) or include (--include-needs) these dependencies`,
|
||||
error: "in ./helmfile.yaml: release(s) \"default//foo\" depend(s) on an undefined release \"default/ns1/bar\". Perhaps you made a typo in \"needs\" or forgot defining a release named \"bar\" with appropriate \"namespace\" and \"kubeContext\"?",
|
||||
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[]}
|
||||
|
|
@ -4249,7 +4312,7 @@ first-pass rendering output of "helmfile.yaml.part.0":
|
|||
5: - name: foo
|
||||
6: chart: mychart1
|
||||
7: needs:
|
||||
8: - bar
|
||||
8: - ns1/bar
|
||||
9:
|
||||
|
||||
first-pass produced: &{default map[] map[]}
|
||||
|
|
@ -4266,13 +4329,85 @@ second-pass rendering result of "helmfile.yaml.part.0":
|
|||
5: - name: foo
|
||||
6: chart: mychart1
|
||||
7: needs:
|
||||
8: - bar
|
||||
8: - ns1/bar
|
||||
9:
|
||||
|
||||
merged environment: &{default map[] map[]}
|
||||
2 release(s) found in helmfile.yaml
|
||||
|
||||
err: release "default//foo" depends on "default//bar" which does not match the selectors. Please add a selector like "--selector name=bar", or indicate whether to skip (--skip-needs) or include (--include-needs) these dependencies
|
||||
err: release(s) "default//foo" depend(s) on an undefined release "default/ns1/bar". Perhaps you made a typo in "needs" or forgot defining a release named "bar" with appropriate "namespace" and "kubeContext"?
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "duplicate releases",
|
||||
loc: location(),
|
||||
files: map[string]string{
|
||||
"/path/to/helmfile.yaml": `
|
||||
releases:
|
||||
- name: bar
|
||||
namespace: ns1
|
||||
chart: mychart3
|
||||
- name: foo
|
||||
chart: mychart2
|
||||
needs:
|
||||
- ns1/bar
|
||||
- name: foo
|
||||
chart: mychart1
|
||||
needs:
|
||||
- ns1/bar
|
||||
`,
|
||||
},
|
||||
diffs: map[exectest.DiffKey]error{
|
||||
exectest.DiffKey{Name: "bar", Chart: "mychart3", Flags: "--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||
},
|
||||
lists: map[exectest.ListKey]string{},
|
||||
upgraded: []exectest.Release{},
|
||||
deleted: []exectest.Release{},
|
||||
concurrency: 1,
|
||||
error: "in ./helmfile.yaml: found 2 duplicate releases with ID \"default//foo\"",
|
||||
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: releases:
|
||||
2: - name: bar
|
||||
3: namespace: ns1
|
||||
4: chart: mychart3
|
||||
5: - name: foo
|
||||
6: chart: mychart2
|
||||
7: needs:
|
||||
8: - ns1/bar
|
||||
9: - name: foo
|
||||
10: chart: mychart1
|
||||
11: needs:
|
||||
12: - ns1/bar
|
||||
13:
|
||||
|
||||
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: releases:
|
||||
2: - name: bar
|
||||
3: namespace: ns1
|
||||
4: chart: mychart3
|
||||
5: - name: foo
|
||||
6: chart: mychart2
|
||||
7: needs:
|
||||
8: - ns1/bar
|
||||
9: - name: foo
|
||||
10: chart: mychart1
|
||||
11: needs:
|
||||
12: - ns1/bar
|
||||
13:
|
||||
|
||||
merged environment: &{default map[] map[]}
|
||||
err: found 2 duplicate releases with ID "default//foo"
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1227,7 +1227,7 @@ releases:
|
|||
upgraded: []exectest.Release{},
|
||||
deleted: []exectest.Release{},
|
||||
concurrency: 1,
|
||||
error: `in ./helmfile.yaml: release "foo" depends on "bar" which does not match the selectors. Please add a selector like "--selector name=bar", or indicate whether to skip (--skip-needs) or include (--include-needs) these dependencies`,
|
||||
error: `in ./helmfile.yaml: release(s) "foo" depend(s) on an undefined release "bar". Perhaps you made a typo in "needs" or forgot defining a release named "bar" with appropriate "namespace" and "kubeContext"?`,
|
||||
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[]}
|
||||
|
|
@ -1263,7 +1263,7 @@ second-pass rendering result of "helmfile.yaml.part.0":
|
|||
merged environment: &{default map[] map[]}
|
||||
2 release(s) found in helmfile.yaml
|
||||
|
||||
err: release "foo" depends on "bar" which does not match the selectors. Please add a selector like "--selector name=bar", or indicate whether to skip (--skip-needs) or include (--include-needs) these dependencies
|
||||
err: release(s) "foo" depend(s) on an undefined release "bar". Perhaps you made a typo in "needs" or forgot defining a release named "bar" with appropriate "namespace" and "kubeContext"?
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1313,6 +1313,68 @@ merged environment: &{default map[] map[]}
|
|||
//
|
||||
// error cases
|
||||
//
|
||||
{
|
||||
name: "unselected release in needs",
|
||||
loc: location(),
|
||||
flags: flags{skipNeeds: false},
|
||||
files: map[string]string{
|
||||
"/path/to/helmfile.yaml": `
|
||||
releases:
|
||||
- name: bar
|
||||
chart: mychart3
|
||||
- name: foo
|
||||
chart: mychart1
|
||||
needs:
|
||||
- bar
|
||||
`,
|
||||
},
|
||||
detailedExitcode: true,
|
||||
selectors: []string{"name=foo"},
|
||||
diffs: map[exectest.DiffKey]error{
|
||||
exectest.DiffKey{Name: "bar", Chart: "mychart3", Flags: "--kube-contextdefault--namespacens1--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||
exectest.DiffKey{Name: "foo", Chart: "mychart1", Flags: "--kube-contextdefault--detailed-exitcode"}: helmexec.ExitError{Code: 2},
|
||||
},
|
||||
lists: map[exectest.ListKey]string{},
|
||||
upgraded: []exectest.Release{},
|
||||
deleted: []exectest.Release{},
|
||||
concurrency: 1,
|
||||
error: `in ./helmfile.yaml: release "default//foo" depends on "default//bar" which does not match the selectors. Please add a selector like "--selector name=bar", or indicate whether to skip (--skip-needs) or include (--include-needs) these dependencies`,
|
||||
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: releases:
|
||||
2: - name: bar
|
||||
3: chart: mychart3
|
||||
4: - name: foo
|
||||
5: chart: mychart1
|
||||
6: needs:
|
||||
7: - bar
|
||||
8:
|
||||
|
||||
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: releases:
|
||||
2: - name: bar
|
||||
3: chart: mychart3
|
||||
4: - name: foo
|
||||
5: chart: mychart1
|
||||
6: needs:
|
||||
7: - bar
|
||||
8:
|
||||
|
||||
merged environment: &{default map[] map[]}
|
||||
1 release(s) matching name=foo found in helmfile.yaml
|
||||
|
||||
err: release "default//foo" depends on "default//bar" which does not match the selectors. Please add a selector like "--selector name=bar", or indicate whether to skip (--skip-needs) or include (--include-needs) these dependencies
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "non-existent release in needs",
|
||||
loc: location(),
|
||||
|
|
@ -1337,7 +1399,7 @@ releases:
|
|||
upgraded: []exectest.Release{},
|
||||
deleted: []exectest.Release{},
|
||||
concurrency: 1,
|
||||
error: `in ./helmfile.yaml: release "default//foo" depends on "default//bar" which does not match the selectors. Please add a selector like "--selector name=bar", or indicate whether to skip (--skip-needs) or include (--include-needs) these dependencies`,
|
||||
error: `in ./helmfile.yaml: release(s) "default//foo" depend(s) on an undefined release "default//bar". Perhaps you made a typo in "needs" or forgot defining a release named "bar" with appropriate "namespace" and "kubeContext"?`,
|
||||
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[]}
|
||||
|
|
@ -1373,7 +1435,7 @@ second-pass rendering result of "helmfile.yaml.part.0":
|
|||
merged environment: &{default map[] map[]}
|
||||
2 release(s) found in helmfile.yaml
|
||||
|
||||
err: release "default//foo" depends on "default//bar" which does not match the selectors. Please add a selector like "--selector name=bar", or indicate whether to skip (--skip-needs) or include (--include-needs) these dependencies
|
||||
err: release(s) "default//foo" depend(s) on an undefined release "default//bar". Perhaps you made a typo in "needs" or forgot defining a release named "bar" with appropriate "namespace" and "kubeContext"?
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1888,8 +1888,11 @@ func (st *HelmState) DiffReleases(helm helmexec.Interface, additionalValues []st
|
|||
)
|
||||
|
||||
for _, p := range preps {
|
||||
if stdout, ok := outputs[ReleaseToID(p.release)]; ok {
|
||||
id := ReleaseToID(p.release)
|
||||
if stdout, ok := outputs[id]; ok {
|
||||
fmt.Print(stdout.String())
|
||||
} else {
|
||||
panic(fmt.Sprintf("missing output for release %s", id))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,15 +150,12 @@ func GroupReleasesByDependency(releases []Release, opts PlanOptions) ([][]Releas
|
|||
idToReleases[id] = append(idToReleases[id], r)
|
||||
idToIndex[id] = i
|
||||
|
||||
// Only compute dependencies from non-filtered releases
|
||||
if !r.Filtered {
|
||||
var needs []string
|
||||
for i := 0; i < len(r.Needs); i++ {
|
||||
n := r.Needs[i]
|
||||
needs = append(needs, n)
|
||||
}
|
||||
d.Add(id, dag.Dependencies(needs))
|
||||
var needs []string
|
||||
for i := 0; i < len(r.Needs); i++ {
|
||||
n := r.Needs[i]
|
||||
needs = append(needs, n)
|
||||
}
|
||||
d.Add(id, dag.Dependencies(needs))
|
||||
}
|
||||
|
||||
var ids []string
|
||||
|
|
@ -218,6 +215,22 @@ func GroupReleasesByDependency(releases []Release, opts PlanOptions) ([][]Releas
|
|||
msgs[i] = msg
|
||||
}
|
||||
return nil, errors.New(msgs[0])
|
||||
} else if ude, ok := err.(*dag.UndefinedDependencyError); ok {
|
||||
var quotedReleaseNames []string
|
||||
for _, d := range ude.Dependents {
|
||||
quotedReleaseNames = append(quotedReleaseNames, fmt.Sprintf("%q", d))
|
||||
}
|
||||
|
||||
idComponents := strings.Split(ude.UndefinedNode, "/")
|
||||
name := idComponents[len(idComponents)-1]
|
||||
humanReadableUndefinedReleaseInfo := fmt.Sprintf(`named %q with appropriate "namespace" and "kubeContext"`, name)
|
||||
|
||||
return nil, fmt.Errorf(
|
||||
`release(s) %s depend(s) on an undefined release %q. Perhaps you made a typo in "needs" or forgot defining a release %s?`,
|
||||
strings.Join(quotedReleaseNames, ", "),
|
||||
ude.UndefinedNode,
|
||||
humanReadableUndefinedReleaseInfo,
|
||||
)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue