Skip to content
This repository has been archived by the owner on Jan 20, 2023. It is now read-only.

Check plugins' extensions for conflicts during metadata broker #93

Merged
merged 1 commit into from
Feb 14, 2020
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
8 changes: 7 additions & 1 deletion brokers/metadata/broker.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
// when downloading metas
const RegistryURLFormat = "%s/%s/meta.yaml"

// Broker is used to process Che plugins
// Broker is used to process Che plugins
type Broker struct {
common.Broker
Expand Down Expand Up @@ -72,6 +71,13 @@ func (b *Broker) Start(pluginFQNs []model.PluginFQN, defaultRegistry string) err
}
b.PrintPlan(pluginMetas)

if collisions := utils.GetExtensionCollisions(pluginMetas); len(collisions) > 0 {
collisionLog := []string{"WARNING: multiple instances of the same extension will be included in this workspace:"}
collisionLog = append(collisionLog, utils.ConvertCollisionsToLog(collisions)...)
collisionLog = append(collisionLog, "These plugins may not work as expected. If errors occur please try disabling all but one of the conflicting plugins.")
b.PrintInfoBuffer(collisionLog)
}

// Process plugins into ChePlugins
err = b.ProcessPlugins(pluginMetas)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions brokers/testdata/config-plugin-ids.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
{
"id": "ms-kubernetes-tools/vscode-kubernetes-tools/0.1.17"
},
{
"id": "redhat/vscode-openshift-connector/0.1.2"
},
{
"id": "eclipse/che-machine-exec-plugin/0.0.1"
},
Expand Down
56 changes: 56 additions & 0 deletions utils/dependencies.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// Copyright (c) 2020 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//

package utils

import (
"fmt"

"github.com/eclipse/che-plugin-broker/model"
)

// GetExtensionCollisions checks a list of plugin metas for extensions shared by
// more than one plugin. Return value is a list of
func GetExtensionCollisions(metas []model.PluginMeta) map[string][]string {
extensions := map[string][]string{}
for _, meta := range metas {
for _, ext := range meta.Spec.Extensions {
extensions[ext] = append(extensions[ext], meta.ID)
}
}
collisions := make(map[string][]string)
for ext, ids := range extensions {
if len(ids) > 1 {
collisions[ext] = ids
}
}
return collisions
}

// ConvertCollisionsToLog converts the output of GetExtensionCollisions to a human-readable
// string. Output is a slice of strings, to be joined by newlines
func ConvertCollisionsToLog(collisions map[string][]string) []string {
var output []string
for ext, plugins := range collisions {
output = append(output, fmt.Sprintf(" Plugins"))
for _, plugin := range plugins {
output = append(output, fmt.Sprintf(" - %s", plugin))
}
if len(plugins) > 2 {
output = append(output, fmt.Sprintf(" all depend on and embed extension"))
} else {
output = append(output, fmt.Sprintf(" both depend on and embed extension"))
}
output = append(output, fmt.Sprintf(" %s", ext))
}
return output
}
86 changes: 86 additions & 0 deletions utils/dependencies_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//
// Copyright (c) 2020 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//

package utils

import (
"regexp"
"strings"
"testing"

"github.com/stretchr/testify/assert"

"github.com/eclipse/che-plugin-broker/model"
)

func TestGetExtensionCollisions(t *testing.T) {
metas := []model.PluginMeta{
generateMetaWithExtensions("test/conflict_one", "aaa", "bbb"),
generateMetaWithExtensions("test/no_conflict", "ddd"),
generateMetaWithExtensions("test/conflict_two", "ccc", "bbb"),
}

output := GetExtensionCollisions(metas)
assert.NotEmpty(t, output)
assert.ElementsMatch(t, output["bbb"], []string{"test/conflict_one", "test/conflict_two"})
assert.NotContains(t, output, "aaa")
assert.NotContains(t, output, "ccc")
assert.NotContains(t, output, "ddd")
}

func TestGetExtensionCollisionsMulti(t *testing.T) {
metas := []model.PluginMeta{
generateMetaWithExtensions("one", "aaa", "bbb"),
generateMetaWithExtensions("two", "xxx", "bbb"),
generateMetaWithExtensions("three", "aaa", "yyy"),
}

output := GetExtensionCollisions(metas)
assert.NotEmpty(t, output)
assert.ElementsMatch(t, output["aaa"], []string{"one", "three"})
assert.ElementsMatch(t, output["bbb"], []string{"one", "two"})
assert.NotContains(t, output, "xxx")
assert.NotContains(t, output, "yyy")
}

func TestConvertCollisionsToLog(t *testing.T) {
collisions := map[string][]string{
"ext1": []string{"plugin_a", "plugin_b"},
"ext2": []string{"plugin_c", "plugin_d", "plugin_e"},
}
output := ConvertCollisionsToLog(collisions)
for _, test := range []string{
".*ext1.*", ".*ext2.*", ".*plugin_a.*", ".*plugin_b.*", ".*plugin_c.*", ".*plugin_d.*", ".*plugin_e.*",
} {
assertMatchSliceRegexp(t, output, test)
}
}

func generateMetaWithExtensions(id string, exts ...string) model.PluginMeta {
return model.PluginMeta{
ID: id,
Spec: model.PluginMetaSpec{
Extensions: exts,
},
}
}

func assertMatchSliceRegexp(t *testing.T, slice []string, pattern string) {
re := regexp.MustCompile(pattern)
match := false
for _, str := range slice {
if re.MatchString(str) {
match = true
}
}
assert.Truef(t, match, "Expected '%s' to be logged but got:\n%s", pattern, strings.Join(slice, "\n"))
}