Skip to content

Commit f7ef0bd

Browse files
authored
fix : backward compatibility in loading yaml plugins (#567)
* fix : load both yaml and bin plugin if available, revert plugin discovery logic * add tests
1 parent 2560ef8 commit f7ef0bd

File tree

6 files changed

+48
-22
lines changed

6 files changed

+48
-22
lines changed

cmd/version/version.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,7 @@ func (v *versionCommand) printAllPluginInfos() {
115115
v.logger.Info(fmt.Sprintf("\nDiscovered plugins: %d", len(plugins)))
116116
for taskIdx, tasks := range plugins {
117117
schema := tasks.Info()
118-
if tasks.YamlMod != nil {
119-
v.logger.Info(fmt.Sprintf("\n%d. %s (%s)", taskIdx+1, schema.Name, "yaml"))
120-
} else {
121-
v.logger.Info(fmt.Sprintf("\n%d. %s", taskIdx+1, schema.Name))
122-
}
118+
v.logger.Info(fmt.Sprintf("\n%d. %s", taskIdx+1, schema.Name))
123119
v.logger.Info(fmt.Sprintf("Description: %s", schema.Description))
124120
v.logger.Info(fmt.Sprintf("Image: %s", schema.Image))
125121
v.logger.Info(fmt.Sprintf("Type: %s", schema.PluginType))

models/plugin.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -526,13 +526,13 @@ func (s *registeredPlugins) Add(baseMod BasePlugin, cliMod CommandLineMod, drMod
526526
func (s *registeredPlugins) add(baseMod BasePlugin, cliMod CommandLineMod, drMod DependencyResolverMod, yamlMod CommandLineMod) error {
527527
var info *PluginInfoResponse
528528
var err error
529-
if baseMod != nil {
530-
info, err = baseMod.PluginInfo()
529+
if yamlMod != nil {
530+
info, err = yamlMod.PluginInfo()
531531
if err != nil {
532532
return err
533533
}
534534
} else {
535-
info, err = yamlMod.PluginInfo()
535+
info, err = baseMod.PluginInfo()
536536
if err != nil {
537537
return err
538538
}
@@ -542,11 +542,6 @@ func (s *registeredPlugins) add(baseMod BasePlugin, cliMod CommandLineMod, drMod
542542
return errors.New("plugin name cannot be empty")
543543
}
544544

545-
// check if name is already used
546-
if _, ok := s.data[info.Name]; ok {
547-
return fmt.Errorf("plugin name already in use %s", info.Name)
548-
}
549-
550545
// image is a required field
551546
if info.Image == "" {
552547
return errors.New("plugin image cannot be empty")
@@ -564,6 +559,19 @@ func (s *registeredPlugins) add(baseMod BasePlugin, cliMod CommandLineMod, drMod
564559
return ErrUnsupportedPlugin
565560
}
566561

562+
isCandidatePluginYaml := yamlMod != nil
563+
existingPlugin, alreadyPresent := s.data[info.Name]
564+
if alreadyPresent {
565+
if existingPlugin.IsYamlPlugin() == isCandidatePluginYaml {
566+
return fmt.Errorf("plugin name already in use %s", info.Name)
567+
}
568+
// merge plugin case : existing plugin is binary and candidate is yaml
569+
// (as binaries are loaded first)
570+
s.data[info.Name].YamlMod = yamlMod
571+
return nil
572+
}
573+
574+
// creating new plugin
567575
s.data[info.Name] = &Plugin{
568576
Base: baseMod,
569577
CLIMod: cliMod,

models/plugin_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ func TestPluginModels(t *testing.T) {
133133
NewMockYamlPlugin("c", string(models.PluginTypeTask)),
134134
NewMockYamlPlugin("b", string(models.PluginTypeTask)),
135135
NewMockPlugin("a", string(models.PluginTypeHook)),
136+
NewMockYamlPlugin("a", string(models.PluginTypeHook)),
136137
NewMockYamlPlugin("z", string(models.PluginTypeTask)),
137138
}
138139
for _, plugin := range plugins {
@@ -142,6 +143,12 @@ func TestPluginModels(t *testing.T) {
142143
repo.Add(plugin.Base, plugin.CLIMod, plugin.DependencyMod)
143144
}
144145
}
146+
t.Run("should allow both yaml and bin implementations in plugin", func(t *testing.T) {
147+
plugin, _ := repo.GetByName("a")
148+
assert.Equal(t, plugin.IsYamlPlugin(), true)
149+
assert.NotNil(t, plugin.CLIMod)
150+
assert.NotNil(t, plugin.YamlMod)
151+
})
145152

146153
t.Run("should return sorted plugins", func(t *testing.T) {
147154
list := repo.GetAll()

plugin/plugin.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,25 @@ func modSupported(mods []models.PluginMod, mod models.PluginMod) bool {
109109
func DiscoverPluginsGivenFilePattern(pluginLogger hclog.Logger, prefix, suffix string) []string {
110110
var discoveredPlugins, dirs []string
111111

112-
// static plugin discovery in both server and client
113112
if p, err := os.Getwd(); err == nil {
114113
dirs = append(dirs, path.Join(p, PluginsDir))
114+
dirs = append(dirs, p)
115115
} else {
116116
pluginLogger.Debug(fmt.Sprintf("Error discovering working dir: %s", err))
117117
}
118118

119+
// look in the same directory as the executable
120+
if exePath, err := os.Executable(); err != nil {
121+
pluginLogger.Debug(fmt.Sprintf("Error discovering exe directory: %s", err))
122+
} else {
123+
dirs = append(dirs, filepath.Dir(exePath))
124+
}
125+
126+
// add user home directory
127+
if currentHomeDir, err := os.UserHomeDir(); err == nil {
128+
dirs = append(dirs, filepath.Join(currentHomeDir, ".optimus", "plugins"))
129+
}
130+
119131
for _, dirPath := range dirs {
120132
fileInfos, err := os.ReadDir(dirPath)
121133
if err != nil {

plugin/yaml/plugin.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,17 +116,13 @@ func NewPluginSpec(pluginPath string) (*PluginSpec, error) {
116116
// NOTE: binary plugins are loaded prior to yaml plugins
117117
func Init(pluginsRepo models.PluginRepository, discoveredYamlPlugins []string, pluginLogger hclog.Logger) {
118118
for _, yamlPluginPath := range discoveredYamlPlugins {
119-
yamlPlugin, err := NewPluginSpec(yamlPluginPath)
119+
yamlPluginSpec, err := NewPluginSpec(yamlPluginPath)
120120
if err != nil {
121121
pluginLogger.Error(fmt.Sprintf("plugin Init: %s", yamlPluginPath), err)
122122
continue
123123
}
124-
pluginInfo, _ := yamlPlugin.PluginInfo()
125-
if plugin, _ := pluginsRepo.GetByName(pluginInfo.Name); plugin != nil && !plugin.IsYamlPlugin() {
126-
pluginLogger.Debug(fmt.Sprintf("skipping yaml plugin (as binary already added): %s", pluginInfo.Name))
127-
continue
128-
}
129-
if err := pluginsRepo.AddYaml(yamlPlugin); err != nil {
124+
pluginInfo, _ := yamlPluginSpec.PluginInfo()
125+
if err := pluginsRepo.AddYaml(yamlPluginSpec); err != nil {
130126
pluginLogger.Error(fmt.Sprintf("PluginRegistry.Add: %s", yamlPluginPath), err)
131127
continue
132128
}

plugin/yaml/plugin_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ func TestYamlPlugin(t *testing.T) {
155155
yaml.Init(repo, []string{testYamlPluginPath}, pluginLogger)
156156
assert.NotEmpty(t, repo.GetAll())
157157
})
158-
t.Run("should not load yaml plugin due to binary plugin with same name exists", func(t *testing.T) {
158+
t.Run("should load yaml even when binary plugin with same name exists", func(t *testing.T) {
159159
repoWithBinayPlugin := models.NewPluginRepository()
160160
err := repoWithBinayPlugin.Add(&mockBasePlugin{
161161
Name: testYamlPluginName,
@@ -171,6 +171,13 @@ func TestYamlPlugin(t *testing.T) {
171171

172172
assert.Len(t, repoPlugins, 1)
173173
assert.Equal(t, repoPlugins[0].Info().Name, testYamlPluginName)
174+
assert.NotNil(t, repoPlugins[0].YamlMod)
175+
})
176+
t.Run("should not load duplicate yaml", func(t *testing.T) {
177+
repoWithBinayPlugin := models.NewPluginRepository()
178+
yaml.Init(repoWithBinayPlugin, []string{testYamlPluginPath, testYamlPluginPath}, pluginLogger)
179+
repoPlugins := repoWithBinayPlugin.GetAll()
180+
assert.Len(t, repoPlugins, 1)
174181
})
175182
t.Run("should not load yaml plugin for invalid paths or yaml", func(t *testing.T) {
176183
repo := models.NewPluginRepository()

0 commit comments

Comments
 (0)