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"
|
||||
|
||||
// ApplyFlagRegistrar handles flags specific to the apply command
|
||||
type ApplyFlagRegistrar struct {
|
||||
*GenericFlagRegistrar
|
||||
// ApplyFlagRegistry handles flags specific to the apply command
|
||||
type ApplyFlagRegistry struct {
|
||||
*GenericFlagRegistry
|
||||
IncludeCRDs bool
|
||||
SkipCRDs bool
|
||||
}
|
||||
|
||||
// NewApplyFlagRegistrar creates a new ApplyFlagRegistrar
|
||||
func NewApplyFlagRegistrar() *ApplyFlagRegistrar {
|
||||
return &ApplyFlagRegistrar{
|
||||
GenericFlagRegistrar: NewGenericFlagRegistrar(),
|
||||
// NewApplyFlagRegistry creates a new ApplyFlagRegistry
|
||||
func NewApplyFlagRegistry() *ApplyFlagRegistry {
|
||||
return &ApplyFlagRegistry{
|
||||
GenericFlagRegistry: NewGenericFlagRegistry(),
|
||||
}
|
||||
}
|
||||
|
||||
// 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, "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"
|
||||
|
||||
// SyncFlagRegistrar handles flags specific to the sync command
|
||||
type SyncFlagRegistrar struct {
|
||||
*GenericFlagRegistrar
|
||||
// SyncFlagRegistry handles flags specific to the sync command
|
||||
type SyncFlagRegistry struct {
|
||||
*GenericFlagRegistry
|
||||
IncludeCRDs bool
|
||||
SkipCRDs bool
|
||||
}
|
||||
|
||||
// NewSyncFlagRegistrar creates a new SyncFlagRegistrar
|
||||
func NewSyncFlagRegistrar() *SyncFlagRegistrar {
|
||||
return &SyncFlagRegistrar{
|
||||
GenericFlagRegistrar: NewGenericFlagRegistrar(),
|
||||
// NewSyncFlagRegistry creates a new SyncFlagRegistry
|
||||
func NewSyncFlagRegistry() *SyncFlagRegistry {
|
||||
return &SyncFlagRegistry{
|
||||
GenericFlagRegistry: NewGenericFlagRegistry(),
|
||||
}
|
||||
}
|
||||
|
||||
// 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, "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