Issue-1883 fix (#2058)

* Issue-1883 fix

Signed-off-by: zhaque44 <haque.zubair@gmail.com>
Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
Zubair Haque
2025-11-19 07:45:56 +08:00
committed by GitHub
parent 258b8a0b30
commit ab5e9a1326
14 changed files with 176 additions and 78 deletions
+17 -2
View File
@@ -2144,13 +2144,19 @@ func (a *App) withNeeds(r *Run, c DAGConfig, includeDisabled bool, f func(*state
includeNeeds = true
}
batches, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, IncludeNeeds: includeNeeds, IncludeTransitiveNeeds: c.IncludeTransitiveNeeds(), SkipNeeds: c.SkipNeeds()})
batches, err := st.PlanReleases(state.PlanOptions{
Reverse: false,
SelectedReleases: selectedReleases,
IncludeNeeds: includeNeeds,
IncludeTransitiveNeeds: c.IncludeTransitiveNeeds(),
SkipNeeds: c.SkipNeeds(),
})
if err != nil {
return false, []error{err}
}
var selectedReleasesWithNeeds []state.ReleaseSpec
for _, rs := range batches {
for _, r := range rs {
selectedReleasesWithNeeds = append(selectedReleasesWithNeeds, r.ReleaseSpec)
@@ -2185,6 +2191,15 @@ func (a *App) withNeeds(r *Run, c DAGConfig, includeDisabled bool, f func(*state
}
}
if c.EnforceNeedsAreInstalled() {
for _, r := range toRender {
visited := make(map[string]bool)
if depErr := st.HasTransitiveDependencyWithInstalledFalse(r, visited); depErr != nil {
return false, []error{fmt.Errorf("Release %s has a transitive dependency %s marked as installed=false", depErr.Release.Name, depErr.Dependency.Name)}
}
}
}
if includeDisabled {
for _, d := range releasesToUninstall {
rels = append(rels, d)
+55 -45
View File
@@ -2195,11 +2195,12 @@ type configImpl struct {
skipSchemaValidation bool
skipRefresh bool
skipNeeds bool
includeNeeds bool
includeTransitiveNeeds bool
skipCharts bool
kubeVersion string
skipNeeds bool
includeNeeds bool
includeTransitiveNeeds bool
enforceNeedsAreInstalled bool
skipCharts bool
kubeVersion string
}
func (c configImpl) Selectors() []string {
@@ -2306,51 +2307,56 @@ func (c configImpl) ShowOnly() []string {
return nil
}
func (c configImpl) EnforceNeedsAreInstalled() bool {
return c.enforceNeedsAreInstalled
}
type applyConfig struct {
args string
cascade string
values []string
set []string
validate bool
skipCleanup bool
skipCRDs bool
skipDeps bool
skipRefresh bool
skipNeeds bool
includeNeeds bool
includeTransitiveNeeds bool
includeTests bool
suppress []string
suppressSecrets bool
showSecrets bool
noHooks bool
suppressDiff bool
noColor bool
color bool
context int
diffOutput string
concurrency int
detailedExitcode bool
stripTrailingCR bool
interactive bool
skipDiffOnInstall bool
syncArgs string
diffArgs string
logger *zap.SugaredLogger
wait bool
waitRetries int
waitForJobs bool
reuseValues bool
postRenderer string
postRendererArgs []string
skipSchemaValidation bool
kubeVersion string
suppressOutputLineRegex []string
showOnly []string
hideNotes bool
takeOwnership bool
syncReleaseLabels bool
set []string
validate bool
skipCleanup bool
skipCRDs bool
skipDeps bool
skipRefresh bool
skipNeeds bool
includeNeeds bool
includeTransitiveNeeds bool
includeTests bool
suppress []string
suppressSecrets bool
showSecrets bool
noHooks bool
suppressDiff bool
noColor bool
color bool
context int
diffOutput string
concurrency int
detailedExitcode bool
stripTrailingCR bool
interactive bool
skipDiffOnInstall bool
syncArgs string
diffArgs string
logger *zap.SugaredLogger
wait bool
waitRetries int
waitForJobs bool
reuseValues bool
postRenderer string
postRendererArgs []string
skipSchemaValidation bool
kubeVersion string
suppressOutputLineRegex []string
showOnly []string
hideNotes bool
takeOwnership bool
syncReleaseLabels bool
enforceNeedsAreInstalled bool
// template-only options
includeCRDs, skipTests bool
@@ -2409,6 +2415,10 @@ func (a applyConfig) SkipNeeds() bool {
return a.skipNeeds
}
func (a applyConfig) EnforceNeedsAreInstalled() bool {
return a.enforceNeedsAreInstalled
}
func (a applyConfig) IncludeNeeds() bool {
return a.includeNeeds || a.IncludeTransitiveNeeds()
}
+1
View File
@@ -242,6 +242,7 @@ type DAGConfig interface {
SkipNeeds() bool
IncludeNeeds() bool
IncludeTransitiveNeeds() bool
EnforceNeedsAreInstalled() bool
}
type WriteValuesConfigProvider interface {
+36 -31
View File
@@ -16,37 +16,38 @@ import (
)
type diffConfig struct {
args string
diffArgs string
values []string
retainValuesFiles bool
set []string
validate bool
skipCRDs bool
skipDeps bool
skipRefresh bool
includeTests bool
skipNeeds bool
includeNeeds bool
includeTransitiveNeeds bool
suppress []string
suppressSecrets bool
showSecrets bool
noHooks bool
suppressDiff bool
suppressOutputLineRegex []string
noColor bool
context int
diffOutput string
concurrency int
detailedExitcode bool
stripTrailingCR bool
interactive bool
skipDiffOnInstall bool
skipSchemaValidation bool
reuseValues bool
logger *zap.SugaredLogger
takeOwnership bool
args string
diffArgs string
values []string
retainValuesFiles bool
set []string
validate bool
skipCRDs bool
skipDeps bool
skipRefresh bool
includeTests bool
skipNeeds bool
includeNeeds bool
includeTransitiveNeeds bool
suppress []string
suppressSecrets bool
showSecrets bool
noHooks bool
suppressDiff bool
suppressOutputLineRegex []string
noColor bool
context int
diffOutput string
concurrency int
detailedExitcode bool
stripTrailingCR bool
interactive bool
skipDiffOnInstall bool
skipSchemaValidation bool
reuseValues bool
logger *zap.SugaredLogger
takeOwnership bool
enforceNeedsAreInstalled bool
}
func (a diffConfig) Args() string {
@@ -188,6 +189,10 @@ func (a diffConfig) TakeOwnership() bool {
return a.takeOwnership
}
func (a diffConfig) EnforceNeedsAreInstalled() bool {
return a.enforceNeedsAreInstalled
}
func TestDiff(t *testing.T) {
type flags struct {
skipNeeds bool
+7
View File
@@ -28,6 +28,8 @@ type ApplyOptions struct {
IncludeNeeds bool
// IncludeTransitiveNeeds is true if the transitive needs should be included
IncludeTransitiveNeeds bool
// EnforceNeedsAreInstalled is true if we should error if/when there are unmeetable dependencies
EnforceNeedsAreInstalled bool
// SkipDiffOnInstall is true if the diff should be skipped on install
SkipDiffOnInstall bool
// DiffArgs is the list of arguments to pass to the helm-diff.
@@ -139,6 +141,11 @@ func (a *ApplyImpl) IncludeTransitiveNeeds() bool {
return a.ApplyOptions.IncludeTransitiveNeeds
}
// EnforceNeedsAreInstalled is true we should error if/when there are unmeetable dependencies
func (a *ApplyImpl) EnforceNeedsAreInstalled() bool {
return a.ApplyOptions.EnforceNeedsAreInstalled
}
// ShowSecrets returns the show secrets.
func (a *ApplyImpl) ShowSecrets() bool {
return a.ApplyOptions.ShowSecrets
+7
View File
@@ -18,6 +18,8 @@ type DiffOptions struct {
IncludeNeeds bool
// IncludeTransitiveNeeds is the include transitive needs flag
IncludeTransitiveNeeds bool
// EnforceNeedsAreInstalled is the enforce needs are installed flag
EnforceNeedsAreInstalled bool
// SkipDiffOnInstall is the skip diff on install flag
SkipDiffOnInstall bool
// ShowSecrets is the show secrets flag
@@ -87,6 +89,11 @@ func (t *DiffImpl) IncludeTransitiveNeeds() bool {
return t.DiffOptions.IncludeTransitiveNeeds
}
// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable
func (t *DiffImpl) EnforceNeedsAreInstalled() bool {
return t.DiffOptions.EnforceNeedsAreInstalled
}
// Set returns the Set
func (t *DiffImpl) Set() []string {
return t.DiffOptions.Set
+7
View File
@@ -14,6 +14,8 @@ type LintOptions struct {
IncludeNeeds bool
// IncludeTransitiveNeeds is the include transitive needs flag
IncludeTransitiveNeeds bool
// EnforceNeedsAreInstalled is the enforce needs are installed flag
EnforceNeedsAreInstalled bool
// SkipDeps is the skip deps flag
}
@@ -66,6 +68,11 @@ func (l *LintImpl) IncludeTransitiveNeeds() bool {
return l.LintOptions.IncludeTransitiveNeeds
}
// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable
func (l *LintImpl) EnforceNeedsAreInstalled() bool {
return l.LintOptions.EnforceNeedsAreInstalled
}
// SkipNeeds returns the skip needs
func (l *LintImpl) SkipNeeds() bool {
if !l.IncludeNeeds() {
+7
View File
@@ -16,6 +16,8 @@ type SyncOptions struct {
IncludeNeeds bool
// IncludeTransitiveNeeds is the include transitive needs flag
IncludeTransitiveNeeds bool
// EnforceNeedsAreInstalled indicates whether to error 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
+7
View File
@@ -30,6 +30,8 @@ type TemplateOptions struct {
IncludeNeeds bool
// IncludeTransitiveNeeds is the include transitive needs flag
IncludeTransitiveNeeds bool
// EnforceNeedsAreInstalled indicates whether to error 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
}
+28
View File
@@ -2738,6 +2738,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