fix: update dependencies whose installed version does not satisfy the Chart.yaml constraint

`CheckDependencies` matched dependencies only by name, so a chart that had
previously downloaded a dependency (charts/<name>) was considered satisfied
even when its installed version no longer satisfied the version constraint in
Chart.yaml. With --dependency-update, `helm install` / `helm template` therefore
silently kept the outdated dependency instead of updating it.

Compare the installed chart version against the requested constraint using
IsCompatibleRange, and treat the dependency as present only when the name
matches and either no constraint is declared or the installed version satisfies
it. Expose Version() on the chart/dependency accessors to make this possible.

Fixes #31455

Signed-off-by: waterWang <672684719@qq.com>
pull/32588/head
waterWang 2 weeks ago
parent d62bee21c2
commit f7f1c74dc0

@ -844,7 +844,7 @@ OUTER:
if err != nil {
return err
}
if dac.Name() == rac.Name() {
if dac.Name() == rac.Name() && (rac.Version() == "" || chartutil.IsCompatibleRange(rac.Version(), dac.Version())) {
continue OUTER
}
}

@ -1196,6 +1196,27 @@ func TestCheckDependencies_MissingDependency(t *testing.T) {
assert.ErrorContains(t, CheckDependencies(mockChart, []ci.Dependency{&dependency}), "missing in charts")
}
func TestCheckDependencies_MatchingVersion(t *testing.T) {
dependency := chart.Dependency{Name: "hello", Version: "0.1.0"}
mockChart := buildChart(withDependency())
assert.NoError(t, CheckDependencies(mockChart, []ci.Dependency{&dependency}))
}
func TestCheckDependencies_MismatchedVersion(t *testing.T) {
mismatched := chart.Dependency{Name: "hello", Version: "0.2.0"}
mockChart := buildChart(withDependency())
assert.ErrorContains(t, CheckDependencies(mockChart, []ci.Dependency{&mismatched}), "missing in charts")
}
func TestCheckDependencies_WithoutVersionConstraint(t *testing.T) {
dependency := chart.Dependency{Name: "hello"}
mockChart := buildChart(withDependency())
assert.NoError(t, CheckDependencies(mockChart, []ci.Dependency{&dependency}))
}
func TestInstallCRDs_CheckNilErrors(t *testing.T) {
tests := []struct {
name string

@ -51,6 +51,10 @@ func (r *v2Accessor) Name() string {
return r.chrt.Metadata.Name
}
func (r *v2Accessor) Version() string {
return r.chrt.Metadata.Version
}
func (r *v2Accessor) IsRoot() bool {
return r.chrt.IsRoot()
}
@ -120,6 +124,10 @@ func (r *v3Accessor) Name() string {
return r.chrt.Metadata.Name
}
func (r *v3Accessor) Version() string {
return r.chrt.Metadata.Version
}
func (r *v3Accessor) IsRoot() bool {
return r.chrt.IsRoot()
}

@ -47,6 +47,10 @@ func (r *v2DependencyAccessor) Name() string {
return r.dep.Name
}
func (r *v2DependencyAccessor) Version() string {
return r.dep.Version
}
func (r *v2DependencyAccessor) Alias() string {
return r.dep.Alias
}
@ -59,6 +63,10 @@ func (r *v3DependencyAccessor) Name() string {
return r.dep.Name
}
func (r *v3DependencyAccessor) Version() string {
return r.dep.Version
}
func (r *v3DependencyAccessor) Alias() string {
return r.dep.Alias
}

@ -25,6 +25,7 @@ type Dependency any
type Accessor interface {
Name() string
Version() string
IsRoot() bool
MetadataAsMap() map[string]any
Files() []*common.File
@ -40,5 +41,6 @@ type Accessor interface {
type DependencyAccessor interface {
Name() string
Version() string
Alias() string
}

Loading…
Cancel
Save