Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,10 @@ plugin:
# ignored if plugin.dir is set
baseDir: "/path/to/base/dir"

# Default configuration regardless of engine version
default:
# List of plugins to install
plugins:
- store-dynamodb
- store-redis
# List of plugins to install
plugins:
- store-dynamodb
- store-redis

# Map of environment variables to set
env:
Expand Down
66 changes: 64 additions & 2 deletions internal/plugin/configs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ func TestEnsureConfiguredPlugins(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Setup viper configuration
viper.Set(defaultPluginsConfigKey, tt.configuredPlugins)
defer viper.Set(defaultPluginsConfigKey, nil) // Clean up
viper.Set(pluginsConfigKey, tt.configuredPlugins)
defer viper.Set(pluginsConfigKey, nil) // Clean up

// Test EnsureConfiguredPlugins
count, err := EnsureConfiguredPlugins(tt.engineType, tt.version)
Expand All @@ -78,3 +78,65 @@ func TestEnsureConfiguredPlugins(t *testing.T) {
})
}
}

func TestEnsureConfiguredPlugins_DeprecatedKey(t *testing.T) {
configDir, err := os.MkdirTemp(os.TempDir(), "imposter-plugin-configs-deprecated-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(configDir)
config.DirPath = configDir

tests := []struct {
name string
deprecatedPlugins []string
expectedCount int
}{
{
name: "deprecated key with plugins",
deprecatedPlugins: []string{"store-redis"},
expectedCount: 1,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
viper.Set(defaultPluginsConfigKey, tt.deprecatedPlugins)
defer viper.Set(defaultPluginsConfigKey, nil)

count, err := EnsureConfiguredPlugins(engine.EngineTypeDockerCore, "4.9.1")
if err != nil {
t.Errorf("EnsureConfiguredPlugins() error = %v", err)
return
}
if count != tt.expectedCount {
t.Errorf("EnsureConfiguredPlugins() count = %v, expectedCount %v", count, tt.expectedCount)
}
})
}
}

func TestEnsureConfiguredPlugins_BothKeys(t *testing.T) {
configDir, err := os.MkdirTemp(os.TempDir(), "imposter-plugin-configs-both-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(configDir)
config.DirPath = configDir

viper.Set(pluginsConfigKey, []string{"store-redis"})
viper.Set(defaultPluginsConfigKey, []string{"store-redis"})
defer func() {
viper.Set(pluginsConfigKey, nil)
viper.Set(defaultPluginsConfigKey, nil)
}()

count, err := EnsureConfiguredPlugins(engine.EngineTypeDockerCore, "4.9.1")
if err != nil {
t.Errorf("EnsureConfiguredPlugins() error = %v", err)
return
}
if count != 1 {
t.Errorf("EnsureConfiguredPlugins() count = %v, expected 1 (merged and deduplicated)", count)
}
}
25 changes: 22 additions & 3 deletions internal/plugin/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import (
"path/filepath"
)

const pluginsConfigKey = "plugins"

// Deprecated: use pluginsConfigKey instead.
const defaultPluginsConfigKey = "default.plugins"

// addDefaultPlugins adds the provided plugins to the list of default
Expand Down Expand Up @@ -45,17 +48,33 @@ func ListDefaultPlugins() ([]string, error) {
v, err := parseConfigFile()
if err != nil {
return []string{}, err
} else {
return v.GetStringSlice(defaultPluginsConfigKey), nil
}
return getConfiguredPlugins(v), nil
}

// getConfiguredPlugins reads plugins from both the top-level "plugins"
// key and the deprecated "default.plugins" key, merging and deduplicating.
func getConfiguredPlugins(v *viper.Viper) []string {
plugins := v.GetStringSlice(pluginsConfigKey)
deprecated := v.GetStringSlice(defaultPluginsConfigKey)
if len(deprecated) > 0 {
logger.Warnf("'default.plugins' config key is deprecated; use top-level 'plugins' instead")
plugins = stringutil.CombineUnique(plugins, deprecated)
}
return plugins
}

func writeDefaultPlugins(plugins []string) error {
v, err := parseConfigFile()
if err != nil {
return err
}
v.Set(defaultPluginsConfigKey, plugins)
v.Set(pluginsConfigKey, plugins)

// clear deprecated nested key so it is not written back
if v.IsSet(defaultPluginsConfigKey) {
v.Set(defaultPluginsConfigKey, []string{})
}

configDir, err := config.GetGlobalConfigDir()
if err != nil {
Expand Down
70 changes: 58 additions & 12 deletions internal/plugin/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,23 @@ func TestListDefaultPlugins(t *testing.T) {
expectError: false,
},
{
name: "config with plugins",
name: "top-level plugins",
configContent: `plugins:
- store-redis
- js-graal
`,
expectedPlugins: []string{"store-redis", "js-graal"},
expectError: false,
},
{
name: "top-level empty plugins list",
configContent: `plugins: []
`,
expectedPlugins: []string{},
expectError: false,
},
{
name: "deprecated default.plugins format",
configContent: `default:
plugins:
- store-redis
Expand All @@ -39,13 +55,25 @@ func TestListDefaultPlugins(t *testing.T) {
expectError: false,
},
{
name: "config with empty plugins list",
name: "deprecated default.plugins empty list",
configContent: `default:
plugins: []
`,
expectedPlugins: []string{},
expectError: false,
},
{
name: "both formats merges and deduplicates",
configContent: `plugins:
- store-redis
default:
plugins:
- js-graal
- store-redis
`,
expectedPlugins: []string{"store-redis", "js-graal"},
expectError: false,
},
}

for _, tt := range tests {
Expand Down Expand Up @@ -321,36 +349,54 @@ func TestParseConfigFile(t *testing.T) {
config.DirPath = configDir

// Test with non-existent config file
viper, err := parseConfigFile()
v, err := parseConfigFile()
if err != nil {
t.Errorf("parseConfigFile() with non-existent file error = %v", err)
}
if viper == nil {
if v == nil {
t.Error("parseConfigFile() returned nil viper instance")
}

// Test with existing config file
configContent := `default:
plugins:
- test-plugin
// Test with existing config file using top-level plugins
configContent := `plugins:
- test-plugin
`
configFilePath := filepath.Join(configDir, "config.yaml")
err = os.WriteFile(configFilePath, []byte(configContent), 0644)
if err != nil {
t.Fatal(err)
}

viper, err = parseConfigFile()
v, err = parseConfigFile()
if err != nil {
t.Errorf("parseConfigFile() with existing file error = %v", err)
}
if viper == nil {
if v == nil {
t.Error("parseConfigFile() returned nil viper instance")
}

// Verify the config was parsed correctly
plugins := viper.GetStringSlice("default.plugins")
plugins := v.GetStringSlice("plugins")
if len(plugins) != 1 || plugins[0] != "test-plugin" {
t.Errorf("parseConfigFile() parsed plugins incorrectly: got %v, expected [test-plugin]", plugins)
}

// Test with deprecated default.plugins format
configContent = `default:
plugins:
- legacy-plugin
`
err = os.WriteFile(configFilePath, []byte(configContent), 0644)
if err != nil {
t.Fatal(err)
}

v, err = parseConfigFile()
if err != nil {
t.Errorf("parseConfigFile() with deprecated format error = %v", err)
}

legacyPlugins := v.GetStringSlice("default.plugins")
if len(legacyPlugins) != 1 || legacyPlugins[0] != "legacy-plugin" {
t.Errorf("parseConfigFile() parsed deprecated plugins incorrectly: got %v, expected [legacy-plugin]", legacyPlugins)
}
}
17 changes: 11 additions & 6 deletions internal/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,24 @@ func EnsureConfiguredPlugins(engineType engine.EngineType, version string) (int,
// this includes the config from the current configuration context,
// not just the global CLI config file, so it includes any
// configuration in the working directory
plugins := viper.GetStringSlice(defaultPluginsConfigKey)
plugins := viper.GetStringSlice(pluginsConfigKey)

deprecated := viper.GetStringSlice(defaultPluginsConfigKey)
if len(deprecated) > 0 {
logger.Warnf("'default.plugins' config key is deprecated; use top-level 'plugins' instead")
plugins = append(plugins, deprecated...)
}

var expanded []string
for _, plugin := range plugins {
// work-around for https://github.com/spf13/viper/issues/380
if strings.Contains(plugin, ",") {
for _, p := range strings.Split(plugin, ",") {
plugins = append(plugins, p)
}
expanded = append(expanded, strings.Split(plugin, ",")...)
} else {
plugins = append(plugins, plugin)
expanded = append(expanded, plugin)
}
}
plugins = stringutil.Unique(plugins)
plugins = stringutil.Unique(expanded)

logger.Tracef("found %d configured plugin(s): %v", len(plugins), plugins)
return EnsurePlugins(plugins, engineType, version, false)
Expand Down
Loading