Provisioning: Configurable Repository Types in monolith and operators (#110822)
* Configurable repository types in monolith and operator * Default to Github in operators * Regenerate wire * Fix and implement unit tests * Same types for enterprise tests * Remove unnecessary conversion * Remove the issue with import cycles
This commit is contained in:
@@ -3,8 +3,6 @@ package repository
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
|
||||||
"slices"
|
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||||
@@ -28,12 +26,14 @@ type Factory interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type factory struct {
|
type factory struct {
|
||||||
extras map[provisioning.RepositoryType]Extra
|
extras map[provisioning.RepositoryType]Extra
|
||||||
|
enabled map[provisioning.RepositoryType]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideFactory(extras []Extra) (Factory, error) {
|
func ProvideFactory(enabled map[provisioning.RepositoryType]struct{}, extras []Extra) (Factory, error) {
|
||||||
f := &factory{
|
f := &factory{
|
||||||
extras: make(map[provisioning.RepositoryType]Extra, len(extras)),
|
enabled: enabled,
|
||||||
|
extras: make(map[provisioning.RepositoryType]Extra, len(extras)),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range extras {
|
for _, e := range extras {
|
||||||
@@ -47,16 +47,27 @@ func ProvideFactory(extras []Extra) (Factory, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *factory) Types() []provisioning.RepositoryType {
|
func (f *factory) Types() []provisioning.RepositoryType {
|
||||||
types := slices.Collect(maps.Keys(f.extras))
|
var types []provisioning.RepositoryType
|
||||||
|
for t := range f.enabled {
|
||||||
|
if _, exists := f.extras[t]; exists {
|
||||||
|
types = append(types, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sort.Slice(types, func(i, j int) bool {
|
sort.Slice(types, func(i, j int) bool {
|
||||||
return string(types[i]) < string(types[j])
|
return string(types[i]) < string(types[j])
|
||||||
})
|
})
|
||||||
|
|
||||||
return types
|
return types
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *factory) Build(ctx context.Context, r *provisioning.Repository) (Repository, error) {
|
func (f *factory) Build(ctx context.Context, r *provisioning.Repository) (Repository, error) {
|
||||||
for _, e := range f.extras {
|
for _, e := range f.extras {
|
||||||
if e.Type() == r.Spec.Type {
|
if e.Type() == r.Spec.Type {
|
||||||
|
if _, enabled := f.enabled[e.Type()]; !enabled {
|
||||||
|
return nil, fmt.Errorf("repository type %q is not enabled", e.Type())
|
||||||
|
}
|
||||||
|
|
||||||
return e.Build(ctx, r)
|
return e.Build(ctx, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import (
|
|||||||
|
|
||||||
func TestNewFactory(t *testing.T) {
|
func TestNewFactory(t *testing.T) {
|
||||||
t.Run("creates factory with empty extras", func(t *testing.T) {
|
t.Run("creates factory with empty extras", func(t *testing.T) {
|
||||||
factory, err := ProvideFactory([]Extra{})
|
enabled := map[provisioning.RepositoryType]struct{}{}
|
||||||
|
factory, err := ProvideFactory(enabled, []Extra{})
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, factory)
|
require.NotNil(t, factory)
|
||||||
@@ -32,8 +33,13 @@ func TestNewFactory(t *testing.T) {
|
|||||||
githubExtra := &MockExtra{}
|
githubExtra := &MockExtra{}
|
||||||
githubExtra.On("Type").Return(provisioning.GitHubRepositoryType)
|
githubExtra.On("Type").Return(provisioning.GitHubRepositoryType)
|
||||||
|
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
provisioning.GitRepositoryType: {},
|
||||||
|
provisioning.GitHubRepositoryType: {},
|
||||||
|
}
|
||||||
extras := []Extra{localExtra, gitExtra, githubExtra}
|
extras := []Extra{localExtra, gitExtra, githubExtra}
|
||||||
factory, err := ProvideFactory(extras)
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, factory)
|
require.NotNil(t, factory)
|
||||||
@@ -60,8 +66,11 @@ func TestNewFactory(t *testing.T) {
|
|||||||
secondExtra := &MockExtra{}
|
secondExtra := &MockExtra{}
|
||||||
secondExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
secondExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
}
|
||||||
extras := []Extra{firstExtra, secondExtra}
|
extras := []Extra{firstExtra, secondExtra}
|
||||||
factory, err := ProvideFactory(extras)
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Nil(t, factory)
|
assert.Nil(t, factory)
|
||||||
@@ -81,8 +90,12 @@ func TestNewFactory(t *testing.T) {
|
|||||||
duplicateGitExtra := &MockExtra{}
|
duplicateGitExtra := &MockExtra{}
|
||||||
duplicateGitExtra.On("Type").Return(provisioning.GitRepositoryType)
|
duplicateGitExtra.On("Type").Return(provisioning.GitRepositoryType)
|
||||||
|
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
provisioning.GitRepositoryType: {},
|
||||||
|
}
|
||||||
extras := []Extra{localExtra, gitExtra, duplicateGitExtra}
|
extras := []Extra{localExtra, gitExtra, duplicateGitExtra}
|
||||||
factory, err := ProvideFactory(extras)
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Nil(t, factory)
|
assert.Nil(t, factory)
|
||||||
@@ -94,7 +107,8 @@ func TestNewFactory(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("handles nil extras slice", func(t *testing.T) {
|
t.Run("handles nil extras slice", func(t *testing.T) {
|
||||||
factory, err := ProvideFactory(nil)
|
enabled := map[provisioning.RepositoryType]struct{}{}
|
||||||
|
factory, err := ProvideFactory(enabled, nil)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, factory)
|
require.NotNil(t, factory)
|
||||||
@@ -105,7 +119,8 @@ func TestNewFactory(t *testing.T) {
|
|||||||
|
|
||||||
func TestFactory_Types(t *testing.T) {
|
func TestFactory_Types(t *testing.T) {
|
||||||
t.Run("returns empty slice for factory with no extras", func(t *testing.T) {
|
t.Run("returns empty slice for factory with no extras", func(t *testing.T) {
|
||||||
factory, err := ProvideFactory([]Extra{})
|
enabled := map[provisioning.RepositoryType]struct{}{}
|
||||||
|
factory, err := ProvideFactory(enabled, []Extra{})
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
types := factory.Types()
|
types := factory.Types()
|
||||||
@@ -128,8 +143,15 @@ func TestFactory_Types(t *testing.T) {
|
|||||||
gitlabExtra := &MockExtra{}
|
gitlabExtra := &MockExtra{}
|
||||||
gitlabExtra.On("Type").Return(provisioning.GitLabRepositoryType)
|
gitlabExtra.On("Type").Return(provisioning.GitLabRepositoryType)
|
||||||
|
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
provisioning.GitRepositoryType: {},
|
||||||
|
provisioning.GitHubRepositoryType: {},
|
||||||
|
provisioning.BitbucketRepositoryType: {},
|
||||||
|
provisioning.GitLabRepositoryType: {},
|
||||||
|
}
|
||||||
extras := []Extra{localExtra, gitExtra, githubExtra, bitbucketExtra, gitlabExtra}
|
extras := []Extra{localExtra, gitExtra, githubExtra, bitbucketExtra, gitlabExtra}
|
||||||
factory, err := ProvideFactory(extras)
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
types := factory.Types()
|
types := factory.Types()
|
||||||
@@ -163,8 +185,13 @@ func TestFactory_Types(t *testing.T) {
|
|||||||
githubExtra := &MockExtra{}
|
githubExtra := &MockExtra{}
|
||||||
githubExtra.On("Type").Return(provisioning.GitHubRepositoryType)
|
githubExtra.On("Type").Return(provisioning.GitHubRepositoryType)
|
||||||
|
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
provisioning.GitRepositoryType: {},
|
||||||
|
provisioning.GitHubRepositoryType: {},
|
||||||
|
}
|
||||||
extras := []Extra{githubExtra, localExtra, gitExtra} // Intentionally unordered
|
extras := []Extra{githubExtra, localExtra, gitExtra} // Intentionally unordered
|
||||||
factory, err := ProvideFactory(extras)
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
types1 := factory.Types()
|
types1 := factory.Types()
|
||||||
@@ -196,7 +223,10 @@ func TestFactory_Build(t *testing.T) {
|
|||||||
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
localExtra.On("Build", mock.Anything, mock.Anything).Return(expectedRepo, nil)
|
localExtra.On("Build", mock.Anything, mock.Anything).Return(expectedRepo, nil)
|
||||||
|
|
||||||
factory, err := ProvideFactory([]Extra{localExtra})
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
}
|
||||||
|
factory, err := ProvideFactory(enabled, []Extra{localExtra})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -217,7 +247,10 @@ func TestFactory_Build(t *testing.T) {
|
|||||||
gitExtra := &MockExtra{}
|
gitExtra := &MockExtra{}
|
||||||
gitExtra.On("Type").Return(provisioning.GitRepositoryType)
|
gitExtra.On("Type").Return(provisioning.GitRepositoryType)
|
||||||
|
|
||||||
factory, err := ProvideFactory([]Extra{gitExtra})
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.GitRepositoryType: {},
|
||||||
|
}
|
||||||
|
factory, err := ProvideFactory(enabled, []Extra{gitExtra})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -242,7 +275,10 @@ func TestFactory_Build(t *testing.T) {
|
|||||||
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
localExtra.On("Build", mock.Anything, mock.Anything).Return(nil, expectedError)
|
localExtra.On("Build", mock.Anything, mock.Anything).Return(nil, expectedError)
|
||||||
|
|
||||||
factory, err := ProvideFactory([]Extra{localExtra})
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
}
|
||||||
|
factory, err := ProvideFactory(enabled, []Extra{localExtra})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -270,7 +306,11 @@ func TestFactory_Build(t *testing.T) {
|
|||||||
gitExtra.On("Type").Return(provisioning.GitRepositoryType)
|
gitExtra.On("Type").Return(provisioning.GitRepositoryType)
|
||||||
gitExtra.On("Build", mock.Anything, mock.Anything).Return(gitRepo, nil)
|
gitExtra.On("Build", mock.Anything, mock.Anything).Return(gitRepo, nil)
|
||||||
|
|
||||||
factory, err := ProvideFactory([]Extra{localExtra, gitExtra})
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
provisioning.GitRepositoryType: {},
|
||||||
|
}
|
||||||
|
factory, err := ProvideFactory(enabled, []Extra{localExtra, gitExtra})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -293,7 +333,10 @@ func TestFactory_Build(t *testing.T) {
|
|||||||
localExtra := &MockExtra{}
|
localExtra := &MockExtra{}
|
||||||
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
|
||||||
factory, err := ProvideFactory([]Extra{localExtra})
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
}
|
||||||
|
factory, err := ProvideFactory(enabled, []Extra{localExtra})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -326,7 +369,10 @@ func TestFactory_Build(t *testing.T) {
|
|||||||
return c.Value(testKey("test")) == "value"
|
return c.Value(testKey("test")) == "value"
|
||||||
}), mock.Anything).Return(localRepo, nil)
|
}), mock.Anything).Return(localRepo, nil)
|
||||||
|
|
||||||
factory, err := ProvideFactory([]Extra{localExtra})
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
}
|
||||||
|
factory, err := ProvideFactory(enabled, []Extra{localExtra})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
repoConfig := &provisioning.Repository{
|
repoConfig := &provisioning.Repository{
|
||||||
@@ -341,3 +387,241 @@ func TestFactory_Build(t *testing.T) {
|
|||||||
localExtra.AssertExpectations(t)
|
localExtra.AssertExpectations(t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFactory_Types_EnabledFiltering(t *testing.T) {
|
||||||
|
t.Run("returns only enabled types", func(t *testing.T) {
|
||||||
|
localExtra := &MockExtra{}
|
||||||
|
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
|
||||||
|
gitExtra := &MockExtra{}
|
||||||
|
gitExtra.On("Type").Return(provisioning.GitRepositoryType)
|
||||||
|
|
||||||
|
githubExtra := &MockExtra{}
|
||||||
|
githubExtra.On("Type").Return(provisioning.GitHubRepositoryType)
|
||||||
|
|
||||||
|
// Only enable local and github, not git
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
provisioning.GitHubRepositoryType: {},
|
||||||
|
}
|
||||||
|
extras := []Extra{localExtra, gitExtra, githubExtra}
|
||||||
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
types := factory.Types()
|
||||||
|
|
||||||
|
assert.Len(t, types, 2)
|
||||||
|
expectedTypes := []provisioning.RepositoryType{
|
||||||
|
provisioning.GitHubRepositoryType,
|
||||||
|
provisioning.LocalRepositoryType,
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectedTypes, types)
|
||||||
|
|
||||||
|
localExtra.AssertExpectations(t)
|
||||||
|
gitExtra.AssertExpectations(t)
|
||||||
|
githubExtra.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("returns empty when no types enabled", func(t *testing.T) {
|
||||||
|
localExtra := &MockExtra{}
|
||||||
|
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
|
||||||
|
gitExtra := &MockExtra{}
|
||||||
|
gitExtra.On("Type").Return(provisioning.GitRepositoryType)
|
||||||
|
|
||||||
|
// Nothing enabled
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{}
|
||||||
|
extras := []Extra{localExtra, gitExtra}
|
||||||
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
types := factory.Types()
|
||||||
|
|
||||||
|
assert.Empty(t, types)
|
||||||
|
|
||||||
|
localExtra.AssertExpectations(t)
|
||||||
|
gitExtra.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ignores enabled types without corresponding extras", func(t *testing.T) {
|
||||||
|
localExtra := &MockExtra{}
|
||||||
|
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
|
||||||
|
// Enable local and git, but only have local extra
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
provisioning.GitRepositoryType: {},
|
||||||
|
}
|
||||||
|
extras := []Extra{localExtra}
|
||||||
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
types := factory.Types()
|
||||||
|
|
||||||
|
// Should only return local since git extra doesn't exist
|
||||||
|
assert.Len(t, types, 1)
|
||||||
|
assert.Equal(t, []provisioning.RepositoryType{provisioning.LocalRepositoryType}, types)
|
||||||
|
|
||||||
|
localExtra.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProvideFactory_EnabledParameter(t *testing.T) {
|
||||||
|
t.Run("creates factory with specific enabled types", func(t *testing.T) {
|
||||||
|
localExtra := &MockExtra{}
|
||||||
|
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
|
||||||
|
gitExtra := &MockExtra{}
|
||||||
|
gitExtra.On("Type").Return(provisioning.GitRepositoryType)
|
||||||
|
|
||||||
|
githubExtra := &MockExtra{}
|
||||||
|
githubExtra.On("Type").Return(provisioning.GitHubRepositoryType)
|
||||||
|
|
||||||
|
// Only enable local and git, not github
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
provisioning.GitRepositoryType: {},
|
||||||
|
}
|
||||||
|
extras := []Extra{localExtra, gitExtra, githubExtra}
|
||||||
|
|
||||||
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, factory)
|
||||||
|
types := factory.Types()
|
||||||
|
|
||||||
|
// Should only return enabled types
|
||||||
|
assert.Len(t, types, 2)
|
||||||
|
expectedTypes := []provisioning.RepositoryType{
|
||||||
|
provisioning.GitRepositoryType,
|
||||||
|
provisioning.LocalRepositoryType,
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectedTypes, types)
|
||||||
|
|
||||||
|
localExtra.AssertExpectations(t)
|
||||||
|
gitExtra.AssertExpectations(t)
|
||||||
|
githubExtra.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("creates factory with no enabled types", func(t *testing.T) {
|
||||||
|
localExtra := &MockExtra{}
|
||||||
|
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
|
||||||
|
gitExtra := &MockExtra{}
|
||||||
|
gitExtra.On("Type").Return(provisioning.GitRepositoryType)
|
||||||
|
|
||||||
|
// Enable nothing
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{}
|
||||||
|
extras := []Extra{localExtra, gitExtra}
|
||||||
|
|
||||||
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, factory)
|
||||||
|
types := factory.Types()
|
||||||
|
|
||||||
|
assert.Empty(t, types)
|
||||||
|
|
||||||
|
localExtra.AssertExpectations(t)
|
||||||
|
gitExtra.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("enabled types without extras are ignored", func(t *testing.T) {
|
||||||
|
localExtra := &MockExtra{}
|
||||||
|
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
|
||||||
|
// Enable both local and git, but only provide local extra
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
provisioning.GitRepositoryType: {},
|
||||||
|
}
|
||||||
|
extras := []Extra{localExtra}
|
||||||
|
|
||||||
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, factory)
|
||||||
|
types := factory.Types()
|
||||||
|
|
||||||
|
// Should only return local since git extra doesn't exist
|
||||||
|
assert.Len(t, types, 1)
|
||||||
|
assert.Equal(t, []provisioning.RepositoryType{provisioning.LocalRepositoryType}, types)
|
||||||
|
|
||||||
|
localExtra.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("still errors for duplicate repository types", func(t *testing.T) {
|
||||||
|
// Create duplicate extras to trigger error
|
||||||
|
firstExtra := &MockExtra{}
|
||||||
|
firstExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
|
||||||
|
secondExtra := &MockExtra{}
|
||||||
|
secondExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
}
|
||||||
|
extras := []Extra{firstExtra, secondExtra}
|
||||||
|
|
||||||
|
factory, err := ProvideFactory(enabled, extras)
|
||||||
|
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, factory)
|
||||||
|
assert.Contains(t, err.Error(), "repository type \"local\" is already registered")
|
||||||
|
|
||||||
|
firstExtra.AssertExpectations(t)
|
||||||
|
secondExtra.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("build fails for disabled repository type", func(t *testing.T) {
|
||||||
|
localExtra := &MockExtra{}
|
||||||
|
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
|
||||||
|
// Create factory with local extra but don't enable it
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{}
|
||||||
|
factory, err := ProvideFactory(enabled, []Extra{localExtra})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
repoConfig := &provisioning.Repository{
|
||||||
|
Spec: provisioning.RepositorySpec{
|
||||||
|
Type: provisioning.LocalRepositoryType,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := factory.Build(ctx, repoConfig)
|
||||||
|
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, result)
|
||||||
|
assert.Contains(t, err.Error(), "repository type \"local\" is not enabled")
|
||||||
|
localExtra.AssertNotCalled(t, "Build")
|
||||||
|
localExtra.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("build succeeds for enabled repository type", func(t *testing.T) {
|
||||||
|
expectedRepo := &MockConfigRepository{}
|
||||||
|
localExtra := &MockExtra{}
|
||||||
|
localExtra.On("Type").Return(provisioning.LocalRepositoryType)
|
||||||
|
localExtra.On("Build", mock.Anything, mock.Anything).Return(expectedRepo, nil)
|
||||||
|
|
||||||
|
// Create factory with local extra and enable it
|
||||||
|
enabled := map[provisioning.RepositoryType]struct{}{
|
||||||
|
provisioning.LocalRepositoryType: {},
|
||||||
|
}
|
||||||
|
factory, err := ProvideFactory(enabled, []Extra{localExtra})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
repoConfig := &provisioning.Repository{
|
||||||
|
Spec: provisioning.RepositorySpec{
|
||||||
|
Type: provisioning.LocalRepositoryType,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := factory.Build(ctx, repoConfig)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, expectedRepo, result)
|
||||||
|
localExtra.AssertExpectations(t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
authrt "github.com/grafana/grafana/apps/provisioning/pkg/auth"
|
authrt "github.com/grafana/grafana/apps/provisioning/pkg/auth"
|
||||||
client "github.com/grafana/grafana/apps/provisioning/pkg/generated/clientset/versioned"
|
client "github.com/grafana/grafana/apps/provisioning/pkg/generated/clientset/versioned"
|
||||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository"
|
"github.com/grafana/grafana/apps/provisioning/pkg/repository"
|
||||||
|
"github.com/grafana/grafana/apps/provisioning/pkg/repository/git"
|
||||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository/github"
|
"github.com/grafana/grafana/apps/provisioning/pkg/repository/github"
|
||||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository/local"
|
"github.com/grafana/grafana/apps/provisioning/pkg/repository/local"
|
||||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/resources"
|
"github.com/grafana/grafana/pkg/registry/apis/provisioning/resources"
|
||||||
@@ -64,9 +65,10 @@ type provisioningControllerConfig struct {
|
|||||||
// tls_key_file =
|
// tls_key_file =
|
||||||
// tls_ca_file =
|
// tls_ca_file =
|
||||||
// resync_interval =
|
// resync_interval =
|
||||||
// repository_types =
|
|
||||||
// home_path =
|
// home_path =
|
||||||
// local_permitted_prefixes =
|
// local_permitted_prefixes =
|
||||||
|
// [provisioning]
|
||||||
|
// repository_types =
|
||||||
func setupFromConfig(cfg *setting.Cfg) (controllerCfg *provisioningControllerConfig, err error) {
|
func setupFromConfig(cfg *setting.Cfg) (controllerCfg *provisioningControllerConfig, err error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return nil, fmt.Errorf("no configuration available")
|
return nil, fmt.Errorf("no configuration available")
|
||||||
@@ -220,7 +222,11 @@ func setupRepoFactory(
|
|||||||
provisioningClient *client.Clientset,
|
provisioningClient *client.Clientset,
|
||||||
) (repository.Factory, error) {
|
) (repository.Factory, error) {
|
||||||
operatorSec := cfg.SectionWithEnvOverrides("operator")
|
operatorSec := cfg.SectionWithEnvOverrides("operator")
|
||||||
repoTypes := operatorSec.Key("repository_types").Strings("|")
|
provisioningSec := cfg.SectionWithEnvOverrides("provisioning")
|
||||||
|
repoTypes := provisioningSec.Key("repository_types").Strings("|")
|
||||||
|
if len(repoTypes) == 0 {
|
||||||
|
repoTypes = []string{"github"}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: This depends on the different flavor of Grafana
|
// TODO: This depends on the different flavor of Grafana
|
||||||
// https://github.com/grafana/git-ui-sync-project/issues/495
|
// https://github.com/grafana/git-ui-sync-project/issues/495
|
||||||
@@ -234,6 +240,8 @@ func setupRepoFactory(
|
|||||||
alreadyRegistered[provisioning.RepositoryType(t)] = struct{}{}
|
alreadyRegistered[provisioning.RepositoryType(t)] = struct{}{}
|
||||||
|
|
||||||
switch provisioning.RepositoryType(t) {
|
switch provisioning.RepositoryType(t) {
|
||||||
|
case provisioning.GitRepositoryType:
|
||||||
|
extras = append(extras, git.Extra(decrypter))
|
||||||
case provisioning.GitHubRepositoryType:
|
case provisioning.GitHubRepositoryType:
|
||||||
var webhook *webhooks.WebhookExtraBuilder
|
var webhook *webhooks.WebhookExtraBuilder
|
||||||
provisioningAppURL := operatorSec.Key("provisioning_server_public_url").String()
|
provisioningAppURL := operatorSec.Key("provisioning_server_public_url").String()
|
||||||
@@ -267,7 +275,7 @@ func setupRepoFactory(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repoFactory, err := repository.ProvideFactory(extras)
|
repoFactory, err := repository.ProvideFactory(alreadyRegistered, extras)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create repository factory: %w", err)
|
return nil, fmt.Errorf("create repository factory: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package extras
|
package extras
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
apisprovisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository"
|
"github.com/grafana/grafana/apps/provisioning/pkg/repository"
|
||||||
|
"github.com/grafana/grafana/apps/provisioning/pkg/repository/git"
|
||||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository/github"
|
"github.com/grafana/grafana/apps/provisioning/pkg/repository/github"
|
||||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository/local"
|
"github.com/grafana/grafana/apps/provisioning/pkg/repository/local"
|
||||||
"github.com/grafana/grafana/apps/secret/pkg/decrypt"
|
"github.com/grafana/grafana/apps/secret/pkg/decrypt"
|
||||||
@@ -25,13 +27,15 @@ func ProvideProvisioningOSSRepositoryExtras(
|
|||||||
ghFactory *github.Factory,
|
ghFactory *github.Factory,
|
||||||
webhooksBuilder *webhooks.WebhookExtraBuilder,
|
webhooksBuilder *webhooks.WebhookExtraBuilder,
|
||||||
) []repository.Extra {
|
) []repository.Extra {
|
||||||
|
decrypter := repository.ProvideDecrypter(decryptSvc)
|
||||||
return []repository.Extra{
|
return []repository.Extra{
|
||||||
local.Extra(
|
local.Extra(
|
||||||
cfg.HomePath,
|
cfg.HomePath,
|
||||||
cfg.PermittedProvisioningPaths,
|
cfg.PermittedProvisioningPaths,
|
||||||
),
|
),
|
||||||
|
git.Extra(decrypter),
|
||||||
github.Extra(
|
github.Extra(
|
||||||
repository.ProvideDecrypter(decryptSvc),
|
decrypter,
|
||||||
ghFactory,
|
ghFactory,
|
||||||
webhooksBuilder,
|
webhooksBuilder,
|
||||||
),
|
),
|
||||||
@@ -41,3 +45,12 @@ func ProvideProvisioningOSSRepositoryExtras(
|
|||||||
func ProvideExtraWorkers(pullRequestWorker *pullrequest.PullRequestWorker) []jobs.Worker {
|
func ProvideExtraWorkers(pullRequestWorker *pullrequest.PullRequestWorker) []jobs.Worker {
|
||||||
return []jobs.Worker{pullRequestWorker}
|
return []jobs.Worker{pullRequestWorker}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ProvideFactoryFromConfig(cfg *setting.Cfg, extras []repository.Extra) (repository.Factory, error) {
|
||||||
|
enabledTypes := make(map[apisprovisioning.RepositoryType]struct{}, len(cfg.ProvisioningRepositoryTypes))
|
||||||
|
for _, e := range cfg.ProvisioningRepositoryTypes {
|
||||||
|
enabledTypes[apisprovisioning.RepositoryType(e)] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return repository.ProvideFactory(enabledTypes, extras)
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package apiregistry
|
|||||||
import (
|
import (
|
||||||
"github.com/google/wire"
|
"github.com/google/wire"
|
||||||
|
|
||||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository"
|
|
||||||
dashboardinternal "github.com/grafana/grafana/pkg/registry/apis/dashboard"
|
dashboardinternal "github.com/grafana/grafana/pkg/registry/apis/dashboard"
|
||||||
"github.com/grafana/grafana/pkg/registry/apis/dashboardsnapshot"
|
"github.com/grafana/grafana/pkg/registry/apis/dashboardsnapshot"
|
||||||
"github.com/grafana/grafana/pkg/registry/apis/datasource"
|
"github.com/grafana/grafana/pkg/registry/apis/datasource"
|
||||||
@@ -32,9 +31,9 @@ var WireSetExts = wire.NewSet(
|
|||||||
)
|
)
|
||||||
|
|
||||||
var provisioningExtras = wire.NewSet(
|
var provisioningExtras = wire.NewSet(
|
||||||
repository.ProvideFactory,
|
|
||||||
pullrequest.ProvidePullRequestWorker,
|
pullrequest.ProvidePullRequestWorker,
|
||||||
webhooks.ProvideWebhooksWithImages,
|
webhooks.ProvideWebhooksWithImages,
|
||||||
|
extras.ProvideFactoryFromConfig,
|
||||||
extras.ProvideProvisioningExtraAPIs,
|
extras.ProvideProvisioningExtraAPIs,
|
||||||
extras.ProvideExtraWorkers,
|
extras.ProvideExtraWorkers,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/google/wire"
|
"github.com/google/wire"
|
||||||
httpclient2 "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
httpclient2 "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
||||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository"
|
|
||||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository/github"
|
"github.com/grafana/grafana/apps/provisioning/pkg/repository/github"
|
||||||
"github.com/grafana/grafana/pkg/api"
|
"github.com/grafana/grafana/pkg/api"
|
||||||
"github.com/grafana/grafana/pkg/api/avatar"
|
"github.com/grafana/grafana/pkg/api/avatar"
|
||||||
@@ -830,7 +829,7 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
|
|||||||
}
|
}
|
||||||
factory := github.ProvideFactory()
|
factory := github.ProvideFactory()
|
||||||
v5 := extras.ProvideProvisioningOSSRepositoryExtras(cfg, decryptService, factory, webhookExtraBuilder)
|
v5 := extras.ProvideProvisioningOSSRepositoryExtras(cfg, decryptService, factory, webhookExtraBuilder)
|
||||||
repositoryFactory, err := repository.ProvideFactory(v5)
|
repositoryFactory, err := extras.ProvideFactoryFromConfig(cfg, v5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1419,7 +1418,7 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
|
|||||||
}
|
}
|
||||||
factory := github.ProvideFactory()
|
factory := github.ProvideFactory()
|
||||||
v5 := extras.ProvideProvisioningOSSRepositoryExtras(cfg, decryptService, factory, webhookExtraBuilder)
|
v5 := extras.ProvideProvisioningOSSRepositoryExtras(cfg, decryptService, factory, webhookExtraBuilder)
|
||||||
repositoryFactory, err := repository.ProvideFactory(v5)
|
repositoryFactory, err := extras.ProvideFactoryFromConfig(cfg, v5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ type Cfg struct {
|
|||||||
PermittedProvisioningPaths []string
|
PermittedProvisioningPaths []string
|
||||||
// Provisioning config
|
// Provisioning config
|
||||||
ProvisioningDisableControllers bool
|
ProvisioningDisableControllers bool
|
||||||
|
ProvisioningRepositoryTypes []string
|
||||||
ProvisioningLokiURL string
|
ProvisioningLokiURL string
|
||||||
ProvisioningLokiUser string
|
ProvisioningLokiUser string
|
||||||
ProvisioningLokiPassword string
|
ProvisioningLokiPassword string
|
||||||
@@ -2103,6 +2104,19 @@ func (cfg *Cfg) readProvisioningSettings(iniFile *ini.File) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repositoryTypes := strings.TrimSpace(valueAsString(iniFile.Section("provisioning"), "repository_types", "github|local"))
|
||||||
|
if repositoryTypes != "|" && repositoryTypes != "" {
|
||||||
|
cfg.ProvisioningRepositoryTypes = strings.Split(repositoryTypes, "|")
|
||||||
|
for i, s := range cfg.ProvisioningRepositoryTypes {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
if s == "" {
|
||||||
|
return fmt.Errorf("a provisioning repository type is empty in '%s' (at index %d)", repositoryTypes, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.ProvisioningRepositoryTypes[i] = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cfg.ProvisioningDisableControllers = iniFile.Section("provisioning").Key("disable_controllers").MustBool(false)
|
cfg.ProvisioningDisableControllers = iniFile.Section("provisioning").Key("disable_controllers").MustBool(false)
|
||||||
|
|
||||||
// Read job history configuration
|
// Read job history configuration
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
|
|
||||||
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||||
"github.com/grafana/grafana/pkg/extensions"
|
|
||||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||||
"github.com/grafana/grafana/pkg/tests/apis"
|
"github.com/grafana/grafana/pkg/tests/apis"
|
||||||
"github.com/grafana/grafana/pkg/util/testutil"
|
"github.com/grafana/grafana/pkg/util/testutil"
|
||||||
@@ -134,21 +133,10 @@ func TestIntegrationProvisioning_CreatingAndGetting(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: this should be an enterprise integration test
|
assert.ElementsMatch(collect, []provisioning.RepositoryType{
|
||||||
if extensions.IsEnterprise {
|
provisioning.LocalRepositoryType,
|
||||||
assert.ElementsMatch(collect, []provisioning.RepositoryType{
|
provisioning.GitHubRepositoryType,
|
||||||
provisioning.LocalRepositoryType,
|
}, settings.AvailableRepositoryTypes)
|
||||||
provisioning.GitHubRepositoryType,
|
|
||||||
provisioning.GitRepositoryType,
|
|
||||||
provisioning.BitbucketRepositoryType,
|
|
||||||
provisioning.GitLabRepositoryType,
|
|
||||||
}, settings.AvailableRepositoryTypes)
|
|
||||||
} else {
|
|
||||||
assert.ElementsMatch(collect, []provisioning.RepositoryType{
|
|
||||||
provisioning.LocalRepositoryType,
|
|
||||||
provisioning.GitHubRepositoryType,
|
|
||||||
}, settings.AvailableRepositoryTypes)
|
|
||||||
}
|
|
||||||
}, time.Second*10, time.Millisecond*100, "Expected settings to match")
|
}, time.Second*10, time.Millisecond*100, "Expected settings to match")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user