diff --git a/pkg/action/get_metadata.go b/pkg/action/get_metadata.go index 889545ddc..2677a57ad 100644 --- a/pkg/action/get_metadata.go +++ b/pkg/action/get_metadata.go @@ -17,11 +17,12 @@ limitations under the License. package action import ( + "log/slog" "sort" "strings" "time" - chart "helm.sh/helm/v4/pkg/chart/v2" + ci "helm.sh/helm/v4/pkg/chart" ) // GetMetadata is the action for checking a given release's metadata. @@ -41,13 +42,13 @@ type Metadata struct { // Annotations are fetched from the Chart.yaml file Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` // Labels of the release which are stored in driver metadata fields storage - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` - Dependencies []*chart.Dependency `json:"dependencies,omitempty" yaml:"dependencies,omitempty"` - Namespace string `json:"namespace" yaml:"namespace"` - Revision int `json:"revision" yaml:"revision"` - Status string `json:"status" yaml:"status"` - DeployedAt string `json:"deployedAt" yaml:"deployedAt"` - ApplyMethod string `json:"applyMethod,omitempty" yaml:"applyMethod,omitempty"` + Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` + Dependencies []ci.Dependency `json:"dependencies,omitempty" yaml:"dependencies,omitempty"` + Namespace string `json:"namespace" yaml:"namespace"` + Revision int `json:"revision" yaml:"revision"` + Status string `json:"status" yaml:"status"` + DeployedAt string `json:"deployedAt" yaml:"deployedAt"` + ApplyMethod string `json:"applyMethod,omitempty" yaml:"applyMethod,omitempty"` } // NewGetMetadata creates a new GetMetadata object with the given configuration. @@ -68,12 +69,17 @@ func (g *GetMetadata) Run(name string) (*Metadata, error) { return nil, err } + ac, err := ci.NewAccessor(rel.Chart) + if err != nil { + return nil, err + } + return &Metadata{ Name: rel.Name, Chart: rel.Chart.Metadata.Name, Version: rel.Chart.Metadata.Version, AppVersion: rel.Chart.Metadata.AppVersion, - Dependencies: rel.Chart.Metadata.Dependencies, + Dependencies: ac.MetaDependencies(), Annotations: rel.Chart.Metadata.Annotations, Labels: rel.Labels, Namespace: rel.Namespace, @@ -88,7 +94,13 @@ func (g *GetMetadata) Run(name string) (*Metadata, error) { func (m *Metadata) FormattedDepNames() string { depsNames := make([]string, 0, len(m.Dependencies)) for _, dep := range m.Dependencies { - depsNames = append(depsNames, dep.Name) + ac, err := ci.NewDependencyAccessor(dep) + if err != nil { + slog.Error("unable to access dependency metadata", "error", err) + continue + } + depsNames = append(depsNames, ac.Name()) + } sort.StringSlice(depsNames).Sort() diff --git a/pkg/action/get_metadata_test.go b/pkg/action/get_metadata_test.go index 7962a2133..27e9f3777 100644 --- a/pkg/action/get_metadata_test.go +++ b/pkg/action/get_metadata_test.go @@ -25,6 +25,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + ci "helm.sh/helm/v4/pkg/chart" chart "helm.sh/helm/v4/pkg/chart/v2" kubefake "helm.sh/helm/v4/pkg/kube/fake" release "helm.sh/helm/v4/pkg/release/v1" @@ -123,13 +124,18 @@ func TestGetMetadata_Run_WithDependencies(t *testing.T) { result, err := client.Run(releaseName) require.NoError(t, err) + dep0, err := ci.NewDependencyAccessor(result.Dependencies[0]) + require.NoError(t, err) + dep1, err := ci.NewDependencyAccessor(result.Dependencies[1]) + require.NoError(t, err) + assert.Equal(t, releaseName, result.Name) assert.Equal(t, "test-chart", result.Chart) assert.Equal(t, "1.0.0", result.Version) - assert.Equal(t, dependencies, result.Dependencies) + assert.Equal(t, convertDeps(dependencies), result.Dependencies) assert.Len(t, result.Dependencies, 2) - assert.Equal(t, "mysql", result.Dependencies[0].Name) - assert.Equal(t, "redis", result.Dependencies[1].Name) + assert.Equal(t, "mysql", dep0.Name()) + assert.Equal(t, "redis", dep1.Name()) } func TestGetMetadata_Run_WithDependenciesAliases(t *testing.T) { @@ -177,15 +183,20 @@ func TestGetMetadata_Run_WithDependenciesAliases(t *testing.T) { result, err := client.Run(releaseName) require.NoError(t, err) + dep0, err := ci.NewDependencyAccessor(result.Dependencies[0]) + require.NoError(t, err) + dep1, err := ci.NewDependencyAccessor(result.Dependencies[1]) + require.NoError(t, err) + assert.Equal(t, releaseName, result.Name) assert.Equal(t, "test-chart", result.Chart) assert.Equal(t, "1.0.0", result.Version) - assert.Equal(t, dependencies, result.Dependencies) + assert.Equal(t, convertDeps(dependencies), result.Dependencies) assert.Len(t, result.Dependencies, 2) - assert.Equal(t, "mysql", result.Dependencies[0].Name) - assert.Equal(t, "database", result.Dependencies[0].Alias) - assert.Equal(t, "redis", result.Dependencies[1].Name) - assert.Equal(t, "cache", result.Dependencies[1].Alias) + assert.Equal(t, "mysql", dep0.Name()) + assert.Equal(t, "database", dep0.Alias()) + assert.Equal(t, "redis", dep1.Name()) + assert.Equal(t, "cache", dep1.Alias()) } func TestGetMetadata_Run_WithMixedDependencies(t *testing.T) { @@ -243,23 +254,32 @@ func TestGetMetadata_Run_WithMixedDependencies(t *testing.T) { result, err := client.Run(releaseName) require.NoError(t, err) + dep0, err := ci.NewDependencyAccessor(result.Dependencies[0]) + require.NoError(t, err) + dep1, err := ci.NewDependencyAccessor(result.Dependencies[1]) + require.NoError(t, err) + dep2, err := ci.NewDependencyAccessor(result.Dependencies[2]) + require.NoError(t, err) + dep3, err := ci.NewDependencyAccessor(result.Dependencies[3]) + require.NoError(t, err) + assert.Equal(t, releaseName, result.Name) assert.Equal(t, "test-chart", result.Chart) assert.Equal(t, "1.0.0", result.Version) - assert.Equal(t, dependencies, result.Dependencies) + assert.Equal(t, convertDeps(dependencies), result.Dependencies) assert.Len(t, result.Dependencies, 4) // Verify dependencies with aliases - assert.Equal(t, "mysql", result.Dependencies[0].Name) - assert.Equal(t, "database", result.Dependencies[0].Alias) - assert.Equal(t, "redis", result.Dependencies[2].Name) - assert.Equal(t, "cache", result.Dependencies[2].Alias) + assert.Equal(t, "mysql", dep0.Name()) + assert.Equal(t, "database", dep0.Alias()) + assert.Equal(t, "redis", dep2.Name()) + assert.Equal(t, "cache", dep2.Alias()) // Verify dependencies without aliases - assert.Equal(t, "nginx", result.Dependencies[1].Name) - assert.Equal(t, "", result.Dependencies[1].Alias) - assert.Equal(t, "postgresql", result.Dependencies[3].Name) - assert.Equal(t, "", result.Dependencies[3].Alias) + assert.Equal(t, "nginx", dep1.Name()) + assert.Equal(t, "", dep1.Alias()) + assert.Equal(t, "postgresql", dep3.Name()) + assert.Equal(t, "", dep3.Alias()) } func TestGetMetadata_Run_WithAnnotations(t *testing.T) { @@ -515,8 +535,9 @@ func TestMetadata_FormattedDepNames(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + deps := convertDeps(tc.dependencies) metadata := &Metadata{ - Dependencies: tc.dependencies, + Dependencies: deps, } result := metadata.FormattedDepNames() @@ -525,6 +546,14 @@ func TestMetadata_FormattedDepNames(t *testing.T) { } } +func convertDeps(deps []*chart.Dependency) []ci.Dependency { + var newDeps = make([]ci.Dependency, len(deps)) + for i, c := range deps { + newDeps[i] = c + } + return newDeps +} + func TestMetadata_FormattedDepNames_WithComplexDependencies(t *testing.T) { dependencies := []*chart.Dependency{ { @@ -546,8 +575,9 @@ func TestMetadata_FormattedDepNames_WithComplexDependencies(t *testing.T) { }, } + deps := convertDeps(dependencies) metadata := &Metadata{ - Dependencies: dependencies, + Dependencies: deps, } result := metadata.FormattedDepNames() @@ -597,8 +627,9 @@ func TestMetadata_FormattedDepNames_WithAliases(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + deps := convertDeps(tc.dependencies) metadata := &Metadata{ - Dependencies: tc.dependencies, + Dependencies: deps, } result := metadata.FormattedDepNames() diff --git a/pkg/chart/dependency.go b/pkg/chart/dependency.go index 9f7c90364..864fe6d2c 100644 --- a/pkg/chart/dependency.go +++ b/pkg/chart/dependency.go @@ -47,6 +47,10 @@ func (r *v2DependencyAccessor) Name() string { return r.dep.Name } +func (r *v2DependencyAccessor) Alias() string { + return r.dep.Alias +} + type v3DependencyAccessor struct { dep *v3chart.Dependency } @@ -54,3 +58,7 @@ type v3DependencyAccessor struct { func (r *v3DependencyAccessor) Name() string { return r.dep.Name } + +func (r *v3DependencyAccessor) Alias() string { + return r.dep.Alias +} diff --git a/pkg/chart/interfaces.go b/pkg/chart/interfaces.go index f9c61c35c..4001bc548 100644 --- a/pkg/chart/interfaces.go +++ b/pkg/chart/interfaces.go @@ -40,4 +40,5 @@ type Accessor interface { type DependencyAccessor interface { Name() string + Alias() string }