Add flag registry for CLI commands
Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
		
							parent
							
								
									8067504097
								
							
						
					
					
						commit
						6b587e15f0
					
				|  | @ -0,0 +1,77 @@ | ||||||
|  | # Flags Package | ||||||
|  | 
 | ||||||
|  | ## Overview | ||||||
|  | 
 | ||||||
|  | The `pkg/flags` package provides utilities for registering, handling, and transferring command-line flags. It serves as the bridge between the command-line interface and the configuration options. | ||||||
|  | 
 | ||||||
|  | ## File Structure | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | pkg/flags/ | ||||||
|  | ├── README.md             # This documentation file | ||||||
|  | ├── registry.go           # Core interface and generic implementation | ||||||
|  | ├── registry_mock.go      # Mock implementation for testing | ||||||
|  | ├── registry_diff.go      # Diff-specific registry | ||||||
|  | ├── registry_apply.go     # Apply-specific registry | ||||||
|  | ├── registry_sync.go      # Sync-specific registry | ||||||
|  | ├── registry_template.go  # Template-specific registry | ||||||
|  | ├── registry_lint.go      # Lint-specific registry | ||||||
|  | ├── registry_destroy.go   # Destroy-specific registry | ||||||
|  | ├── registry_fetch.go     # Fetch-specific registry | ||||||
|  | ├── registry_list.go      # List-specific registry | ||||||
|  | ├── registry_status.go    # Status-specific registry | ||||||
|  | ├── registry_test.go      # Tests for registry implementation | ||||||
|  | ├── flag_handler.go       # FlagHandler interface | ||||||
|  | ├── flag_handler_mock.go  # Mock implementation of FlagHandler | ||||||
|  | ├── flag_handler_test.go  # Tests for flag handler implementations | ||||||
|  | ├── flag_value.go         # Generic flag value retrieval functions | ||||||
|  | └── flag_value_test.go    # Tests for flag value functions | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Components | ||||||
|  | 
 | ||||||
|  | - **FlagHandler Interface**: Defines how components handle flag values with boolean return for success | ||||||
|  | - **FlagRegistry**: Manages flag registration and transfer | ||||||
|  | - **Command-specific Registries**: Specialized registries for each command | ||||||
|  | - **Helper Functions**: Utilities for getting flag values of different types | ||||||
|  | 
 | ||||||
|  | ## Key Features | ||||||
|  | 
 | ||||||
|  | - **Type Safety**: Helper functions for safely retrieving typed flag values | ||||||
|  | - **Flag Registration**: Centralized registration of flags to command objects | ||||||
|  | - **Flag Transfer**: Mechanism to transfer flag values to option objects | ||||||
|  | - **Flag Existence Checking**: Methods to check if flags are registered or handled | ||||||
|  | - **Success Indication**: Boolean return values to indicate if flags were successfully handled | ||||||
|  | 
 | ||||||
|  | ## Usage | ||||||
|  | 
 | ||||||
|  | ```go | ||||||
|  | // Create a registry | ||||||
|  | registry := flags.NewGenericFlagRegistry() | ||||||
|  | 
 | ||||||
|  | // Register flags to a command | ||||||
|  | registry.RegisterFlags(cmd) | ||||||
|  | 
 | ||||||
|  | // Transfer flags to options | ||||||
|  | registry.TransferFlags(cmd, opts) | ||||||
|  | 
 | ||||||
|  | // Check if a flag is registered | ||||||
|  | if registry.IsFlagRegistered("my-flag") { | ||||||
|  |     // Do something | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Handle a flag with success indication | ||||||
|  | handled := opts.HandleFlag("flag-name", value, changed) | ||||||
|  | if !handled { | ||||||
|  |     // Flag wasn't recognized | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Testing | ||||||
|  | 
 | ||||||
|  | The package includes mock implementations for testing: | ||||||
|  | 
 | ||||||
|  | - `MockFlagHandler`: For testing flag handling logic | ||||||
|  | - `MockFlagRegistry`: For testing flag registration and transfer | ||||||
|  | 
 | ||||||
|  | These mocks can be used to verify flag handling behavior without needing real command objects. | ||||||
|  | @ -1,49 +0,0 @@ | ||||||
| package flags |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"github.com/spf13/cobra" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // FlagRegistrar defines an interface for registering and transferring flags
 |  | ||||||
| type FlagRegistrar interface { |  | ||||||
| 	RegisterFlags(cmd *cobra.Command) |  | ||||||
| 	TransferFlags(cmd *cobra.Command, opts interface{}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // FlagHandler is a generic interface for handling flag values
 |  | ||||||
| type FlagHandler interface { |  | ||||||
| 	// HandleFlag receives a flag name, value, and whether it was changed
 |  | ||||||
| 	HandleFlag(name string, value interface{}, changed bool) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GenericFlagRegistrar is a base struct for flag registrars
 |  | ||||||
| type GenericFlagRegistrar struct { |  | ||||||
| 	// Map of flag names to their values
 |  | ||||||
| 	values map[string]interface{} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // NewGenericFlagRegistrar creates a new GenericFlagRegistrar
 |  | ||||||
| func NewGenericFlagRegistrar() *GenericFlagRegistrar { |  | ||||||
| 	return &GenericFlagRegistrar{ |  | ||||||
| 		values: make(map[string]interface{}), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // TransferFlags transfers all registered flags to the options
 |  | ||||||
| func (r *GenericFlagRegistrar) TransferFlags(cmd *cobra.Command, opts interface{}) { |  | ||||||
| 	if handler, ok := opts.(FlagHandler); ok { |  | ||||||
| 		flags := cmd.Flags() |  | ||||||
| 
 |  | ||||||
| 		// Transfer each registered flag
 |  | ||||||
| 		for name, value := range r.values { |  | ||||||
| 			changed := flags.Changed(name) |  | ||||||
| 			handler.HandleFlag(name, value, changed) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // RegisterBoolFlag registers a boolean flag and stores its reference
 |  | ||||||
| func (r *GenericFlagRegistrar) RegisterBoolFlag(cmd *cobra.Command, name string, value *bool, defaultValue bool, usage string) { |  | ||||||
| 	cmd.Flags().BoolVar(value, name, defaultValue, usage) |  | ||||||
| 	r.values[name] = value |  | ||||||
| } |  | ||||||
|  | @ -1,140 +0,0 @@ | ||||||
| package flags |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"testing" |  | ||||||
| 
 |  | ||||||
| 	"github.com/spf13/cobra" |  | ||||||
| 	"github.com/stretchr/testify/assert" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // MockFlagHandler implements FlagHandler for testing
 |  | ||||||
| type MockFlagHandler struct { |  | ||||||
| 	handledFlags map[string]interface{} |  | ||||||
| 	changedFlags map[string]bool |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func NewMockFlagHandler() *MockFlagHandler { |  | ||||||
| 	return &MockFlagHandler{ |  | ||||||
| 		handledFlags: make(map[string]interface{}), |  | ||||||
| 		changedFlags: make(map[string]bool), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (h *MockFlagHandler) HandleFlag(name string, value interface{}, changed bool) { |  | ||||||
| 	h.handledFlags[name] = value |  | ||||||
| 	h.changedFlags[name] = changed |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestNewGenericFlagRegistrar(t *testing.T) { |  | ||||||
| 	registrar := NewGenericFlagRegistrar() |  | ||||||
| 	assert.NotNil(t, registrar) |  | ||||||
| 	assert.NotNil(t, registrar.values) |  | ||||||
| 	assert.Len(t, registrar.values, 0) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestGenericFlagRegistrar_RegisterBoolFlag(t *testing.T) { |  | ||||||
| 	registrar := NewGenericFlagRegistrar() |  | ||||||
| 	cmd := &cobra.Command{Use: "test"} |  | ||||||
| 
 |  | ||||||
| 	var testFlag bool |  | ||||||
| 	registrar.RegisterBoolFlag(cmd, "test-flag", &testFlag, false, "Test flag") |  | ||||||
| 
 |  | ||||||
| 	// Verify the flag was registered
 |  | ||||||
| 	flag := cmd.Flags().Lookup("test-flag") |  | ||||||
| 	assert.NotNil(t, flag) |  | ||||||
| 	assert.Equal(t, "test-flag", flag.Name) |  | ||||||
| 	assert.Equal(t, "false", flag.DefValue) |  | ||||||
| 	assert.Equal(t, "Test flag", flag.Usage) |  | ||||||
| 
 |  | ||||||
| 	// Verify the value was stored in the registrar
 |  | ||||||
| 	value, exists := registrar.values["test-flag"] |  | ||||||
| 	assert.True(t, exists) |  | ||||||
| 	assert.Equal(t, &testFlag, value) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestGenericFlagRegistrar_TransferFlags_NoChanges(t *testing.T) { |  | ||||||
| 	registrar := NewGenericFlagRegistrar() |  | ||||||
| 	cmd := &cobra.Command{Use: "test"} |  | ||||||
| 
 |  | ||||||
| 	var testFlag bool |  | ||||||
| 	registrar.RegisterBoolFlag(cmd, "test-flag", &testFlag, false, "Test flag") |  | ||||||
| 
 |  | ||||||
| 	// Create a mock handler
 |  | ||||||
| 	handler := NewMockFlagHandler() |  | ||||||
| 
 |  | ||||||
| 	// Transfer flags (none changed)
 |  | ||||||
| 	registrar.TransferFlags(cmd, handler) |  | ||||||
| 
 |  | ||||||
| 	// Verify the handler was called with the right parameters
 |  | ||||||
| 	assert.Equal(t, &testFlag, handler.handledFlags["test-flag"]) |  | ||||||
| 	assert.False(t, handler.changedFlags["test-flag"]) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestGenericFlagRegistrar_TransferFlags_WithChanges(t *testing.T) { |  | ||||||
| 	registrar := NewGenericFlagRegistrar() |  | ||||||
| 	cmd := &cobra.Command{Use: "test"} |  | ||||||
| 
 |  | ||||||
| 	var testFlag bool |  | ||||||
| 	registrar.RegisterBoolFlag(cmd, "test-flag", &testFlag, false, "Test flag") |  | ||||||
| 
 |  | ||||||
| 	// Simulate flag being set on command line
 |  | ||||||
| 	err := cmd.Flags().Set("test-flag", "true") |  | ||||||
| 	assert.NoError(t, err) |  | ||||||
| 	testFlag = true // Value would be updated by cobra
 |  | ||||||
| 
 |  | ||||||
| 	// Create a mock handler
 |  | ||||||
| 	handler := NewMockFlagHandler() |  | ||||||
| 
 |  | ||||||
| 	// Transfer flags (with changes)
 |  | ||||||
| 	registrar.TransferFlags(cmd, handler) |  | ||||||
| 
 |  | ||||||
| 	// Verify the handler was called with the right parameters
 |  | ||||||
| 	assert.Equal(t, &testFlag, handler.handledFlags["test-flag"]) |  | ||||||
| 	assert.True(t, handler.changedFlags["test-flag"]) |  | ||||||
| 	assert.True(t, *handler.handledFlags["test-flag"].(*bool)) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestGenericFlagRegistrar_TransferFlags_NonHandler(t *testing.T) { |  | ||||||
| 	registrar := NewGenericFlagRegistrar() |  | ||||||
| 	cmd := &cobra.Command{Use: "test"} |  | ||||||
| 
 |  | ||||||
| 	var testFlag bool |  | ||||||
| 	registrar.RegisterBoolFlag(cmd, "test-flag", &testFlag, false, "Test flag") |  | ||||||
| 
 |  | ||||||
| 	// Use a non-handler type
 |  | ||||||
| 	nonHandler := struct{}{} |  | ||||||
| 
 |  | ||||||
| 	// This should not panic
 |  | ||||||
| 	registrar.TransferFlags(cmd, nonHandler) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestGenericFlagRegistrar_MultipleFlags(t *testing.T) { |  | ||||||
| 	registrar := NewGenericFlagRegistrar() |  | ||||||
| 	cmd := &cobra.Command{Use: "test"} |  | ||||||
| 
 |  | ||||||
| 	var boolFlag bool |  | ||||||
| 	var boolFlag2 bool |  | ||||||
| 
 |  | ||||||
| 	registrar.RegisterBoolFlag(cmd, "bool-flag", &boolFlag, false, "Boolean flag") |  | ||||||
| 	registrar.RegisterBoolFlag(cmd, "bool-flag2", &boolFlag2, true, "Another boolean flag") |  | ||||||
| 
 |  | ||||||
| 	// Set one flag
 |  | ||||||
| 	err := cmd.Flags().Set("bool-flag", "true") |  | ||||||
| 	assert.NoError(t, err) |  | ||||||
| 	boolFlag = true // Value would be updated by cobra
 |  | ||||||
| 
 |  | ||||||
| 	// Create a mock handler
 |  | ||||||
| 	handler := NewMockFlagHandler() |  | ||||||
| 
 |  | ||||||
| 	// Transfer flags
 |  | ||||||
| 	registrar.TransferFlags(cmd, handler) |  | ||||||
| 
 |  | ||||||
| 	// Verify both flags were handled correctly
 |  | ||||||
| 	assert.Equal(t, &boolFlag, handler.handledFlags["bool-flag"]) |  | ||||||
| 	assert.True(t, handler.changedFlags["bool-flag"]) |  | ||||||
| 	assert.True(t, *handler.handledFlags["bool-flag"].(*bool)) |  | ||||||
| 
 |  | ||||||
| 	assert.Equal(t, &boolFlag2, handler.handledFlags["bool-flag2"]) |  | ||||||
| 	assert.False(t, handler.changedFlags["bool-flag2"]) |  | ||||||
| 	assert.True(t, *handler.handledFlags["bool-flag2"].(*bool)) // Default is true
 |  | ||||||
| } |  | ||||||
|  | @ -1,22 +0,0 @@ | ||||||
| package flags |  | ||||||
| 
 |  | ||||||
| import "github.com/spf13/cobra" |  | ||||||
| 
 |  | ||||||
| // DiffFlagRegistrar handles flags specific to the diff command
 |  | ||||||
| type DiffFlagRegistrar struct { |  | ||||||
| 	*GenericFlagRegistrar |  | ||||||
| 	IncludeCRDs bool |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // NewDiffFlagRegistrar creates a new DiffFlagRegistrar
 |  | ||||||
| func NewDiffFlagRegistrar() *DiffFlagRegistrar { |  | ||||||
| 	return &DiffFlagRegistrar{ |  | ||||||
| 		GenericFlagRegistrar: NewGenericFlagRegistrar(), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // RegisterFlags registers diff-specific flags
 |  | ||||||
| func (r *DiffFlagRegistrar) RegisterFlags(cmd *cobra.Command) { |  | ||||||
| 	r.RegisterBoolFlag(cmd, "include-crds", &r.IncludeCRDs, false, "include CRDs in the diffing") |  | ||||||
| 	// Diff doesn't have skip-crds
 |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,8 @@ | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | // FlagHandler is a generic interface for handling flag values
 | ||||||
|  | type FlagHandler interface { | ||||||
|  | 	// HandleFlag receives a flag name, value, and whether it was changed
 | ||||||
|  | 	// Returns true if the flag was handled, false otherwise
 | ||||||
|  | 	HandleFlag(name string, value interface{}, changed bool) bool | ||||||
|  | } | ||||||
|  | @ -0,0 +1,20 @@ | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | // MockFlagHandler implements FlagHandler for testing
 | ||||||
|  | type MockFlagHandler struct { | ||||||
|  | 	handledFlags map[string]interface{} | ||||||
|  | 	changedFlags map[string]bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func NewMockFlagHandler() *MockFlagHandler { | ||||||
|  | 	return &MockFlagHandler{ | ||||||
|  | 		handledFlags: make(map[string]interface{}), | ||||||
|  | 		changedFlags: make(map[string]bool), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (h *MockFlagHandler) HandleFlag(name string, value interface{}, changed bool) bool { | ||||||
|  | 	h.handledFlags[name] = value | ||||||
|  | 	h.changedFlags[name] = changed | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | @ -0,0 +1,51 @@ | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestMockFlagHandler_HandleFlag_ReturnValue(t *testing.T) { | ||||||
|  | 	// Create a mock handler
 | ||||||
|  | 	mockHandler := NewMockFlagHandler() | ||||||
|  | 
 | ||||||
|  | 	// Test that it returns true for any flag
 | ||||||
|  | 	result := mockHandler.HandleFlag("test-flag", true, false) | ||||||
|  | 	assert.True(t, result, "MockHandler should return true for any flag") | ||||||
|  | 
 | ||||||
|  | 	// Test with multiple flags
 | ||||||
|  | 	result = mockHandler.HandleFlag("another-flag", "value", true) | ||||||
|  | 	assert.True(t, result, "MockHandler should return true for any flag") | ||||||
|  | 
 | ||||||
|  | 	// Verify the flags were stored correctly
 | ||||||
|  | 	assert.Equal(t, true, mockHandler.handledFlags["test-flag"]) | ||||||
|  | 	assert.Equal(t, "value", mockHandler.handledFlags["another-flag"]) | ||||||
|  | 	assert.Equal(t, false, mockHandler.changedFlags["test-flag"]) | ||||||
|  | 	assert.Equal(t, true, mockHandler.changedFlags["another-flag"]) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // CustomFlagHandler implements FlagHandler for testing specific return values
 | ||||||
|  | type CustomFlagHandler struct{} | ||||||
|  | 
 | ||||||
|  | func (h *CustomFlagHandler) HandleFlag(name string, value interface{}, changed bool) bool { | ||||||
|  | 	// Only handle specific flags
 | ||||||
|  | 	switch name { | ||||||
|  | 	case "known-flag": | ||||||
|  | 		return true | ||||||
|  | 	default: | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestCustomFlagHandler_HandleFlag_ReturnValue(t *testing.T) { | ||||||
|  | 	handler := &CustomFlagHandler{} | ||||||
|  | 
 | ||||||
|  | 	// Test with a recognized flag
 | ||||||
|  | 	result := handler.HandleFlag("known-flag", true, false) | ||||||
|  | 	assert.True(t, result, "Should return true for recognized flag") | ||||||
|  | 
 | ||||||
|  | 	// Test with an unrecognized flag
 | ||||||
|  | 	result = handler.HandleFlag("unknown-flag", true, false) | ||||||
|  | 	assert.False(t, result, "Should return false for unrecognized flag") | ||||||
|  | } | ||||||
|  | @ -0,0 +1,43 @@ | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | // GetFlagValue is a generic function to get flag values with type safety
 | ||||||
|  | func GetFlagValue[T any](registry FlagRegistry, name string) (T, bool) { | ||||||
|  | 	var zero T | ||||||
|  | 	values := registry.GetValues() | ||||||
|  | 	if value, exists := values[name]; exists { | ||||||
|  | 		if typedValue, ok := value.(*T); ok { | ||||||
|  | 			return *typedValue, true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return zero, false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetBoolFlagValue is a convenience function to get a boolean flag value
 | ||||||
|  | func GetBoolFlagValue(registry FlagRegistry, name string) (bool, bool) { | ||||||
|  | 	return GetFlagValue[bool](registry, name) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetStringFlagValue is a convenience function to get a string flag value
 | ||||||
|  | func GetStringFlagValue(registry FlagRegistry, name string) (string, bool) { | ||||||
|  | 	return GetFlagValue[string](registry, name) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetStringSliceFlagValue is a convenience function to get a string slice flag value
 | ||||||
|  | func GetStringSliceFlagValue(registry FlagRegistry, name string) ([]string, bool) { | ||||||
|  | 	return GetFlagValue[[]string](registry, name) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetIntFlagValue is a convenience function to get an integer flag value
 | ||||||
|  | func GetIntFlagValue(registry FlagRegistry, name string) (int, bool) { | ||||||
|  | 	return GetFlagValue[int](registry, name) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetInt64FlagValue is a convenience function to get an int64 flag value
 | ||||||
|  | func GetInt64FlagValue(registry FlagRegistry, name string) (int64, bool) { | ||||||
|  | 	return GetFlagValue[int64](registry, name) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetFloat64FlagValue is a convenience function to get a float64 flag value
 | ||||||
|  | func GetFloat64FlagValue(registry FlagRegistry, name string) (float64, bool) { | ||||||
|  | 	return GetFlagValue[float64](registry, name) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,220 @@ | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestGetFlagValue(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 
 | ||||||
|  | 	// Register some test flags
 | ||||||
|  | 	boolValue := false | ||||||
|  | 	registry.values["bool-flag"] = &boolValue | ||||||
|  | 
 | ||||||
|  | 	stringValue := "test" | ||||||
|  | 	registry.values["string-flag"] = &stringValue | ||||||
|  | 
 | ||||||
|  | 	stringSliceValue := []string{"one", "two", "three"} | ||||||
|  | 	registry.values["string-slice-flag"] = &stringSliceValue | ||||||
|  | 
 | ||||||
|  | 	intValue := 42 | ||||||
|  | 	registry.values["int-flag"] = &intValue | ||||||
|  | 
 | ||||||
|  | 	// Test getting boolean flag
 | ||||||
|  | 	gotBool, exists := GetFlagValue[bool](registry, "bool-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, false, gotBool) | ||||||
|  | 
 | ||||||
|  | 	// Test getting string flag
 | ||||||
|  | 	gotString, exists := GetFlagValue[string](registry, "string-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, "test", gotString) | ||||||
|  | 
 | ||||||
|  | 	// Test getting string slice flag
 | ||||||
|  | 	gotStringSlice, exists := GetFlagValue[[]string](registry, "string-slice-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, []string{"one", "two", "three"}, gotStringSlice) | ||||||
|  | 
 | ||||||
|  | 	// Test getting int flag
 | ||||||
|  | 	gotInt, exists := GetFlagValue[int](registry, "int-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, 42, gotInt) | ||||||
|  | 
 | ||||||
|  | 	// Test getting non-existent flag
 | ||||||
|  | 	_, exists = GetFlagValue[bool](registry, "non-existent") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | 
 | ||||||
|  | 	// Test getting flag with wrong type
 | ||||||
|  | 	_, exists = GetFlagValue[string](registry, "bool-flag") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGetBoolFlagValue(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 
 | ||||||
|  | 	// Register a boolean flag
 | ||||||
|  | 	boolValue := false | ||||||
|  | 	registry.values["bool-flag"] = &boolValue | ||||||
|  | 
 | ||||||
|  | 	// Test getting the flag value
 | ||||||
|  | 	value, exists := GetBoolFlagValue(registry, "bool-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.False(t, value) | ||||||
|  | 
 | ||||||
|  | 	// Change the value
 | ||||||
|  | 	*registry.values["bool-flag"].(*bool) = true | ||||||
|  | 
 | ||||||
|  | 	// Test getting the updated value
 | ||||||
|  | 	value, exists = GetBoolFlagValue(registry, "bool-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.True(t, value) | ||||||
|  | 
 | ||||||
|  | 	// Test getting a non-existent flag
 | ||||||
|  | 	value, exists = GetBoolFlagValue(registry, "non-existent") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | 	assert.False(t, value) // Default value for bool
 | ||||||
|  | 
 | ||||||
|  | 	// Test getting a flag with wrong type
 | ||||||
|  | 	stringValue := "test" | ||||||
|  | 	registry.values["string-flag"] = &stringValue | ||||||
|  | 	value, exists = GetBoolFlagValue(registry, "string-flag") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | 	assert.False(t, value) // Default value for bool
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGetStringFlagValue(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 
 | ||||||
|  | 	// Register a string flag
 | ||||||
|  | 	stringValue := "test" | ||||||
|  | 	registry.values["string-flag"] = &stringValue | ||||||
|  | 
 | ||||||
|  | 	// Test getting the flag value
 | ||||||
|  | 	value, exists := GetStringFlagValue(registry, "string-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, "test", value) | ||||||
|  | 
 | ||||||
|  | 	// Change the value
 | ||||||
|  | 	*registry.values["string-flag"].(*string) = "updated" | ||||||
|  | 
 | ||||||
|  | 	// Test getting the updated value
 | ||||||
|  | 	value, exists = GetStringFlagValue(registry, "string-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, "updated", value) | ||||||
|  | 
 | ||||||
|  | 	// Test getting a non-existent flag
 | ||||||
|  | 	value, exists = GetStringFlagValue(registry, "non-existent") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | 	assert.Equal(t, "", value) // Default value for string
 | ||||||
|  | 
 | ||||||
|  | 	// Test getting a flag with wrong type
 | ||||||
|  | 	boolValue := true | ||||||
|  | 	registry.values["bool-flag"] = &boolValue | ||||||
|  | 	value, exists = GetStringFlagValue(registry, "bool-flag") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | 	assert.Equal(t, "", value) // Default value for string
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGetStringSliceFlagValue(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 
 | ||||||
|  | 	// Register a string slice flag
 | ||||||
|  | 	sliceValue := []string{"one", "two", "three"} | ||||||
|  | 	registry.values["slice-flag"] = &sliceValue | ||||||
|  | 
 | ||||||
|  | 	// Test getting the flag value
 | ||||||
|  | 	value, exists := GetStringSliceFlagValue(registry, "slice-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, []string{"one", "two", "three"}, value) | ||||||
|  | 
 | ||||||
|  | 	// Change the value
 | ||||||
|  | 	*registry.values["slice-flag"].(*[]string) = []string{"updated"} | ||||||
|  | 
 | ||||||
|  | 	// Test getting the updated value
 | ||||||
|  | 	value, exists = GetStringSliceFlagValue(registry, "slice-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, []string{"updated"}, value) | ||||||
|  | 
 | ||||||
|  | 	// Test getting a non-existent flag
 | ||||||
|  | 	value, exists = GetStringSliceFlagValue(registry, "non-existent") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | 	assert.Nil(t, value) // Default value for slice
 | ||||||
|  | 
 | ||||||
|  | 	// Test getting a flag with wrong type
 | ||||||
|  | 	boolValue := true | ||||||
|  | 	registry.values["bool-flag"] = &boolValue | ||||||
|  | 	value, exists = GetStringSliceFlagValue(registry, "bool-flag") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | 	assert.Nil(t, value) // Default value for slice
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGetIntFlagValue(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 
 | ||||||
|  | 	// Register an int flag
 | ||||||
|  | 	intValue := 42 | ||||||
|  | 	registry.values["int-flag"] = &intValue | ||||||
|  | 
 | ||||||
|  | 	// Test getting the flag value
 | ||||||
|  | 	value, exists := GetIntFlagValue(registry, "int-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, 42, value) | ||||||
|  | 
 | ||||||
|  | 	// Change the value
 | ||||||
|  | 	*registry.values["int-flag"].(*int) = 100 | ||||||
|  | 
 | ||||||
|  | 	// Test getting the updated value
 | ||||||
|  | 	value, exists = GetIntFlagValue(registry, "int-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, 100, value) | ||||||
|  | 
 | ||||||
|  | 	// Test getting a non-existent flag
 | ||||||
|  | 	value, exists = GetIntFlagValue(registry, "non-existent") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | 	assert.Equal(t, 0, value) // Default value for int
 | ||||||
|  | 
 | ||||||
|  | 	// Test getting a flag with wrong type
 | ||||||
|  | 	boolValue := true | ||||||
|  | 	registry.values["bool-flag"] = &boolValue | ||||||
|  | 	value, exists = GetIntFlagValue(registry, "bool-flag") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | 	assert.Equal(t, 0, value) // Default value for int
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGetInt64FlagValue(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 
 | ||||||
|  | 	// Register an int64 flag
 | ||||||
|  | 	int64Value := int64(42) | ||||||
|  | 	registry.values["int64-flag"] = &int64Value | ||||||
|  | 
 | ||||||
|  | 	// Test getting the flag value
 | ||||||
|  | 	value, exists := GetInt64FlagValue(registry, "int64-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, int64(42), value) | ||||||
|  | 
 | ||||||
|  | 	// Test getting a non-existent flag
 | ||||||
|  | 	value, exists = GetInt64FlagValue(registry, "non-existent") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | 	assert.Equal(t, int64(0), value) // Default value for int64
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGetFloat64FlagValue(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 
 | ||||||
|  | 	// Register a float64 flag
 | ||||||
|  | 	float64Value := 3.14 | ||||||
|  | 	registry.values["float64-flag"] = &float64Value | ||||||
|  | 
 | ||||||
|  | 	// Test getting the flag value
 | ||||||
|  | 	value, exists := GetFloat64FlagValue(registry, "float64-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, 3.14, value) | ||||||
|  | 
 | ||||||
|  | 	// Test getting a non-existent flag
 | ||||||
|  | 	value, exists = GetFloat64FlagValue(registry, "non-existent") | ||||||
|  | 	assert.False(t, exists) | ||||||
|  | 	assert.Equal(t, 0.0, value) // Default value for float64
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,64 @@ | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | import "github.com/spf13/cobra" | ||||||
|  | 
 | ||||||
|  | // FlagRegistry defines an interface for registering and transferring flags
 | ||||||
|  | type FlagRegistry interface { | ||||||
|  | 	RegisterFlags(cmd *cobra.Command) | ||||||
|  | 	TransferFlags(cmd *cobra.Command, opts interface{}) | ||||||
|  | 	GetRegisteredFlagNames() []string | ||||||
|  | 	GetValues() map[string]interface{} | ||||||
|  | 	IsFlagRegistered(name string) bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GenericFlagRegistry is a base struct for flag registries
 | ||||||
|  | type GenericFlagRegistry struct { | ||||||
|  | 	// Map of flag names to their values
 | ||||||
|  | 	values map[string]interface{} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewGenericFlagRegistry creates a new GenericFlagRegistrar
 | ||||||
|  | func NewGenericFlagRegistry() *GenericFlagRegistry { | ||||||
|  | 	return &GenericFlagRegistry{ | ||||||
|  | 		values: make(map[string]interface{}), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetValues returns the internal values map
 | ||||||
|  | func (r *GenericFlagRegistry) GetValues() map[string]interface{} { | ||||||
|  | 	return r.values | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetRegisteredFlagNames returns the names of all registered flags
 | ||||||
|  | func (r *GenericFlagRegistry) GetRegisteredFlagNames() []string { | ||||||
|  | 	names := make([]string, 0, len(r.values)) | ||||||
|  | 	for name := range r.values { | ||||||
|  | 		names = append(names, name) | ||||||
|  | 	} | ||||||
|  | 	return names | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IsFlagRegistered checks if a flag is registered in the registry
 | ||||||
|  | func (r *GenericFlagRegistry) IsFlagRegistered(name string) bool { | ||||||
|  | 	_, exists := r.values[name] | ||||||
|  | 	return exists | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TransferFlags transfers all registered flags to the options
 | ||||||
|  | func (r *GenericFlagRegistry) TransferFlags(cmd *cobra.Command, opts interface{}) { | ||||||
|  | 	if handler, ok := opts.(FlagHandler); ok { | ||||||
|  | 		flags := cmd.Flags() | ||||||
|  | 
 | ||||||
|  | 		// Transfer each registered flag
 | ||||||
|  | 		for name, value := range r.values { | ||||||
|  | 			changed := flags.Changed(name) | ||||||
|  | 			handler.HandleFlag(name, value, changed) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // RegisterBoolFlag registers a boolean flag and stores its reference
 | ||||||
|  | func (r *GenericFlagRegistry) RegisterBoolFlag(cmd *cobra.Command, name string, value *bool, defaultValue bool, usage string) { | ||||||
|  | 	cmd.Flags().BoolVar(value, name, defaultValue, usage) | ||||||
|  | 	r.values[name] = value | ||||||
|  | } | ||||||
|  | @ -2,22 +2,22 @@ package flags | ||||||
| 
 | 
 | ||||||
| import "github.com/spf13/cobra" | import "github.com/spf13/cobra" | ||||||
| 
 | 
 | ||||||
| // ApplyFlagRegistrar handles flags specific to the apply command
 | // ApplyFlagRegistry handles flags specific to the apply command
 | ||||||
| type ApplyFlagRegistrar struct { | type ApplyFlagRegistry struct { | ||||||
| 	*GenericFlagRegistrar | 	*GenericFlagRegistry | ||||||
| 	IncludeCRDs bool | 	IncludeCRDs bool | ||||||
| 	SkipCRDs    bool | 	SkipCRDs    bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewApplyFlagRegistrar creates a new ApplyFlagRegistrar
 | // NewApplyFlagRegistry creates a new ApplyFlagRegistry
 | ||||||
| func NewApplyFlagRegistrar() *ApplyFlagRegistrar { | func NewApplyFlagRegistry() *ApplyFlagRegistry { | ||||||
| 	return &ApplyFlagRegistrar{ | 	return &ApplyFlagRegistry{ | ||||||
| 		GenericFlagRegistrar: NewGenericFlagRegistrar(), | 		GenericFlagRegistry: NewGenericFlagRegistry(), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // RegisterFlags registers apply-specific flags
 | // RegisterFlags registers apply-specific flags
 | ||||||
| func (r *ApplyFlagRegistrar) RegisterFlags(cmd *cobra.Command) { | func (r *ApplyFlagRegistry) RegisterFlags(cmd *cobra.Command) { | ||||||
| 	r.RegisterBoolFlag(cmd, "include-crds", &r.IncludeCRDs, false, "include CRDs in the diffing") | 	r.RegisterBoolFlag(cmd, "include-crds", &r.IncludeCRDs, false, "include CRDs in the diffing") | ||||||
| 	r.RegisterBoolFlag(cmd, "skip-crds", &r.SkipCRDs, false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present") | 	r.RegisterBoolFlag(cmd, "skip-crds", &r.SkipCRDs, false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present") | ||||||
| } | } | ||||||
|  | @ -0,0 +1,22 @@ | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | import "github.com/spf13/cobra" | ||||||
|  | 
 | ||||||
|  | // DiffFlagRegistry handles flags specific to the diff command
 | ||||||
|  | type DiffFlagRegistry struct { | ||||||
|  | 	*GenericFlagRegistry | ||||||
|  | 	IncludeCRDs bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewDiffFlagRegistry creates a new DiffFlagRegistry
 | ||||||
|  | func NewDiffFlagRegistry() *DiffFlagRegistry { | ||||||
|  | 	return &DiffFlagRegistry{ | ||||||
|  | 		GenericFlagRegistry: NewGenericFlagRegistry(), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // RegisterFlags registers diff-specific flags
 | ||||||
|  | func (r *DiffFlagRegistry) RegisterFlags(cmd *cobra.Command) { | ||||||
|  | 	r.RegisterBoolFlag(cmd, "include-crds", &r.IncludeCRDs, false, "include CRDs in the diffing") | ||||||
|  | 	// Diff doesn't have skip-crds
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,27 @@ | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/spf13/cobra" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestDiffFlagRegisty(t *testing.T) { | ||||||
|  | 	registry := NewDiffFlagRegistry() | ||||||
|  | 
 | ||||||
|  | 	// Create a test command to register flags
 | ||||||
|  | 	cmd := &cobra.Command{Use: "test"} | ||||||
|  | 	registry.RegisterFlags(cmd) | ||||||
|  | 
 | ||||||
|  | 	// Get the names of registered flags
 | ||||||
|  | 	registeredFlags := registry.GetRegisteredFlagNames() | ||||||
|  | 
 | ||||||
|  | 	// Verify that include-crds and skip-crds are registered
 | ||||||
|  | 	assert.Contains(t, registeredFlags, "include-crds") | ||||||
|  | 
 | ||||||
|  | 	// Get and verify the default values using the generic function
 | ||||||
|  | 	includeCRDs, exists := GetFlagValue[bool](registry, "include-crds") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.False(t, includeCRDs) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,24 @@ | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | import "github.com/spf13/cobra" | ||||||
|  | 
 | ||||||
|  | // MockFlagRegistry implements FlagRegistrar for testing
 | ||||||
|  | type MockFlagRegistry struct { | ||||||
|  | 	*GenericFlagRegistry | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func NewMockFlagRegistry() *MockFlagRegistry { | ||||||
|  | 	return &MockFlagRegistry{ | ||||||
|  | 		GenericFlagRegistry: NewGenericFlagRegistry(), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // RegisterFlags implements the FlagRegistrar interface for testing
 | ||||||
|  | func (r *MockFlagRegistry) RegisterFlags(cmd *cobra.Command) { | ||||||
|  | 	// Mock implementation does nothing
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetValues returns the internal values map
 | ||||||
|  | func (r *MockFlagRegistry) GetValues() map[string]interface{} { | ||||||
|  | 	return r.values | ||||||
|  | } | ||||||
|  | @ -2,22 +2,22 @@ package flags | ||||||
| 
 | 
 | ||||||
| import "github.com/spf13/cobra" | import "github.com/spf13/cobra" | ||||||
| 
 | 
 | ||||||
| // SyncFlagRegistrar handles flags specific to the sync command
 | // SyncFlagRegistry handles flags specific to the sync command
 | ||||||
| type SyncFlagRegistrar struct { | type SyncFlagRegistry struct { | ||||||
| 	*GenericFlagRegistrar | 	*GenericFlagRegistry | ||||||
| 	IncludeCRDs bool | 	IncludeCRDs bool | ||||||
| 	SkipCRDs    bool | 	SkipCRDs    bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewSyncFlagRegistrar creates a new SyncFlagRegistrar
 | // NewSyncFlagRegistry creates a new SyncFlagRegistry
 | ||||||
| func NewSyncFlagRegistrar() *SyncFlagRegistrar { | func NewSyncFlagRegistry() *SyncFlagRegistry { | ||||||
| 	return &SyncFlagRegistrar{ | 	return &SyncFlagRegistry{ | ||||||
| 		GenericFlagRegistrar: NewGenericFlagRegistrar(), | 		GenericFlagRegistry: NewGenericFlagRegistry(), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // RegisterFlags registers sync-specific flags
 | // RegisterFlags registers sync-specific flags
 | ||||||
| func (r *SyncFlagRegistrar) RegisterFlags(cmd *cobra.Command) { | func (r *SyncFlagRegistry) RegisterFlags(cmd *cobra.Command) { | ||||||
| 	r.RegisterBoolFlag(cmd, "include-crds", &r.IncludeCRDs, false, "include CRDs in the diffing") | 	r.RegisterBoolFlag(cmd, "include-crds", &r.IncludeCRDs, false, "include CRDs in the diffing") | ||||||
| 	r.RegisterBoolFlag(cmd, "skip-crds", &r.SkipCRDs, false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present") | 	r.RegisterBoolFlag(cmd, "skip-crds", &r.SkipCRDs, false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present") | ||||||
| } | } | ||||||
|  | @ -0,0 +1,22 @@ | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | import "github.com/spf13/cobra" | ||||||
|  | 
 | ||||||
|  | // TemplateFlagRegistry handles flags specific to the template command
 | ||||||
|  | type TemplateFlagRegistry struct { | ||||||
|  | 	*GenericFlagRegistry | ||||||
|  | 	IncludeCRDs bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewTemplateFlagRegistry creates a new TemplateFlagRegistry
 | ||||||
|  | func NewTemplateFlagRegistry() *TemplateFlagRegistry { | ||||||
|  | 	return &TemplateFlagRegistry{ | ||||||
|  | 		GenericFlagRegistry: NewGenericFlagRegistry(), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // RegisterFlags registers template-specific flags
 | ||||||
|  | func (r *TemplateFlagRegistry) RegisterFlags(cmd *cobra.Command) { | ||||||
|  | 	r.RegisterBoolFlag(cmd, "include-crds", &r.IncludeCRDs, false, "include CRDs in the diffing") | ||||||
|  | 	// Template doesn't have skip-crds
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,176 @@ | ||||||
|  | package flags | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/spf13/cobra" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestNewGenericFlagRegistrar(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 	assert.NotNil(t, registry) | ||||||
|  | 	assert.NotNil(t, registry.values) | ||||||
|  | 	assert.Len(t, registry.values, 0) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGenericFlagRegistry_RegisterBoolFlag(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 	cmd := &cobra.Command{Use: "test"} | ||||||
|  | 
 | ||||||
|  | 	var testFlag bool | ||||||
|  | 	registry.RegisterBoolFlag(cmd, "test-flag", &testFlag, false, "Test flag") | ||||||
|  | 
 | ||||||
|  | 	// Verify the flag was registered
 | ||||||
|  | 	flag := cmd.Flags().Lookup("test-flag") | ||||||
|  | 	assert.NotNil(t, flag) | ||||||
|  | 	assert.Equal(t, "test-flag", flag.Name) | ||||||
|  | 	assert.Equal(t, "false", flag.DefValue) | ||||||
|  | 	assert.Equal(t, "Test flag", flag.Usage) | ||||||
|  | 
 | ||||||
|  | 	// Verify the value was stored in the registry
 | ||||||
|  | 	value, exists := registry.values["test-flag"] | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, &testFlag, value) | ||||||
|  | 
 | ||||||
|  | 	// Test the generic GetFlagValue function
 | ||||||
|  | 	flagValue, exists := GetFlagValue[bool](registry, "test-flag") | ||||||
|  | 	assert.True(t, exists) | ||||||
|  | 	assert.Equal(t, false, flagValue) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGenericFlagRegistry_TransferFlags_NoChanges(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 	cmd := &cobra.Command{Use: "test"} | ||||||
|  | 
 | ||||||
|  | 	var testFlag bool | ||||||
|  | 	registry.RegisterBoolFlag(cmd, "test-flag", &testFlag, false, "Test flag") | ||||||
|  | 
 | ||||||
|  | 	// Create a mock handler
 | ||||||
|  | 	handler := NewMockFlagHandler() | ||||||
|  | 
 | ||||||
|  | 	// Transfer flags (none changed)
 | ||||||
|  | 	registry.TransferFlags(cmd, handler) | ||||||
|  | 
 | ||||||
|  | 	// Verify the handler was called with the right parameters
 | ||||||
|  | 	assert.Equal(t, &testFlag, handler.handledFlags["test-flag"]) | ||||||
|  | 	assert.False(t, handler.changedFlags["test-flag"]) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGenericFlagRegistry_TransferFlags_WithChanges(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 	cmd := &cobra.Command{Use: "test"} | ||||||
|  | 
 | ||||||
|  | 	var testFlag bool | ||||||
|  | 	registry.RegisterBoolFlag(cmd, "test-flag", &testFlag, false, "Test flag") | ||||||
|  | 
 | ||||||
|  | 	// Simulate flag being set on command line
 | ||||||
|  | 	err := cmd.Flags().Set("test-flag", "true") | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	testFlag = true // Value would be updated by cobra
 | ||||||
|  | 
 | ||||||
|  | 	// Create a mock handler
 | ||||||
|  | 	handler := NewMockFlagHandler() | ||||||
|  | 
 | ||||||
|  | 	// Transfer flags (with changes)
 | ||||||
|  | 	registry.TransferFlags(cmd, handler) | ||||||
|  | 
 | ||||||
|  | 	// Verify the handler was called with the right parameters
 | ||||||
|  | 	assert.Equal(t, &testFlag, handler.handledFlags["test-flag"]) | ||||||
|  | 	assert.True(t, handler.changedFlags["test-flag"]) | ||||||
|  | 	assert.True(t, *handler.handledFlags["test-flag"].(*bool)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGenericFlagRegistry_TransferFlags_NonHandler(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 	cmd := &cobra.Command{Use: "test"} | ||||||
|  | 
 | ||||||
|  | 	var testFlag bool | ||||||
|  | 	registry.RegisterBoolFlag(cmd, "test-flag", &testFlag, false, "Test flag") | ||||||
|  | 
 | ||||||
|  | 	// Use a non-handler type
 | ||||||
|  | 	nonHandler := struct{}{} | ||||||
|  | 
 | ||||||
|  | 	// This should not panic
 | ||||||
|  | 	registry.TransferFlags(cmd, nonHandler) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGenericFlagRegistry_MultipleFlags(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 	cmd := &cobra.Command{Use: "test"} | ||||||
|  | 
 | ||||||
|  | 	var boolFlag bool | ||||||
|  | 	var boolFlag2 bool | ||||||
|  | 
 | ||||||
|  | 	registry.RegisterBoolFlag(cmd, "bool-flag", &boolFlag, false, "Boolean flag") | ||||||
|  | 	registry.RegisterBoolFlag(cmd, "bool-flag2", &boolFlag2, true, "Another boolean flag") | ||||||
|  | 
 | ||||||
|  | 	// Set one flag
 | ||||||
|  | 	err := cmd.Flags().Set("bool-flag", "true") | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	boolFlag = true // Value would be updated by cobra
 | ||||||
|  | 
 | ||||||
|  | 	// Create a mock handler
 | ||||||
|  | 	handler := NewMockFlagHandler() | ||||||
|  | 
 | ||||||
|  | 	// Transfer flags
 | ||||||
|  | 	registry.TransferFlags(cmd, handler) | ||||||
|  | 
 | ||||||
|  | 	// Verify both flags were handled correctly
 | ||||||
|  | 	assert.Equal(t, &boolFlag, handler.handledFlags["bool-flag"]) | ||||||
|  | 	assert.True(t, handler.changedFlags["bool-flag"]) | ||||||
|  | 	assert.True(t, *handler.handledFlags["bool-flag"].(*bool)) | ||||||
|  | 
 | ||||||
|  | 	assert.Equal(t, &boolFlag2, handler.handledFlags["bool-flag2"]) | ||||||
|  | 	assert.False(t, handler.changedFlags["bool-flag2"]) | ||||||
|  | 	assert.True(t, *handler.handledFlags["bool-flag2"].(*bool)) // Default is true
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGenericFlagRegistry_GetRegisteredFlagNames(t *testing.T) { | ||||||
|  | 	registry := NewMockFlagRegistry() | ||||||
|  | 
 | ||||||
|  | 	// Register some test flags
 | ||||||
|  | 	boolValue := false | ||||||
|  | 	registry.values["bool-flag"] = &boolValue | ||||||
|  | 
 | ||||||
|  | 	stringValue := "test" | ||||||
|  | 	registry.values["string-flag"] = &stringValue | ||||||
|  | 
 | ||||||
|  | 	stringSliceValue := []string{"one", "two", "three"} | ||||||
|  | 	registry.values["string-slice-flag"] = &stringSliceValue | ||||||
|  | 
 | ||||||
|  | 	// Test GetRegisteredFlagNames
 | ||||||
|  | 	names := registry.GetRegisteredFlagNames() | ||||||
|  | 	assert.Len(t, names, 3) | ||||||
|  | 	assert.Contains(t, names, "bool-flag") | ||||||
|  | 	assert.Contains(t, names, "string-flag") | ||||||
|  | 	assert.Contains(t, names, "string-slice-flag") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGenericFlagRegistry_IsFlagRegistered(t *testing.T) { | ||||||
|  | 	registry := NewGenericFlagRegistry() | ||||||
|  | 
 | ||||||
|  | 	// Initially, no flags are registered
 | ||||||
|  | 	assert.False(t, registry.IsFlagRegistered("test-flag")) | ||||||
|  | 
 | ||||||
|  | 	// Register a flag
 | ||||||
|  | 	boolValue := false | ||||||
|  | 	registry.values["test-flag"] = &boolValue | ||||||
|  | 
 | ||||||
|  | 	// Now the flag should be registered
 | ||||||
|  | 	assert.True(t, registry.IsFlagRegistered("test-flag")) | ||||||
|  | 
 | ||||||
|  | 	// Check a non-existent flag
 | ||||||
|  | 	assert.False(t, registry.IsFlagRegistered("non-existent")) | ||||||
|  | 
 | ||||||
|  | 	// Register another flag
 | ||||||
|  | 	stringValue := "test" | ||||||
|  | 	registry.values["string-flag"] = &stringValue | ||||||
|  | 
 | ||||||
|  | 	// Both flags should be registered
 | ||||||
|  | 	assert.True(t, registry.IsFlagRegistered("test-flag")) | ||||||
|  | 	assert.True(t, registry.IsFlagRegistered("string-flag")) | ||||||
|  | 
 | ||||||
|  | 	// Case sensitivity check
 | ||||||
|  | 	assert.False(t, registry.IsFlagRegistered("TEST-FLAG")) | ||||||
|  | } | ||||||
|  | @ -1,21 +0,0 @@ | ||||||
| package flags |  | ||||||
| 
 |  | ||||||
| import "github.com/spf13/cobra" |  | ||||||
| 
 |  | ||||||
| // TemplateFlagRegistrar handles flags specific to the template command
 |  | ||||||
| type TemplateFlagRegistrar struct { |  | ||||||
| 	*GenericFlagRegistrar |  | ||||||
| 	IncludeCRDs bool |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // NewTemplateFlagRegistrar creates a new TemplateFlagRegistrar
 |  | ||||||
| func NewTemplateFlagRegistrar() *TemplateFlagRegistrar { |  | ||||||
| 	return &TemplateFlagRegistrar{ |  | ||||||
| 		GenericFlagRegistrar: NewGenericFlagRegistrar(), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // RegisterFlags registers template-specific flags
 |  | ||||||
| func (r *TemplateFlagRegistrar) RegisterFlags(cmd *cobra.Command) { |  | ||||||
| 	r.RegisterBoolFlag(cmd, "include-crds", &r.IncludeCRDs, false, "include CRDs in the diffing") |  | ||||||
| } |  | ||||||
		Loading…
	
		Reference in New Issue