Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 10 additions & 41 deletions api/v1alpha1/blueprint_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,38 +246,7 @@ func (b *Blueprint) DeepCopy() *Blueprint {

kustomizationsCopy := make([]Kustomization, len(b.Kustomizations))
for i, kustomization := range b.Kustomizations {
var substituteFromCopy []SubstituteReference
if kustomization.PostBuild != nil {
substituteFromCopy = make([]SubstituteReference, len(kustomization.PostBuild.SubstituteFrom))
copy(substituteFromCopy, kustomization.PostBuild.SubstituteFrom)
}

postBuildCopy := &PostBuild{
Substitute: make(map[string]string),
SubstituteFrom: substituteFromCopy,
}
if kustomization.PostBuild != nil {
for key, value := range kustomization.PostBuild.Substitute {
postBuildCopy.Substitute[key] = value
}
}

kustomizationsCopy[i] = Kustomization{
Name: kustomization.Name,
Path: kustomization.Path,
Source: kustomization.Source,
DependsOn: slices.Clone(kustomization.DependsOn),
Interval: kustomization.Interval,
RetryInterval: kustomization.RetryInterval,
Timeout: kustomization.Timeout,
Patches: slices.Clone(kustomization.Patches),
Wait: kustomization.Wait,
Force: kustomization.Force,
Prune: kustomization.Prune,
Components: slices.Clone(kustomization.Components),
Cleanup: slices.Clone(kustomization.Cleanup),
PostBuild: postBuildCopy,
}
kustomizationsCopy[i] = *kustomization.DeepCopy()
}

return &Blueprint{
Expand Down Expand Up @@ -366,9 +335,7 @@ func (b *Blueprint) Merge(overlay *Blueprint) {
if mergedComponent.Values == nil {
mergedComponent.Values = make(map[string]any)
}
for k, v := range overlayComponent.Values {
mergedComponent.Values[k] = v
}
maps.Copy(mergedComponent.Values, overlayComponent.Values)

if overlayComponent.FullPath != "" {
mergedComponent.FullPath = overlayComponent.FullPath
Expand Down Expand Up @@ -402,12 +369,14 @@ func (k *Kustomization) DeepCopy() *Kustomization {

var postBuildCopy *PostBuild
if k.PostBuild != nil {
postBuildCopy = &PostBuild{
Substitute: make(map[string]string),
SubstituteFrom: slices.Clone(k.PostBuild.SubstituteFrom),
}
for key, value := range k.PostBuild.Substitute {
postBuildCopy.Substitute[key] = value
substituteCopy := maps.Clone(k.PostBuild.Substitute)
substituteFromCopy := slices.Clone(k.PostBuild.SubstituteFrom)

if len(substituteCopy) > 0 || len(substituteFromCopy) > 0 {
postBuildCopy = &PostBuild{
Substitute: substituteCopy,
SubstituteFrom: substituteFromCopy,
}
}
}

Expand Down
51 changes: 51 additions & 0 deletions api/v1alpha1/blueprint_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1023,3 +1023,54 @@ func TestBlueprint_DeepCopy(t *testing.T) {
}
})
}

// TestPostBuildOmitEmpty verifies that empty PostBuild objects are omitted from YAML serialization
func TestPostBuildOmitEmpty(t *testing.T) {
t.Run("EmptyPostBuildOmitted", func(t *testing.T) {
kustomization := Kustomization{
Name: "test-kustomization",
Path: "test/path",
PostBuild: &PostBuild{
Substitute: map[string]string{},
SubstituteFrom: []SubstituteReference{},
},
}

// Create a copy using DeepCopy which should omit empty PostBuild
copied := kustomization.DeepCopy()

// Verify that PostBuild is nil for empty content
if copied.PostBuild != nil {
t.Errorf("Expected PostBuild to be nil for empty content, but got %v", copied.PostBuild)
}
})

t.Run("NonEmptyPostBuildPreserved", func(t *testing.T) {
kustomization := Kustomization{
Name: "test-kustomization",
Path: "test/path",
PostBuild: &PostBuild{
Substitute: map[string]string{
"key": "value",
},
SubstituteFrom: []SubstituteReference{
{Kind: "ConfigMap", Name: "test"},
},
},
}

// Create a copy using DeepCopy which should preserve non-empty PostBuild
copied := kustomization.DeepCopy()

// Verify that PostBuild is preserved for non-empty content
if copied.PostBuild == nil {
t.Error("Expected PostBuild to be preserved for non-empty content, but got nil")
}
if copied.PostBuild.Substitute["key"] != "value" {
t.Errorf("Expected substitute key to be 'value', but got %s", copied.PostBuild.Substitute["key"])
}
if len(copied.PostBuild.SubstituteFrom) != 1 {
t.Errorf("Expected 1 substitute reference, but got %d", len(copied.PostBuild.SubstituteFrom))
}
})
}
11 changes: 10 additions & 1 deletion pkg/blueprint/blueprint_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import (
helmv2 "github.com/fluxcd/helm-controller/api/v2"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
"github.com/goccy/go-yaml"
blueprintv1alpha1 "github.com/windsorcli/cli/api/v1alpha1"
"github.com/windsorcli/cli/pkg/artifact"
"github.com/windsorcli/cli/pkg/config"
"github.com/windsorcli/cli/pkg/constants"
"github.com/windsorcli/cli/pkg/di"
"github.com/windsorcli/cli/pkg/kubernetes"
"github.com/windsorcli/cli/pkg/shell"
"gopkg.in/yaml.v3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -3326,6 +3326,15 @@ func TestBlueprintHandler_Write(t *testing.T) {
if len(component.Values) != 0 {
t.Errorf("Expected all values to be cleared, but got %d values: %v", len(component.Values), component.Values)
}

// Also verify kustomizations have postBuild cleared
if len(writtenBlueprint.Kustomizations) > 0 {
for i, kustomization := range writtenBlueprint.Kustomizations {
if kustomization.PostBuild != nil {
t.Errorf("Expected PostBuild to be cleared for kustomization %d, but got %v", i, kustomization.PostBuild)
}
}
}
})

t.Run("ErrorWritingFile", func(t *testing.T) {
Expand Down
Loading