diff --git a/kustomize/commands/edit/add/addconfiguration.go b/kustomize/commands/edit/add/addconfiguration.go new file mode 100644 index 000000000..66fda7c4e --- /dev/null +++ b/kustomize/commands/edit/add/addconfiguration.go @@ -0,0 +1,86 @@ +// Copyright 2025 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package add + +import ( + "errors" + "fmt" + "log" + "slices" + + "github.com/spf13/cobra" + "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile" + "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util" + "sigs.k8s.io/kustomize/kyaml/filesys" +) + +type addConfigurationOptions struct { + configurationFilePaths []string +} + +// newCmdAddConfiguration adds the name of a file containing a configuration +// to the kustomization file. +func newCmdAddConfiguration(fSys filesys.FileSystem) *cobra.Command { + var o addConfigurationOptions + cmd := &cobra.Command{ + Use: "configuration", + Short: "Add the name of a file containing a configuration to the kustomization file", + Long: `Add the name of a file containing a configuration (e.g., a Kubernetes configuration resource) +to the kustomization file. Configurations are used to define custom transformer specifications +for CRDs and other resource types.`, + Example: ` + # Adds a configuration file to the kustomization + kustomize edit add configuration + + # Adds multiple configuration files + kustomize edit add configuration ,`, + RunE: func(cmd *cobra.Command, args []string) error { + err := o.Validate(fSys, args) + if err != nil { + return err + } + return o.RunAddConfiguration(fSys) + }, + } + return cmd +} + +// Validate validates add configuration command. +func (o *addConfigurationOptions) Validate(fSys filesys.FileSystem, args []string) error { + if len(args) == 0 { + return errors.New("must specify a yaml file which contains a configuration resource") + } + var err error + o.configurationFilePaths, err = util.GlobPatterns(fSys, args) + if err != nil { + return fmt.Errorf("glob patterns: %w", err) + } + return nil +} + +// RunAddConfiguration runs add configuration command (do real work). +func (o *addConfigurationOptions) RunAddConfiguration(fSys filesys.FileSystem) error { + if len(o.configurationFilePaths) == 0 { + return nil + } + mf, err := kustfile.NewKustomizationFile(fSys) + if err != nil { + return fmt.Errorf("new kustomization file: %w", err) + } + m, err := mf.Read() + if err != nil { + return fmt.Errorf("read kustomization: %w", err) + } + for _, c := range o.configurationFilePaths { + if slices.Contains(m.Configurations, c) { + log.Printf("configuration %s already in kustomization file", c) + continue + } + m.Configurations = append(m.Configurations, c) + } + if err := mf.Write(m); err != nil { + return fmt.Errorf("write kustomization: %w", err) + } + return nil +} diff --git a/kustomize/commands/edit/add/addconfiguration_test.go b/kustomize/commands/edit/add/addconfiguration_test.go new file mode 100644 index 000000000..57fcfbf93 --- /dev/null +++ b/kustomize/commands/edit/add/addconfiguration_test.go @@ -0,0 +1,78 @@ +// Copyright 2025 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package add + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + testutils_test "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/testutils" + "sigs.k8s.io/kustomize/kyaml/filesys" +) + +func TestAddConfiguration(t *testing.T) { + fSys := filesys.MakeEmptyDirInMemory() + testutils_test.WriteTestKustomization(fSys) + + cmd := newCmdAddConfiguration(fSys) + + if cmd == nil { + t.Fatal("Expected cmd to not be nil") + } + + if cmd.Use != "configuration" { + t.Fatalf("Expected Use to be 'configuration', got '%s'", cmd.Use) + } + + if cmd.Short == "" { + t.Fatal("Expected Short to not be empty") + } +} + +func TestAddConfigurationHappyPath(t *testing.T) { + fSys := filesys.MakeEmptyDirInMemory() + err := fSys.WriteFile("config1.yaml", []byte("apiVersion: v1\nkind: Config")) + require.NoError(t, err) + err = fSys.WriteFile("config2.yaml", []byte("apiVersion: v1\nkind: Config")) + require.NoError(t, err) + testutils_test.WriteTestKustomization(fSys) + + cmd := newCmdAddConfiguration(fSys) + args := []string{"config1.yaml", "config2.yaml"} + require.NoError(t, cmd.RunE(cmd, args)) + + content, err := testutils_test.ReadTestKustomization(fSys) + require.NoError(t, err) + assert.Contains(t, string(content), "config1.yaml") + assert.Contains(t, string(content), "config2.yaml") +} + +func TestAddConfigurationDuplicate(t *testing.T) { + fSys := filesys.MakeEmptyDirInMemory() + err := fSys.WriteFile("config.yaml", []byte("apiVersion: v1\nkind: Config")) + require.NoError(t, err) + testutils_test.WriteTestKustomization(fSys) + + cmd := newCmdAddConfiguration(fSys) + + // First addition + args := []string{"config.yaml"} + require.NoError(t, cmd.RunE(cmd, args)) + + content, err := testutils_test.ReadTestKustomization(fSys) + require.NoError(t, err) + assert.Contains(t, string(content), "config.yaml") + + // Second addition (should skip duplicate) + require.NoError(t, cmd.RunE(cmd, args)) + + content, err = testutils_test.ReadTestKustomization(fSys) + require.NoError(t, err) + + // Count occurrences - should only appear once + count := strings.Count(string(content), "config.yaml") + assert.Equal(t, 1, count, "config.yaml should appear exactly once") +} diff --git a/kustomize/commands/edit/add/all.go b/kustomize/commands/edit/add/all.go index 01dded508..31886de9b 100644 --- a/kustomize/commands/edit/add/all.go +++ b/kustomize/commands/edit/add/all.go @@ -47,6 +47,12 @@ func NewCmdAdd( # Adds a transformer configuration to the kustomization kustomize edit add transformer + + # Adds a configuration file to the kustomization + kustomize edit add configuration + + # Adds a generator configuration to the kustomization + kustomize edit add generator `, Args: cobra.MinimumNArgs(1), } @@ -61,6 +67,7 @@ func NewCmdAdd( newCmdAddLabel(fSys, ldr.Validator().MakeLabelValidator()), newCmdAddAnnotation(fSys, ldr.Validator().MakeAnnotationValidator()), newCmdAddTransformer(fSys), + newCmdAddConfiguration(fSys), newCmdAddGenerator(fSys), ) return c