Skip to content
17 changes: 17 additions & 0 deletions docs/api-reference/landscapekit-v1alpha1.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,23 @@ _Appears in:_



#### MergeMode

_Underlying type:_ _string_

MergeMode controls how operator overwrites are handled during three-way merge.



_Appears in:_
- [LandscapeKitConfiguration](#landscapekitconfiguration)

| Field | Description |
| --- | --- |
| `Informative` | MergeModeInformative annotates operator-overwritten values with a comment showing the current GLK default.<br /> |
| `Silent` | MergeModeSilent retains operator overwrites without annotation.<br /> |


#### OCMComponent


Expand Down
1 change: 1 addition & 0 deletions example/20-componentconfig-glk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ kind: LandscapeKitConfiguration
# - component-name
# versionConfig:
# defaultVersionsUpdateStrategy: ReleaseBranch
# mergeMode: Informative
3 changes: 2 additions & 1 deletion hack/tools/prettify/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

flag "github.com/spf13/pflag"

configv1alpha1 "github.com/gardener/gardener-landscape-kit/pkg/apis/config/v1alpha1"
"github.com/gardener/gardener-landscape-kit/pkg/utils/meta"
)

Expand All @@ -31,7 +32,7 @@ func main() {
if err != nil {
log.Fatalf("Error reading file: %s", err)
}
prettified, err := meta.ThreeWayMergeManifest(nil, content, nil)
prettified, err := meta.ThreeWayMergeManifest(nil, content, nil, configv1alpha1.MergeModeSilent)
if err != nil {
log.Fatalf("Marshalling failed: %s", err)
}
Expand Down
14 changes: 14 additions & 0 deletions pkg/apis/config/v1alpha1/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,17 @@
// SPDX-License-Identifier: Apache-2.0

package v1alpha1

// SetDefaults_LandscapeKitConfiguration sets default values for LandscapeKitConfiguration fields.
func SetDefaults_LandscapeKitConfiguration(obj *LandscapeKitConfiguration) {
if obj.VersionConfig == nil {
obj.VersionConfig = &VersionConfiguration{}
}
if obj.VersionConfig.DefaultVersionsUpdateStrategy == nil {
obj.VersionConfig.DefaultVersionsUpdateStrategy = new(DefaultVersionsUpdateStrategyDisabled)
}

if obj.MergeMode == nil {
obj.MergeMode = new(MergeModeInformative)
}
}
21 changes: 21 additions & 0 deletions pkg/apis/config/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ type LandscapeKitConfiguration struct {
// VersionConfig is the configuration for versioning.
// +optional
VersionConfig *VersionConfiguration `json:"versionConfig,omitempty"`
// MergeMode determines how merge conflicts are resolved:
// - "Informative" (default): New default values from GLK are added as comments after any customized values.
// - "Silent": Operator-customized values are retained, new default values are omitted.
// +optional
MergeMode *MergeMode `json:"mergeMode,omitempty"`
Comment thread
LucaBernstein marked this conversation as resolved.
}

// ComponentsConfiguration contains configuration for components.
Expand Down Expand Up @@ -119,3 +124,19 @@ type VersionConfiguration struct {
// +optional
DefaultVersionsUpdateStrategy *DefaultVersionsUpdateStrategy `json:"defaultVersionsUpdateStrategy,omitempty"`
}

// MergeMode controls how operator overwrites are handled during three-way merge.
type MergeMode string

const (
// MergeModeInformative annotates operator-overwritten values with a comment showing the current GLK default.
MergeModeInformative MergeMode = "Informative"
// MergeModeSilent retains operator overwrites without annotation.
MergeModeSilent MergeMode = "Silent"
)

// AllowedMergeModes lists all allowed merge modes.
var AllowedMergeModes = []string{
string(MergeModeInformative),
string(MergeModeSilent),
}
4 changes: 4 additions & 0 deletions pkg/apis/config/v1alpha1/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func ValidateLandscapeKitConfiguration(conf *configv1alpha1.LandscapeKitConfigur
allErrs = append(allErrs, ValidateVersionConfig(conf.VersionConfig, field.NewPath("versionConfig"))...)
}

if conf.MergeMode != nil && !slices.Contains(configv1alpha1.AllowedMergeModes, string(*conf.MergeMode)) {
allErrs = append(allErrs, field.NotSupported(field.NewPath("mergeMode"), *conf.MergeMode, configv1alpha1.AllowedMergeModes))
}

return allErrs
}

Expand Down
37 changes: 37 additions & 0 deletions pkg/apis/config/v1alpha1/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,43 @@ var _ = Describe("Validation", func() {
Expect(errList).To(BeEmpty())
})
})

Context("MergeMode Configuration", func() {
It("should pass with valid MergeMode values", func() {
for _, mode := range []v1alpha1.MergeMode{
v1alpha1.MergeModeInformative,
v1alpha1.MergeModeSilent,
} {
conf := &v1alpha1.LandscapeKitConfiguration{
MergeMode: &mode,
}
errList := validation.ValidateLandscapeKitConfiguration(conf)
Expect(errList).To(BeEmpty(), fmt.Sprintf("MergeMode %q should be valid", mode))
}
})

It("should pass when MergeMode is not set", func() {
conf := &v1alpha1.LandscapeKitConfiguration{}
errList := validation.ValidateLandscapeKitConfiguration(conf)
Expect(errList).To(BeEmpty())
})

It("should fail with an invalid MergeMode value", func() {
invalid := v1alpha1.MergeMode("Invalid")
conf := &v1alpha1.LandscapeKitConfiguration{
MergeMode: &invalid,
}

errList := validation.ValidateLandscapeKitConfiguration(conf)
Expect(errList).To(ConsistOf(
PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeNotSupported),
"Field": Equal("mergeMode"),
"BadValue": Equal(invalid),
})),
))
})
})
})
})

Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/config/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/apis/config/v1alpha1/zz_generated.defaults.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 25 additions & 17 deletions pkg/cmd/resolve/plain/plain.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ package plain

import (
"context"
"errors"
"fmt"
"os"
"path"
"strings"

"github.com/spf13/afero"
"github.com/spf13/cobra"
Expand All @@ -22,6 +20,7 @@ import (
configv1alpha1 "github.com/gardener/gardener-landscape-kit/pkg/apis/config/v1alpha1"
"github.com/gardener/gardener-landscape-kit/pkg/cmd"
utilscomponentvector "github.com/gardener/gardener-landscape-kit/pkg/utils/componentvector"
utilsfiles "github.com/gardener/gardener-landscape-kit/pkg/utils/files"
)

var configDecoder runtime.Decoder
Expand Down Expand Up @@ -111,7 +110,7 @@ func (o *Options) loadConfigFile(filename string) error {

func run(_ context.Context, opts *Options) error {
if opts.Config != nil && opts.Config.VersionConfig != nil {
if updateStrategy := opts.Config.VersionConfig.DefaultVersionsUpdateStrategy; updateStrategy != nil && *updateStrategy == configv1alpha1.DefaultVersionsUpdateStrategyReleaseBranch {
if *opts.Config.VersionConfig.DefaultVersionsUpdateStrategy == configv1alpha1.DefaultVersionsUpdateStrategyReleaseBranch {
opts.Log.Info("Updating default component vector file from the release branch", "branch", utilscomponentvector.GetReleaseBranchName())
var err error
// The componentvector.DefaultComponentsYAML is intentionally overridden, so that subsequently it can be used to extract the updated default component vector versions.
Expand All @@ -122,21 +121,30 @@ func run(_ context.Context, opts *Options) error {
}
}

compVectorFile := path.Join(opts.TargetDirPath, utilscomponentvector.ComponentVectorFilename)
opts.Log.Info("Writing component vector file", "file", compVectorFile)

var customBytes []byte
var err error
if customBytes, err = opts.fs.ReadFile(compVectorFile); err != nil {
if !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("failed to read component vector override file: %w", err)
}
var (
err error
newDefaultCV utilscomponentvector.Interface
newDefaultBytes []byte
)
newDefaultCV, err = utilscomponentvector.NewWithOverride(componentvector.DefaultComponentsYAML)
if err != nil {
return fmt.Errorf("failed to build default component vector: %w", err)
}

componentVector, err := utilscomponentvector.NewWithOverride(componentvector.DefaultComponentsYAML, customBytes)
newDefaultBytes, err = utilscomponentvector.NameVersionBytes(newDefaultCV)
if err != nil {
return fmt.Errorf("failed to create component vector: %w", err)
return fmt.Errorf("failed to marshal default component vector: %w", err)
}

return utilscomponentvector.WriteComponentVectorFile(opts.fs, opts.TargetDirPath, componentVector)
header := []byte(strings.Join([]string{
"# This file is updated by the gardener-landscape-kit.",
"# If this file is present in the root of a gardener-landscape-kit-managed repository, the component versions will be used as overrides.",
"# If custom component versions should be used, it is recommended to modify the specified versions here and run the `generate` command afterwards.",
}, "\n") + "\n")
newDefaultBytes = append(header, newDefaultBytes...)

if err := utilsfiles.WriteObjectsToFilesystem(map[string][]byte{utilscomponentvector.ComponentVectorFilename: newDefaultBytes}, opts.TargetDirPath, "", opts.fs, *opts.Config.MergeMode); err != nil {
return fmt.Errorf("failed to write updated component vector: %w", err)
}

return nil
}
2 changes: 1 addition & 1 deletion pkg/components/flux/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func writeLandscapeTemplateFiles(opts components.LandscapeOptions) error {
delete(objects, "flux-system/gitignore")
delete(objects, "flux-system/doc.go")

return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), DirName, opts.GetFilesystem())
return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), DirName, opts.GetFilesystem(), opts.GetMergeMode())
}

func writeGitignoreFile(options components.LandscapeOptions) error {
Expand Down
19 changes: 11 additions & 8 deletions pkg/components/flux/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,24 @@ var _ = Describe("Flux Component Generation", func() {

fs = afero.Afero{Fs: afero.NewMemMapFs()}

config := &v1alpha1.LandscapeKitConfiguration{
Git: &v1alpha1.GitRepository{
URL: repoURL,
Paths: v1alpha1.PathConfiguration{
Landscape: relativeLandscapePath,
},
},
}
v1alpha1.SetObjectDefaults_LandscapeKitConfiguration(config)

var err error
opts, err = components.NewLandscapeOptions(
&generateoptions.Options{
Options: &cmd.Options{
Log: logr.Discard(),
},
TargetDirPath: targetPath,
Config: &v1alpha1.LandscapeKitConfiguration{
Git: &v1alpha1.GitRepository{
URL: repoURL,
Paths: v1alpha1.PathConfiguration{
Landscape: relativeLandscapePath,
},
},
},
Config: config,
},
fs,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func writeBaseTemplateFiles(opts components.Options) error {
return err
}

return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem())
return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem(), opts.GetMergeMode())
}

func writeLandscapeTemplateFiles(opts components.LandscapeOptions) error {
Expand All @@ -100,5 +100,5 @@ func writeLandscapeTemplateFiles(opts components.LandscapeOptions) error {
return err
}

return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem())
return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem(), opts.GetMergeMode())
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ var _ = Describe("Component Generation", func() {
generateOpts = &generateoptions.Options{
TargetDirPath: "/repo/baseDir",
Options: cmdOpts,
Config: &v1alpha1.LandscapeKitConfiguration{},
}
v1alpha1.SetObjectDefaults_LandscapeKitConfiguration(generateOpts.Config)
})

Describe("#GenerateBase", func() {
Expand Down Expand Up @@ -68,6 +70,7 @@ var _ = Describe("Component Generation", func() {
generateOpts.Config = &v1alpha1.LandscapeKitConfiguration{
Git: &v1alpha1.GitRepository{Paths: v1alpha1.PathConfiguration{Landscape: "./landscapeDir", Base: "./baseDir"}},
}
v1alpha1.SetObjectDefaults_LandscapeKitConfiguration(generateOpts.Config)
})

It("should generate only the flux kustomization into the landscape dir", func() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func writeBaseTemplateFiles(opts components.Options) error {
return err
}

return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem())
return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem(), opts.GetMergeMode())
}

func writeLandscapeTemplateFiles(opts components.LandscapeOptions) error {
Expand All @@ -100,5 +100,5 @@ func writeLandscapeTemplateFiles(opts components.LandscapeOptions) error {
return err
}

return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem())
return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem(), opts.GetMergeMode())
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ var _ = Describe("Component Generation", func() {
generateOpts = &generateoptions.Options{
TargetDirPath: "/repo/baseDir",
Options: cmdOpts,
Config: &v1alpha1.LandscapeKitConfiguration{},
}
v1alpha1.SetObjectDefaults_LandscapeKitConfiguration(generateOpts.Config)
})

Describe("#GenerateBase", func() {
Expand Down Expand Up @@ -68,6 +70,7 @@ var _ = Describe("Component Generation", func() {
generateOpts.Config = &v1alpha1.LandscapeKitConfiguration{
Git: &v1alpha1.GitRepository{Paths: v1alpha1.PathConfiguration{Landscape: "./landscapeDir", Base: "./baseDir"}},
}
v1alpha1.SetObjectDefaults_LandscapeKitConfiguration(generateOpts.Config)
})

It("should generate only the flux kustomization into the landscape dir", func() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func writeBaseTemplateFiles(opts components.Options) error {
return err
}

return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem())
return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem(), opts.GetMergeMode())
}

func writeLandscapeTemplateFiles(opts components.LandscapeOptions) error {
Expand All @@ -100,5 +100,5 @@ func writeLandscapeTemplateFiles(opts components.LandscapeOptions) error {
return err
}

return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem())
return files.WriteObjectsToFilesystem(objects, opts.GetTargetPath(), path.Join(components.DirName, ComponentDirectory), opts.GetFilesystem(), opts.GetMergeMode())
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ var _ = Describe("Component Generation", func() {
generateOpts = &generateoptions.Options{
TargetDirPath: "/repo/baseDir",
Options: cmdOpts,
Config: &v1alpha1.LandscapeKitConfiguration{},
}
v1alpha1.SetObjectDefaults_LandscapeKitConfiguration(generateOpts.Config)
})

Describe("#GenerateBase", func() {
Expand Down Expand Up @@ -68,6 +70,7 @@ var _ = Describe("Component Generation", func() {
generateOpts.Config = &v1alpha1.LandscapeKitConfiguration{
Git: &v1alpha1.GitRepository{Paths: v1alpha1.PathConfiguration{Landscape: "./landscapeDir", Base: "./baseDir"}},
}
v1alpha1.SetObjectDefaults_LandscapeKitConfiguration(generateOpts.Config)
})

It("should generate only the flux kustomization into the landscape dir", func() {
Expand Down
Loading