mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
feat(commands/edit/add): add support for 'kustomize edit add configuration' command
Add a new subcommand 'kustomize edit add configuration' to programmatically add configuration file references to kustomization.yaml files. This brings configurations support in line with other 'kustomize edit add' subcommands (generators, transformers, validators). Features: - Support for single and multiple configuration file paths - Glob pattern expansion (e.g., ./configs/*.yaml) - Duplicate detection with user logging - Idempotent operation Related to https://github.com/kubernetes-sigs/kustomize/issues/5987
This commit is contained in:
86
kustomize/commands/edit/add/addconfiguration.go
Normal file
86
kustomize/commands/edit/add/addconfiguration.go
Normal file
@@ -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 <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)
|
||||||
|
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
|
||||||
|
}
|
||||||
78
kustomize/commands/edit/add/addconfiguration_test.go
Normal file
78
kustomize/commands/edit/add/addconfiguration_test.go
Normal file
@@ -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")
|
||||||
|
}
|
||||||
@@ -47,6 +47,12 @@ func NewCmdAdd(
|
|||||||
|
|
||||||
# Adds a transformer configuration to the kustomization
|
# Adds a transformer configuration to the kustomization
|
||||||
kustomize edit add transformer <filepath>
|
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),
|
Args: cobra.MinimumNArgs(1),
|
||||||
}
|
}
|
||||||
@@ -61,6 +67,7 @@ func NewCmdAdd(
|
|||||||
newCmdAddLabel(fSys, ldr.Validator().MakeLabelValidator()),
|
newCmdAddLabel(fSys, ldr.Validator().MakeLabelValidator()),
|
||||||
newCmdAddAnnotation(fSys, ldr.Validator().MakeAnnotationValidator()),
|
newCmdAddAnnotation(fSys, ldr.Validator().MakeAnnotationValidator()),
|
||||||
newCmdAddTransformer(fSys),
|
newCmdAddTransformer(fSys),
|
||||||
|
newCmdAddConfiguration(fSys),
|
||||||
newCmdAddGenerator(fSys),
|
newCmdAddGenerator(fSys),
|
||||||
)
|
)
|
||||||
return c
|
return c
|
||||||
|
|||||||
Reference in New Issue
Block a user