reorganise directories for better readbility

This commit is contained in:
jkhelil
2020-05-19 10:26:18 +02:00
parent 57ad3b6be8
commit 5e1496cbc3
85 changed files with 134 additions and 133 deletions
+27
View File
@@ -0,0 +1,27 @@
package plugins
const (
configurationAsCodePlugin = "configuration-as-code:1.38"
gitPlugin = "git:4.2.2"
jobDslPlugin = "job-dsl:1.77"
kubernetesCredentialsProviderPlugin = "kubernetes-credentials-provider:0.13"
kubernetesPlugin = "kubernetes:1.25.2"
workflowAggregatorPlugin = "workflow-aggregator:2.6"
workflowJobPlugin = "workflow-job:2.38"
)
// basePluginsList contains plugins to install by operator.
var basePluginsList = []Plugin{
Must(New(kubernetesPlugin)),
Must(New(workflowJobPlugin)),
Must(New(workflowAggregatorPlugin)),
Must(New(gitPlugin)),
Must(New(jobDslPlugin)),
Must(New(configurationAsCodePlugin)),
Must(New(kubernetesCredentialsProviderPlugin)),
}
// BasePlugins returns list of plugins to install by operator.
func BasePlugins() []Plugin {
return basePluginsList
}
+130
View File
@@ -0,0 +1,130 @@
package plugins
import (
"fmt"
"regexp"
"strings"
"github.com/pkg/errors"
)
// Plugin represents jenkins plugin.
type Plugin struct {
Name string `json:"name"`
Version string `json:"version"`
DownloadURL string `json:"downloadURL"`
rootPluginNameAndVersion string
}
func (p Plugin) String() string {
return fmt.Sprintf("%s:%s", p.Name, p.Version)
}
var (
// NamePattern is the plugin name regex pattern
NamePattern = regexp.MustCompile(`^[0-9a-zA-Z-_]+$`)
// VersionPattern is the plugin version regex pattern
VersionPattern = regexp.MustCompile(`^[0-9a-zA-Z+\\.-]+$`)
// DownloadURLPattern is the plugin download url regex pattern
DownloadURLPattern = regexp.MustCompile(`https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)`)
)
// New creates plugin from string, for example "name-of-plugin:0.0.1".
func New(nameWithVersion string) (*Plugin, error) {
val := strings.SplitN(nameWithVersion, ":", 2)
if val == nil || len(val) != 2 {
return nil, errors.Errorf("invalid plugin format '%s'", nameWithVersion)
}
name := val[0]
version := val[1]
if err := validatePlugin(name, version, ""); err != nil {
return nil, err
}
return &Plugin{
Name: name,
Version: version,
}, nil
}
// NewPlugin creates plugin from name and version, for example "name-of-plugin:0.0.1".
func NewPlugin(name, version, downloadURL string) (*Plugin, error) {
if err := validatePlugin(name, version, downloadURL); err != nil {
return nil, err
}
return &Plugin{
Name: name,
Version: version,
DownloadURL: downloadURL,
}, nil
}
func validatePlugin(name, version, downloadURL string) error {
if ok := NamePattern.MatchString(name); !ok {
return errors.Errorf("invalid plugin name '%s:%s', must follow pattern '%s'", name, version, NamePattern.String())
}
if ok := VersionPattern.MatchString(version); !ok {
return errors.Errorf("invalid plugin version '%s:%s', must follow pattern '%s'", name, version, VersionPattern.String())
}
if len(downloadURL) > 0 {
if ok := DownloadURLPattern.MatchString(downloadURL); !ok {
return errors.Errorf("invalid download URL '%s' for plugin name %s:%s, must follow pattern '%s'", downloadURL, name, version, DownloadURLPattern.String())
}
}
return nil
}
// Must returns plugin from pointer and throws panic when error is set.
func Must(plugin *Plugin, err error) Plugin {
if err != nil {
panic(err)
}
return *plugin
}
// VerifyDependencies checks if all plugins have compatible versions.
func VerifyDependencies(values ...map[Plugin][]Plugin) []string {
var messages []string
// key - plugin name, value array of versions
allPlugins := make(map[string][]Plugin)
for _, value := range values {
for rootPlugin, plugins := range value {
allPlugins[rootPlugin.Name] = append(allPlugins[rootPlugin.Name], Plugin{
Name: rootPlugin.Name,
Version: rootPlugin.Version,
rootPluginNameAndVersion: rootPlugin.String()})
for _, plugin := range plugins {
allPlugins[plugin.Name] = append(allPlugins[plugin.Name], Plugin{
Name: plugin.Name,
Version: plugin.Version,
rootPluginNameAndVersion: rootPlugin.String()})
}
}
}
for pluginName, versions := range allPlugins {
if len(versions) == 1 {
continue
}
for _, firstVersion := range versions {
for _, secondVersion := range versions {
if firstVersion.Version != secondVersion.Version {
messages = append(messages, fmt.Sprintf("Plugin '%s' requires version '%s' but plugin '%s' requires '%s' for plugin '%s'",
firstVersion.rootPluginNameAndVersion,
firstVersion.Version,
secondVersion.rootPluginNameAndVersion,
secondVersion.Version,
pluginName,
))
}
}
}
}
return messages
}
+181
View File
@@ -0,0 +1,181 @@
package plugins
import (
"testing"
"github.com/jenkinsci/kubernetes-operator/pkg/log"
"github.com/stretchr/testify/assert"
)
func TestValidatePlugin(t *testing.T) {
validPluginName := "valid"
validPluginVersion := "0.1.2"
t.Run("version 1.6+build.162", func(t *testing.T) {
got := validatePlugin(validPluginName, "1.6+build.162", "")
assert.NoError(t, got)
})
t.Run("version 1.8+build.201601050116", func(t *testing.T) {
got := validatePlugin(validPluginName, "1.8+build.201601050116", "")
assert.NoError(t, got)
})
t.Run("version 1.8-RELEASE", func(t *testing.T) {
got := validatePlugin(validPluginName, "1.8-RELEASE", "")
assert.NoError(t, got)
})
t.Run("version 20.810504d7462", func(t *testing.T) {
got := validatePlugin(validPluginName, "20.810504d7462", "")
assert.NoError(t, got)
})
t.Run("version 3.0-rc1", func(t *testing.T) {
got := validatePlugin(validPluginName, "3.0-rc1", "")
assert.NoError(t, got)
})
t.Run("version 3.1.20180605-140134.c2e96c4", func(t *testing.T) {
got := validatePlugin(validPluginName, "3.1.20180605-140134.c2e96c4", "")
assert.NoError(t, got)
})
t.Run("invalid version !", func(t *testing.T) {
got := validatePlugin(validPluginName, "0.5.1!", "")
assert.Error(t, got)
})
t.Run("name 01234567890-abcdefghijklmnoprstuwxz_ABCDEFGHIJKLMNOPQRSTUVWXYZ", func(t *testing.T) {
got := validatePlugin("01234567890-abcdefghijklmnoprstuwxz_ABCDEFGHIJKLMNOPQRSTUVWXYZ", validPluginVersion, "")
assert.NoError(t, got)
})
t.Run("invalid name !", func(t *testing.T) {
got := validatePlugin("!", validPluginVersion, "")
assert.Error(t, got)
})
t.Run("invalid download URL", func(t *testing.T) {
got := validatePlugin(validPluginName, validPluginVersion, "http://www.jenkins/plugin.hpi")
assert.Error(t, got)
})
t.Run("valid http download URL", func(t *testing.T) {
got := validatePlugin(validPluginName, validPluginVersion, "http://www.jenkins.com/plugin.hpi")
assert.NoError(t, got)
})
t.Run("valid https download URL", func(t *testing.T) {
got := validatePlugin(validPluginName, validPluginVersion, "https://www.jenkins.com/plugin.hpi")
assert.NoError(t, got)
})
}
func TestVerifyDependencies(t *testing.T) {
log.SetupLogger(false)
t.Run("happy, single root plugin with one dependent plugin", func(t *testing.T) {
basePlugins := map[Plugin][]Plugin{
Must(New("first-root-plugin:1.0.0")): {
Must(New("first-plugin:0.0.1")),
},
}
got := VerifyDependencies(basePlugins)
assert.Nil(t, got)
})
t.Run("happy, two root plugins with one depended plugin with the same version", func(t *testing.T) {
basePlugins := map[Plugin][]Plugin{
Must(New("first-root-plugin:1.0.0")): {
Must(New("first-plugin:0.0.1")),
},
Must(New("second-root-plugin:1.0.0")): {
Must(New("first-plugin:0.0.1")),
},
}
got := VerifyDependencies(basePlugins)
assert.Nil(t, got)
})
t.Run("happy, two plugin names with names with underscores", func(t *testing.T) {
basePlugins := map[Plugin][]Plugin{
Must(New("first_root_plugin:1.0.0")): {
Must(New("first_plugin:0.0.1")),
},
Must(New("second_root_plugin:1.0.0")): {
Must(New("first_plugin:0.0.1")),
},
}
got := VerifyDependencies(basePlugins)
assert.Nil(t, got)
})
t.Run("happy, two plugin names with uppercase names", func(t *testing.T) {
basePlugins := map[Plugin][]Plugin{
Must(New("First-Root-Plugin:1.0.0")): {
Must(New("First_Plugin:0.0.1")),
},
Must(New("Second_Root_Plugin:1.0.0")): {
Must(New("First_Plugin:0.0.1")),
},
}
got := VerifyDependencies(basePlugins)
assert.Nil(t, got)
})
t.Run("fail, two root plugins have different versions", func(t *testing.T) {
basePlugins := map[Plugin][]Plugin{
Must(New("first-root-plugin:1.0.0")): {
Must(New("first-plugin:0.0.1")),
},
Must(New("first-root-plugin:2.0.0")): {
Must(New("first-plugin:0.0.1")),
},
}
got := VerifyDependencies(basePlugins)
assert.Contains(t, got, "Plugin 'first-root-plugin:1.0.0' requires version '1.0.0' but plugin 'first-root-plugin:2.0.0' requires '2.0.0' for plugin 'first-root-plugin'")
assert.Contains(t, got, "Plugin 'first-root-plugin:2.0.0' requires version '2.0.0' but plugin 'first-root-plugin:1.0.0' requires '1.0.0' for plugin 'first-root-plugin'")
})
t.Run("happy, no version collision with two separate plugins lists", func(t *testing.T) {
basePlugins := map[Plugin][]Plugin{
Must(New("first-root-plugin:1.0.0")): {
Must(New("first-plugin:0.0.1")),
},
}
extraPlugins := map[Plugin][]Plugin{
Must(New("second-root-plugin:2.0.0")): {
Must(New("first-plugin:0.0.1")),
},
}
got := VerifyDependencies(basePlugins, extraPlugins)
assert.Nil(t, got)
})
t.Run("fail, dependent plugins have different versions", func(t *testing.T) {
basePlugins := map[Plugin][]Plugin{
Must(New("first-root-plugin:1.0.0")): {
Must(New("first-plugin:0.0.1")),
},
Must(New("first-root-plugin:2.0.0")): {
Must(New("first-plugin:0.0.2")),
},
}
got := VerifyDependencies(basePlugins)
assert.Contains(t, got, "Plugin 'first-root-plugin:1.0.0' requires version '1.0.0' but plugin 'first-root-plugin:2.0.0' requires '2.0.0' for plugin 'first-root-plugin'")
assert.Contains(t, got, "Plugin 'first-root-plugin:2.0.0' requires version '2.0.0' but plugin 'first-root-plugin:1.0.0' requires '1.0.0' for plugin 'first-root-plugin'")
assert.Contains(t, got, "Plugin 'first-root-plugin:1.0.0' requires version '0.0.1' but plugin 'first-root-plugin:2.0.0' requires '0.0.2' for plugin 'first-plugin'")
assert.Contains(t, got, "Plugin 'first-root-plugin:2.0.0' requires version '0.0.2' but plugin 'first-root-plugin:1.0.0' requires '0.0.1' for plugin 'first-plugin'")
})
t.Run("fail, root and dependent plugins have different versions", func(t *testing.T) {
basePlugins := map[Plugin][]Plugin{
Must(New("first-root-plugin:1.0.0")): {
Must(New("first-plugin:0.0.1")),
},
}
extraPlugins := map[Plugin][]Plugin{
Must(New("first-root-plugin:2.0.0")): {
Must(New("first-plugin:0.0.2")),
},
}
got := VerifyDependencies(basePlugins, extraPlugins)
assert.Contains(t, got, "Plugin 'first-root-plugin:1.0.0' requires version '1.0.0' but plugin 'first-root-plugin:2.0.0' requires '2.0.0' for plugin 'first-root-plugin'")
assert.Contains(t, got, "Plugin 'first-root-plugin:2.0.0' requires version '2.0.0' but plugin 'first-root-plugin:1.0.0' requires '1.0.0' for plugin 'first-root-plugin'")
assert.Contains(t, got, "Plugin 'first-root-plugin:1.0.0' requires version '0.0.1' but plugin 'first-root-plugin:2.0.0' requires '0.0.2' for plugin 'first-plugin'")
assert.Contains(t, got, "Plugin 'first-root-plugin:2.0.0' requires version '0.0.2' but plugin 'first-root-plugin:1.0.0' requires '0.0.1' for plugin 'first-plugin'")
})
t.Run("happy with dash in version", func(t *testing.T) {
basePlugins := map[Plugin][]Plugin{
Must(New("first-root-plugin:1.0.0-1")): {
Must(New("first-plugin:0.0.1-1")),
},
}
got := VerifyDependencies(basePlugins)
assert.Nil(t, got)
})
}