diff --git a/pkg/config/sync.go b/pkg/config/sync.go index 8d68aba8..5794d581 100644 --- a/pkg/config/sync.go +++ b/pkg/config/sync.go @@ -16,6 +16,8 @@ type SyncOptions struct { IncludeNeeds bool // IncludeTransitiveNeeds is the include transitive needs flag IncludeTransitiveNeeds bool + // EnforceNeedsAreInstalled is true we should error if/when there are unmeetable dependencies + EnforceNeedsAreInstalled bool // SkipCrds is the skip crds flag SkipCRDs bool // Wait is the wait flag @@ -82,6 +84,11 @@ func (t *SyncImpl) IncludeTransitiveNeeds() bool { return t.SyncOptions.IncludeTransitiveNeeds } +// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable +func (t *SyncImpl) EnforceNeedsAreInstalled() bool { + return t.SyncOptions.EnforceNeedsAreInstalled +} + // Set returns the Set func (t *SyncImpl) Set() []string { return t.SyncOptions.Set diff --git a/pkg/config/template.go b/pkg/config/template.go index 90c82691..ae7c2439 100644 --- a/pkg/config/template.go +++ b/pkg/config/template.go @@ -30,6 +30,8 @@ type TemplateOptions struct { IncludeNeeds bool // IncludeTransitiveNeeds is the include transitive needs flag IncludeTransitiveNeeds bool + // EnforceNeedsAreInstalled is true we should error if/when there are unmeetable dependencies + EnforceNeedsAreInstalled bool // No-Hooks is the no hooks flag NoHooks bool // SkipCleanup is the skip cleanup flag @@ -158,3 +160,8 @@ func (t *TemplateImpl) KubeVersion() string { func (t *TemplateImpl) ShowOnly() []string { return t.TemplateOptions.ShowOnly } + +// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable +func (t *TemplateImpl) EnforceNeedsAreInstalled() bool { + return t.TemplateOptions.EnforceNeedsAreInstalled +} diff --git a/pkg/state/state.go b/pkg/state/state.go index d8e4013c..f5214d67 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -2657,6 +2657,34 @@ func (st *HelmState) UpdateDeps(helm helmexec.Interface, includeTransitiveNeeds return nil } +// DependencyError holds information about a release and its dependency that is not installed. +type DependencyError struct { + Release ReleaseSpec + Dependency ReleaseSpec +} + +// hasTransitiveDependencyWithInstallFalse checks if a release has a transitive dependency with Install set to false. +func (st *HelmState) HasTransitiveDependencyWithInstalledFalse(release ReleaseSpec, visited map[string]bool) *DependencyError { + if visited[release.Name] { + return nil + } + visited[release.Name] = true + + for _, dep := range release.Needs { + for _, r := range st.Releases { + if r.Name == dep { + if r.Installed != nil && !*r.Installed { + return &DependencyError{Release: release, Dependency: r} + } + if depErr := st.HasTransitiveDependencyWithInstalledFalse(r, visited); depErr != nil { + return depErr + } + } + } + } + return nil +} + // find "Chart.yaml" func findChartDirectory(topLevelDir string) (string, error) { var files []string