Skip to content
Open
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
79 changes: 79 additions & 0 deletions kustomize/commands/edit/add/addconfiguration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2025 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package add

import (
"errors"
"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 <filepath>

# Adds multiple configuration files
kustomize edit add configuration <filepath1>,<filepath2>`,
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)
return err
}

// 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 err
}
m, err := mf.Read()
if err != nil {
return 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)
}
return mf.Write(m)
}
92 changes: 92 additions & 0 deletions kustomize/commands/edit/add/addconfiguration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2025 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package add

import (
"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 := 0
data := string(content)
for i := 0; i < len(data); {
if idx := len(data[i:]); idx > 0 {
if len(data) >= i+11 {
if data[i:i+11] == "config.yaml" {
count++
i += 11
} else {
i++
}
} else {
break
}
}
}
assert.Equal(t, 1, count, "config.yaml should appear exactly once")
}
7 changes: 7 additions & 0 deletions kustomize/commands/edit/add/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ func NewCmdAdd(

# Adds a transformer configuration to the kustomization
kustomize edit add transformer <filepath>

# Adds a configuration file to the kustomization
kustomize edit add configuration <filepath>

# Adds a generator configuration to the kustomization
kustomize edit add generator <filepath>
`,
Args: cobra.MinimumNArgs(1),
}
Expand All @@ -61,6 +67,7 @@ func NewCmdAdd(
newCmdAddLabel(fSys, ldr.Validator().MakeLabelValidator()),
newCmdAddAnnotation(fSys, ldr.Validator().MakeAnnotationValidator()),
newCmdAddTransformer(fSys),
newCmdAddConfiguration(fSys),
newCmdAddGenerator(fSys),
)
return c
Expand Down