Provisioning: Migrate use history only with github (#104219)
This commit is contained in:
@@ -5,12 +5,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/client-go/dynamic"
|
||||
|
||||
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/resources"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/client-go/dynamic"
|
||||
)
|
||||
|
||||
func ExportResources(ctx context.Context, options provisioning.ExportJobOptions, clients resources.ResourceClients, repositoryResources resources.RepositoryResources, progress jobs.JobProgressRecorder) error {
|
||||
@@ -37,7 +38,7 @@ func ExportResources(ctx context.Context, options provisioning.ExportJobOptions,
|
||||
|
||||
func exportResource(ctx context.Context, options provisioning.ExportJobOptions, client dynamic.ResourceInterface, repositoryResources resources.RepositoryResources, progress jobs.JobProgressRecorder) error {
|
||||
return resources.ForEach(ctx, client, func(item *unstructured.Unstructured) error {
|
||||
fileName, err := repositoryResources.CreateResourceFileFromObject(ctx, item, resources.WriteOptions{
|
||||
fileName, err := repositoryResources.WriteResourceFileFromObject(ctx, item, resources.WriteOptions{
|
||||
Path: options.Path,
|
||||
Ref: options.Branch,
|
||||
})
|
||||
|
||||
@@ -5,10 +5,6 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
v0alpha1 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/resources"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -17,6 +13,11 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
dynamicfake "k8s.io/client-go/dynamic/fake"
|
||||
k8testing "k8s.io/client-go/testing"
|
||||
|
||||
provisioningV0 "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/resources"
|
||||
)
|
||||
|
||||
func TestExportResources(t *testing.T) {
|
||||
@@ -78,11 +79,11 @@ func TestExportResources(t *testing.T) {
|
||||
Ref: "feature/branch",
|
||||
}
|
||||
|
||||
repoResources.On("CreateResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
repoResources.On("WriteResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
return obj.GetName() == "dashboard-1"
|
||||
}), options).Return("dashboard-1.json", nil)
|
||||
|
||||
repoResources.On("CreateResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
repoResources.On("WriteResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
return obj.GetName() == "dashboard-2"
|
||||
}), options).Return("dashboard-2.json", nil)
|
||||
},
|
||||
@@ -165,11 +166,11 @@ func TestExportResources(t *testing.T) {
|
||||
Ref: "feature/branch",
|
||||
}
|
||||
|
||||
repoResources.On("CreateResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
repoResources.On("WriteResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
return obj.GetName() == "dashboard-1"
|
||||
}), options).Return("", fmt.Errorf("failed to export dashboard"))
|
||||
|
||||
repoResources.On("CreateResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
repoResources.On("WriteResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
return obj.GetName() == "dashboard-2"
|
||||
}), options).Return("dashboard-2.json", nil)
|
||||
},
|
||||
@@ -211,7 +212,7 @@ func TestExportResources(t *testing.T) {
|
||||
Ref: "feature/branch",
|
||||
}
|
||||
|
||||
repoResources.On("CreateResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
repoResources.On("WriteResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
return obj.GetName() == "dashboard-1"
|
||||
}), options).Return("", fmt.Errorf("failed to export dashboard"))
|
||||
},
|
||||
@@ -254,7 +255,7 @@ func TestExportResources(t *testing.T) {
|
||||
}
|
||||
|
||||
// Return true to indicate the file already exists, and provide the updated path
|
||||
repoResources.On("CreateResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
repoResources.On("WriteResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
return obj.GetName() == "existing-dashboard"
|
||||
}), options).Return("", resources.ErrAlreadyInRepository)
|
||||
},
|
||||
@@ -291,7 +292,7 @@ func TestExportResources(t *testing.T) {
|
||||
repoResources := resources.NewMockRepositoryResources(t)
|
||||
tt.setupResources(repoResources, resourceClients, fakeDynamicClient, listGVK)
|
||||
|
||||
options := v0alpha1.ExportJobOptions{
|
||||
options := provisioningV0.ExportJobOptions{
|
||||
Path: "grafana",
|
||||
Branch: "feature/branch",
|
||||
}
|
||||
|
||||
+18
-1
@@ -108,6 +108,7 @@ type legacyResourceResourceMigrator struct {
|
||||
options provisioning.MigrateJobOptions
|
||||
resources resources.RepositoryResources
|
||||
signer signature.Signer
|
||||
history map[string]string // UID >> file path
|
||||
}
|
||||
|
||||
func NewLegacyResourceMigrator(
|
||||
@@ -120,6 +121,10 @@ func NewLegacyResourceMigrator(
|
||||
kind schema.GroupResource,
|
||||
signer signature.Signer,
|
||||
) *legacyResourceResourceMigrator {
|
||||
var history map[string]string
|
||||
if options.History {
|
||||
history = make(map[string]string)
|
||||
}
|
||||
return &legacyResourceResourceMigrator{
|
||||
legacy: legacy,
|
||||
parser: parser,
|
||||
@@ -129,6 +134,7 @@ func NewLegacyResourceMigrator(
|
||||
kind: kind,
|
||||
resources: resources,
|
||||
signer: signer,
|
||||
history: history,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,11 +171,22 @@ func (r *legacyResourceResourceMigrator) Write(ctx context.Context, key *resourc
|
||||
|
||||
// TODO: this seems to be same logic as the export job
|
||||
// TODO: we should use a kind safe manager here
|
||||
fileName, err := r.resources.CreateResourceFileFromObject(ctx, parsed.Obj, resources.WriteOptions{
|
||||
fileName, err := r.resources.WriteResourceFileFromObject(ctx, parsed.Obj, resources.WriteOptions{
|
||||
Path: "",
|
||||
Ref: "",
|
||||
})
|
||||
|
||||
// When replaying history, the path to the file may change over time
|
||||
// This happens when the title or folder change
|
||||
if r.history != nil {
|
||||
name := parsed.Meta.GetName()
|
||||
previous := r.history[name]
|
||||
if previous != "" && previous != fileName {
|
||||
_, _, err = r.resources.RemoveResourceFromFile(ctx, previous, "")
|
||||
}
|
||||
r.history[name] = fileName
|
||||
}
|
||||
|
||||
result := jobs.JobResourceResult{
|
||||
Name: parsed.Meta.GetName(),
|
||||
Resource: r.kind.Resource,
|
||||
+69
-14
@@ -290,8 +290,8 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) {
|
||||
t.Run("records error when create resource file fails", func(t *testing.T) {
|
||||
mockParser := resources.NewMockParser(t)
|
||||
obj := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"name": "test",
|
||||
},
|
||||
},
|
||||
@@ -306,7 +306,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) {
|
||||
}, nil)
|
||||
|
||||
mockRepoResources := resources.NewMockRepositoryResources(t)
|
||||
mockRepoResources.On("CreateResourceFileFromObject", mock.Anything, mock.Anything, mock.Anything).
|
||||
mockRepoResources.On("WriteResourceFileFromObject", mock.Anything, mock.Anything, mock.Anything).
|
||||
Return("", errors.New("create file error"))
|
||||
|
||||
progress := jobs.NewMockJobProgressRecorder(t)
|
||||
@@ -340,8 +340,8 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) {
|
||||
t.Run("should fail when signer fails", func(t *testing.T) {
|
||||
mockParser := resources.NewMockParser(t)
|
||||
obj := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"name": "test",
|
||||
},
|
||||
},
|
||||
@@ -383,8 +383,8 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) {
|
||||
t.Run("should successfully add author signature", func(t *testing.T) {
|
||||
mockParser := resources.NewMockParser(t)
|
||||
obj := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"name": "test",
|
||||
},
|
||||
},
|
||||
@@ -407,7 +407,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) {
|
||||
Return(signedCtx, nil)
|
||||
|
||||
mockRepoResources := resources.NewMockRepositoryResources(t)
|
||||
mockRepoResources.On("CreateResourceFileFromObject", signedCtx, mock.Anything, mock.Anything).
|
||||
mockRepoResources.On("WriteResourceFileFromObject", signedCtx, mock.Anything, mock.Anything).
|
||||
Return("test/path", nil)
|
||||
|
||||
progress := jobs.NewMockJobProgressRecorder(t)
|
||||
@@ -439,11 +439,66 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) {
|
||||
progress.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("should maintain history", func(t *testing.T) {
|
||||
progress := jobs.NewMockJobProgressRecorder(t)
|
||||
progress.On("Record", mock.Anything, mock.Anything).Return()
|
||||
progress.On("TooManyErrors").Return(nil)
|
||||
|
||||
mockParser := resources.NewMockParser(t)
|
||||
obj := &unstructured.Unstructured{
|
||||
Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"name": "test",
|
||||
},
|
||||
},
|
||||
}
|
||||
meta, _ := utils.MetaAccessor(obj)
|
||||
mockParser.On("Parse", mock.Anything, mock.Anything).
|
||||
Return(&resources.ParsedResource{
|
||||
Meta: meta,
|
||||
Obj: obj,
|
||||
}, nil)
|
||||
|
||||
mockRepoResources := resources.NewMockRepositoryResources(t)
|
||||
writeResourceFileFromObject := mockRepoResources.On("WriteResourceFileFromObject", mock.Anything, mock.Anything, mock.Anything)
|
||||
|
||||
migrator := NewLegacyResourceMigrator(
|
||||
nil,
|
||||
mockParser,
|
||||
mockRepoResources,
|
||||
progress,
|
||||
provisioning.MigrateJobOptions{
|
||||
History: true,
|
||||
},
|
||||
"test-namespace",
|
||||
schema.GroupResource{Group: "test.grafana.app", Resource: "tests"},
|
||||
signature.NewGrafanaSigner(),
|
||||
)
|
||||
|
||||
writeResourceFileFromObject.Return("aaaa.json", nil)
|
||||
err := migrator.Write(context.Background(), &resource.ResourceKey{}, []byte(""))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "aaaa.json", migrator.history["test"], "kept track of the old files")
|
||||
|
||||
// Change the result file name
|
||||
writeResourceFileFromObject.Return("bbbb.json", nil)
|
||||
mockRepoResources.On("RemoveResourceFromFile", mock.Anything, "aaaa.json", "").
|
||||
Return("", schema.GroupVersionKind{}, nil).Once()
|
||||
|
||||
err = migrator.Write(context.Background(), &resource.ResourceKey{}, []byte(""))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "bbbb.json", migrator.history["test"], "kept track of the old files")
|
||||
|
||||
mockParser.AssertExpectations(t)
|
||||
mockRepoResources.AssertExpectations(t)
|
||||
progress.AssertExpectations(t)
|
||||
})
|
||||
|
||||
t.Run("should successfully write resource", func(t *testing.T) {
|
||||
mockParser := resources.NewMockParser(t)
|
||||
obj := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"name": "test",
|
||||
},
|
||||
},
|
||||
@@ -471,7 +526,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) {
|
||||
}, nil)
|
||||
|
||||
mockRepoResources := resources.NewMockRepositoryResources(t)
|
||||
mockRepoResources.On("CreateResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
mockRepoResources.On("WriteResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool {
|
||||
if obj == nil {
|
||||
return false
|
||||
}
|
||||
@@ -524,8 +579,8 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) {
|
||||
t.Run("should fail when too many errors", func(t *testing.T) {
|
||||
mockParser := resources.NewMockParser(t)
|
||||
obj := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"name": "test",
|
||||
},
|
||||
},
|
||||
@@ -540,7 +595,7 @@ func TestLegacyResourceResourceMigrator_Write(t *testing.T) {
|
||||
}, nil)
|
||||
|
||||
mockRepoResources := resources.NewMockRepositoryResources(t)
|
||||
mockRepoResources.On("CreateResourceFileFromObject", mock.Anything, mock.Anything, resources.WriteOptions{}).
|
||||
mockRepoResources.On("WriteResourceFileFromObject", mock.Anything, mock.Anything, resources.WriteOptions{}).
|
||||
Return("test/path", nil)
|
||||
|
||||
progress := jobs.NewMockJobProgressRecorder(t)
|
||||
@@ -50,9 +50,19 @@ func (w *MigrationWorker) Process(ctx context.Context, repo repository.Repositor
|
||||
return errors.New("migration job submitted targeting repository that is not a ReaderWriter")
|
||||
}
|
||||
|
||||
if options.History {
|
||||
if repo.Config().Spec.Type != provisioning.GitHubRepositoryType {
|
||||
return errors.New("history is only supported for github repositories")
|
||||
}
|
||||
}
|
||||
|
||||
if dualwrite.IsReadingLegacyDashboardsAndFolders(ctx, w.storageStatus) {
|
||||
return w.legacyMigrator.Migrate(ctx, rw, *options, progress)
|
||||
}
|
||||
|
||||
if options.History {
|
||||
return errors.New("history is not yet supported in unified storage")
|
||||
}
|
||||
|
||||
return w.unifiedMigrator.Migrate(ctx, rw, *options, progress)
|
||||
}
|
||||
|
||||
@@ -68,6 +68,50 @@ func TestMigrationWorker_ProcessNotReaderWriter(t *testing.T) {
|
||||
require.EqualError(t, err, "migration job submitted targeting repository that is not a ReaderWriter")
|
||||
}
|
||||
|
||||
func TestMigrationWorker_WithHistory(t *testing.T) {
|
||||
fakeDualwrite := dualwrite.NewMockService(t)
|
||||
fakeDualwrite.On("ReadFromUnified", mock.Anything, mock.Anything).
|
||||
Maybe().Return(true, nil) // using unified storage
|
||||
|
||||
worker := NewMigrationWorker(nil, nil, fakeDualwrite)
|
||||
job := provisioning.Job{
|
||||
Spec: provisioning.JobSpec{
|
||||
Action: provisioning.JobActionMigrate,
|
||||
Migrate: &provisioning.MigrateJobOptions{
|
||||
History: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("fail local", func(t *testing.T) {
|
||||
progressRecorder := jobs.NewMockJobProgressRecorder(t)
|
||||
progressRecorder.On("SetTotal", mock.Anything, 10).Return()
|
||||
progressRecorder.On("Strict").Return()
|
||||
|
||||
repo := repository.NewLocal(&provisioning.Repository{}, nil)
|
||||
err := worker.Process(context.Background(), repo, job, progressRecorder)
|
||||
require.EqualError(t, err, "history is only supported for github repositories")
|
||||
})
|
||||
|
||||
t.Run("fail unified", func(t *testing.T) {
|
||||
progressRecorder := jobs.NewMockJobProgressRecorder(t)
|
||||
progressRecorder.On("SetTotal", mock.Anything, 10).Return()
|
||||
progressRecorder.On("Strict").Return()
|
||||
|
||||
repo := repository.NewMockRepository(t)
|
||||
repo.On("Config").Return(&provisioning.Repository{
|
||||
Spec: provisioning.RepositorySpec{
|
||||
Type: provisioning.GitHubRepositoryType,
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
URL: "empty", // not valid
|
||||
},
|
||||
},
|
||||
})
|
||||
err := worker.Process(context.Background(), repo, job, progressRecorder)
|
||||
require.EqualError(t, err, "history is not yet supported in unified storage")
|
||||
})
|
||||
}
|
||||
|
||||
func TestMigrationWorker_Process(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -145,7 +145,7 @@ func (r *localRepository) Validate() field.ErrorList {
|
||||
// Test implements provisioning.Repository.
|
||||
// NOTE: Validate has been called (and passed) before this function should be called
|
||||
func (r *localRepository) Test(ctx context.Context) (*provisioning.TestResults, error) {
|
||||
path := field.NewPath("spec", "localhost", "path")
|
||||
path := field.NewPath("spec", "local", "path")
|
||||
if r.config.Spec.Local.Path == "" {
|
||||
return fromFieldError(field.Required(path, "no path is configured")), nil
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning/repository"
|
||||
)
|
||||
|
||||
//go:generate mockery --name RepositoryResourcesFactory --structname MockRepositoryResourcesFactory --inpackage --filename repository_resources_factory_mock.go --with-expecter
|
||||
@@ -23,7 +24,7 @@ type RepositoryResources interface {
|
||||
EnsureFolderExists(ctx context.Context, folder Folder, parentID string) error
|
||||
EnsureFolderTreeExists(ctx context.Context, ref, path string, tree FolderTree, fn func(folder Folder, created bool, err error) error) error
|
||||
// File from Resource
|
||||
CreateResourceFileFromObject(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions) (string, error)
|
||||
WriteResourceFileFromObject(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions) (string, error)
|
||||
// Resource from file
|
||||
WriteResourceFromFile(ctx context.Context, path, ref string) (string, schema.GroupVersionKind, error)
|
||||
RemoveResourceFromFile(ctx context.Context, path, ref string) (string, schema.GroupVersionKind, error)
|
||||
|
||||
@@ -26,12 +26,12 @@ func (_m *MockRepositoryResources) EXPECT() *MockRepositoryResources_Expecter {
|
||||
return &MockRepositoryResources_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// CreateResourceFileFromObject provides a mock function with given fields: ctx, obj, options
|
||||
func (_m *MockRepositoryResources) CreateResourceFileFromObject(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions) (string, error) {
|
||||
// WriteResourceFileFromObject provides a mock function with given fields: ctx, obj, options
|
||||
func (_m *MockRepositoryResources) WriteResourceFileFromObject(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions) (string, error) {
|
||||
ret := _m.Called(ctx, obj, options)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CreateResourceFileFromObject")
|
||||
panic("no return value specified for WriteResourceFileFromObject")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
@@ -54,32 +54,32 @@ func (_m *MockRepositoryResources) CreateResourceFileFromObject(ctx context.Cont
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockRepositoryResources_CreateResourceFileFromObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateResourceFileFromObject'
|
||||
type MockRepositoryResources_CreateResourceFileFromObject_Call struct {
|
||||
// MockRepositoryResources_WriteResourceFileFromObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteResourceFileFromObject'
|
||||
type MockRepositoryResources_WriteResourceFileFromObject_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CreateResourceFileFromObject is a helper method to define mock.On call
|
||||
// WriteResourceFileFromObject is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - obj *unstructured.Unstructured
|
||||
// - options WriteOptions
|
||||
func (_e *MockRepositoryResources_Expecter) CreateResourceFileFromObject(ctx interface{}, obj interface{}, options interface{}) *MockRepositoryResources_CreateResourceFileFromObject_Call {
|
||||
return &MockRepositoryResources_CreateResourceFileFromObject_Call{Call: _e.mock.On("CreateResourceFileFromObject", ctx, obj, options)}
|
||||
func (_e *MockRepositoryResources_Expecter) WriteResourceFileFromObject(ctx interface{}, obj interface{}, options interface{}) *MockRepositoryResources_WriteResourceFileFromObject_Call {
|
||||
return &MockRepositoryResources_WriteResourceFileFromObject_Call{Call: _e.mock.On("WriteResourceFileFromObject", ctx, obj, options)}
|
||||
}
|
||||
|
||||
func (_c *MockRepositoryResources_CreateResourceFileFromObject_Call) Run(run func(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions)) *MockRepositoryResources_CreateResourceFileFromObject_Call {
|
||||
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) Run(run func(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions)) *MockRepositoryResources_WriteResourceFileFromObject_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*unstructured.Unstructured), args[2].(WriteOptions))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockRepositoryResources_CreateResourceFileFromObject_Call) Return(_a0 string, _a1 error) *MockRepositoryResources_CreateResourceFileFromObject_Call {
|
||||
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) Return(_a0 string, _a1 error) *MockRepositoryResources_WriteResourceFileFromObject_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockRepositoryResources_CreateResourceFileFromObject_Call) RunAndReturn(run func(context.Context, *unstructured.Unstructured, WriteOptions) (string, error)) *MockRepositoryResources_CreateResourceFileFromObject_Call {
|
||||
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) RunAndReturn(run func(context.Context, *unstructured.Unstructured, WriteOptions) (string, error)) *MockRepositoryResources_WriteResourceFileFromObject_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package resources
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
@@ -54,7 +53,7 @@ func NewResourcesManager(repo repository.ReaderWriter, folders *FolderManager, p
|
||||
}
|
||||
|
||||
// CreateResource writes an object to the repository
|
||||
func (r *ResourcesManager) CreateResourceFileFromObject(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions) (string, error) {
|
||||
func (r *ResourcesManager) WriteResourceFileFromObject(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions) (string, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return "", fmt.Errorf("context error: %w", err)
|
||||
}
|
||||
@@ -81,7 +80,7 @@ func (r *ResourcesManager) CreateResourceFileFromObject(ctx context.Context, obj
|
||||
}
|
||||
|
||||
manager, _ := meta.GetManagerProperties()
|
||||
// TODO: how we should handle this?
|
||||
// TODO: how should we handle this?
|
||||
if manager.Identity == r.repo.Config().GetName() {
|
||||
// If it's already in the repository, we don't need to write it
|
||||
return "", ErrAlreadyInRepository
|
||||
@@ -100,17 +99,6 @@ func (r *ResourcesManager) CreateResourceFileFromObject(ctx context.Context, obj
|
||||
return "", fmt.Errorf("folder not found in tree: %s", folder)
|
||||
}
|
||||
|
||||
// Clear the metadata
|
||||
delete(obj.Object, "metadata")
|
||||
|
||||
// Always write the identifier
|
||||
meta.SetName(name)
|
||||
|
||||
body, err := json.MarshalIndent(obj.Object, "", " ")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal dashboard: %w", err)
|
||||
}
|
||||
|
||||
fileName := slugify.Slugify(title) + ".json"
|
||||
if fid.Path != "" {
|
||||
fileName = safepath.Join(fid.Path, fileName)
|
||||
@@ -119,6 +107,18 @@ func (r *ResourcesManager) CreateResourceFileFromObject(ctx context.Context, obj
|
||||
fileName = safepath.Join(options.Path, fileName)
|
||||
}
|
||||
|
||||
parsed := ParsedResource{
|
||||
Info: &repository.FileInfo{
|
||||
Path: fileName,
|
||||
Ref: options.Ref,
|
||||
},
|
||||
Obj: obj,
|
||||
}
|
||||
body, err := parsed.ToSaveBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = r.repo.Write(ctx, fileName, options.Ref, body, commitMessage)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to write file: %w", err)
|
||||
|
||||
@@ -17,7 +17,8 @@ export interface SynchronizeStepProps {
|
||||
export function SynchronizeStep({ onStepStatusUpdate, requiresMigration }: SynchronizeStepProps) {
|
||||
const [createJob] = useCreateRepositoryJobsMutation();
|
||||
const { getValues, register, watch } = useFormContext<WizardFormData>();
|
||||
const target = watch('repository.sync.target');
|
||||
const repoType = watch('repository.type');
|
||||
const supportsHistory = requiresMigration && repoType === 'github';
|
||||
const [job, setJob] = useState<Job>();
|
||||
|
||||
const startSynchronization = async () => {
|
||||
@@ -35,7 +36,7 @@ export function SynchronizeStep({ onStepStatusUpdate, requiresMigration }: Synch
|
||||
const jobSpec = requiresMigration
|
||||
? {
|
||||
migrate: {
|
||||
history,
|
||||
history: history && supportsHistory,
|
||||
},
|
||||
}
|
||||
: {
|
||||
@@ -111,7 +112,7 @@ export function SynchronizeStep({ onStepStatusUpdate, requiresMigration }: Synch
|
||||
</li>
|
||||
</ul>
|
||||
</Alert>
|
||||
{requiresMigration && target !== 'folder' && (
|
||||
{supportsHistory && (
|
||||
<>
|
||||
<Text element="h3">
|
||||
<Trans i18nKey="provisioning.synchronize-step.synchronization-options">Synchronization options</Trans>
|
||||
|
||||
Reference in New Issue
Block a user