Provisioning: Move repository file API (#108514)

* Bump nanogit version
* Embed git repository in the Github one
This commit is contained in:
Roberto Jiménez Sánchez
2025-07-24 23:28:59 -05:00
committed by GitHub
parent 22bcd4dab4
commit 16339b0788
24 changed files with 2011 additions and 99 deletions
@@ -453,6 +453,56 @@ func (_c *MockGithubRepository_ListRefs_Call) RunAndReturn(run func(context.Cont
return _c
}
// Move provides a mock function with given fields: ctx, oldPath, newPath, ref, message
func (_m *MockGithubRepository) Move(ctx context.Context, oldPath string, newPath string, ref string, message string) error {
ret := _m.Called(ctx, oldPath, newPath, ref, message)
if len(ret) == 0 {
panic("no return value specified for Move")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok {
r0 = rf(ctx, oldPath, newPath, ref, message)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockGithubRepository_Move_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Move'
type MockGithubRepository_Move_Call struct {
*mock.Call
}
// Move is a helper method to define mock.On call
// - ctx context.Context
// - oldPath string
// - newPath string
// - ref string
// - message string
func (_e *MockGithubRepository_Expecter) Move(ctx interface{}, oldPath interface{}, newPath interface{}, ref interface{}, message interface{}) *MockGithubRepository_Move_Call {
return &MockGithubRepository_Move_Call{Call: _e.mock.On("Move", ctx, oldPath, newPath, ref, message)}
}
func (_c *MockGithubRepository_Move_Call) Run(run func(ctx context.Context, oldPath string, newPath string, ref string, message string)) *MockGithubRepository_Move_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(string))
})
return _c
}
func (_c *MockGithubRepository_Move_Call) Return(_a0 error) *MockGithubRepository_Move_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockGithubRepository_Move_Call) RunAndReturn(run func(context.Context, string, string, string, string) error) *MockGithubRepository_Move_Call {
_c.Call.Return(run)
return _c
}
// OnCreate provides a mock function with given fields: ctx
func (_m *MockGithubRepository) OnCreate(ctx context.Context) ([]map[string]interface{}, error) {
ret := _m.Called(ctx)
@@ -22,7 +22,7 @@ const githubTokenSecretSuffix = "-github-token"
// Make sure all public functions of this struct call the (*githubRepository).logger function, to ensure the GH repo details are included.
type githubRepository struct {
gitRepo git.GitRepository
git.GitRepository
config *provisioning.Repository
gh Client // assumes github.com base URL
secrets secrets.RepositorySecrets
@@ -62,19 +62,15 @@ func NewGitHub(
}
return &githubRepository{
config: config,
gitRepo: gitRepo,
gh: factory.New(ctx, token), // TODO, baseURL from config
owner: owner,
repo: repo,
secrets: secrets,
config: config,
GitRepository: gitRepo,
gh: factory.New(ctx, token), // TODO, baseURL from config
owner: owner,
repo: repo,
secrets: secrets,
}, nil
}
func (r *githubRepository) Config() *provisioning.Repository {
return r.gitRepo.Config()
}
func (r *githubRepository) Owner() string {
return r.owner
}
@@ -89,7 +85,7 @@ func (r *githubRepository) Client() Client {
// Validate implements provisioning.Repository.
func (r *githubRepository) Validate() (list field.ErrorList) {
cfg := r.gitRepo.Config()
cfg := r.Config()
gh := cfg.Spec.GitHub
if gh == nil {
list = append(list, field.Required(field.NewPath("spec", "github"), "a github config is required"))
@@ -110,7 +106,7 @@ func (r *githubRepository) Validate() (list field.ErrorList) {
return list
}
return r.gitRepo.Validate()
return r.GitRepository.Validate()
}
func ParseOwnerRepoGithub(giturl string) (owner string, repo string, err error) {
@@ -139,32 +135,7 @@ func (r *githubRepository) Test(ctx context.Context) (*provisioning.TestResults,
field.NewPath("spec", "github", "url"), url, err.Error())), nil
}
return r.gitRepo.Test(ctx)
}
// ReadResource implements provisioning.Repository.
func (r *githubRepository) Read(ctx context.Context, filePath, ref string) (*repository.FileInfo, error) {
return r.gitRepo.Read(ctx, filePath, ref)
}
func (r *githubRepository) ReadTree(ctx context.Context, ref string) ([]repository.FileTreeEntry, error) {
return r.gitRepo.ReadTree(ctx, ref)
}
func (r *githubRepository) Create(ctx context.Context, path, ref string, data []byte, comment string) error {
return r.gitRepo.Create(ctx, path, ref, data, comment)
}
func (r *githubRepository) Update(ctx context.Context, path, ref string, data []byte, comment string) error {
return r.gitRepo.Update(ctx, path, ref, data, comment)
}
func (r *githubRepository) Write(ctx context.Context, path string, ref string, data []byte, message string) error {
return r.gitRepo.Write(ctx, path, ref, data, message)
}
func (r *githubRepository) Delete(ctx context.Context, path, ref, comment string) error {
return r.gitRepo.Delete(ctx, path, ref, comment)
return r.GitRepository.Test(ctx)
}
func (r *githubRepository) History(ctx context.Context, path, ref string) ([]provisioning.HistoryItem, error) {
@@ -214,7 +185,7 @@ func (r *githubRepository) History(ctx context.Context, path, ref string) ([]pro
// ListRefs list refs from the git repository and add the ref URL to the ref item
func (r *githubRepository) ListRefs(ctx context.Context) ([]provisioning.RefItem, error) {
refs, err := r.gitRepo.ListRefs(ctx)
refs, err := r.GitRepository.ListRefs(ctx)
if err != nil {
return nil, fmt.Errorf("list refs: %w", err)
}
@@ -226,14 +197,6 @@ func (r *githubRepository) ListRefs(ctx context.Context) ([]provisioning.RefItem
return refs, nil
}
func (r *githubRepository) LatestRef(ctx context.Context) (string, error) {
return r.gitRepo.LatestRef(ctx)
}
func (r *githubRepository) CompareFiles(ctx context.Context, base, ref string) ([]repository.VersionedFileChange, error) {
return r.gitRepo.CompareFiles(ctx, base, ref)
}
// ResourceURLs implements RepositoryWithURLs.
func (r *githubRepository) ResourceURLs(ctx context.Context, file *repository.FileInfo) (*provisioning.ResourceURLs, error) {
cfg := r.config.Spec.GitHub
@@ -261,10 +224,6 @@ func (r *githubRepository) ResourceURLs(ctx context.Context, file *repository.Fi
return urls, nil
}
func (r *githubRepository) Stage(ctx context.Context, opts repository.StageOptions) (repository.StagedRepository, error) {
return r.gitRepo.Stage(ctx, opts)
}
func (r *githubRepository) OnCreate(_ context.Context) ([]map[string]interface{}, error) {
return nil, nil
}
@@ -105,7 +105,7 @@ func TestNewGitHub(t *testing.T) {
assert.Equal(t, tt.expectedRepo, repo.Repo())
concreteRepo, ok := repo.(*githubRepository)
require.True(t, ok)
assert.Equal(t, gitRepo, concreteRepo.gitRepo)
assert.Equal(t, gitRepo, concreteRepo.GitRepository)
}
})
}
@@ -301,8 +301,8 @@ func TestGitHubRepositoryValidate(t *testing.T) {
}
repo := &githubRepository{
config: tt.config,
gitRepo: mockGitRepo,
config: tt.config,
GitRepository: mockGitRepo,
}
errors := repo.Validate()
@@ -388,10 +388,10 @@ func TestGitHubRepositoryTest(t *testing.T) {
}
repo := &githubRepository{
config: tt.config,
gitRepo: mockGitRepo,
owner: "grafana",
repo: "grafana",
config: tt.config,
GitRepository: mockGitRepo,
owner: "grafana",
repo: "grafana",
}
result, err := repo.Test(context.Background())
@@ -802,8 +802,8 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
mockGitRepo.On("Config").Return(config)
repo := &githubRepository{
config: config,
gitRepo: mockGitRepo,
config: config,
GitRepository: mockGitRepo,
}
result := repo.Config()
@@ -822,8 +822,8 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
mockGitRepo.On("Read", ctx, "test.yaml", "main").Return(expectedFileInfo, nil)
repo := &githubRepository{
config: config,
gitRepo: mockGitRepo,
config: config,
GitRepository: mockGitRepo,
}
result, err := repo.Read(ctx, "test.yaml", "main")
@@ -840,8 +840,8 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
mockGitRepo.On("ReadTree", ctx, "main").Return(expectedEntries, nil)
repo := &githubRepository{
config: config,
gitRepo: mockGitRepo,
config: config,
GitRepository: mockGitRepo,
}
result, err := repo.ReadTree(ctx, "main")
@@ -856,8 +856,8 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
mockGitRepo.On("Create", ctx, "new-file.yaml", "main", data, "Create new file").Return(nil)
repo := &githubRepository{
config: config,
gitRepo: mockGitRepo,
config: config,
GitRepository: mockGitRepo,
}
err := repo.Create(ctx, "new-file.yaml", "main", data, "Create new file")
@@ -871,8 +871,8 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
mockGitRepo.On("Update", ctx, "existing-file.yaml", "main", data, "Update file").Return(nil)
repo := &githubRepository{
config: config,
gitRepo: mockGitRepo,
config: config,
GitRepository: mockGitRepo,
}
err := repo.Update(ctx, "existing-file.yaml", "main", data, "Update file")
@@ -886,8 +886,8 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
mockGitRepo.On("Write", ctx, "file.yaml", "main", data, "Write file").Return(nil)
repo := &githubRepository{
config: config,
gitRepo: mockGitRepo,
config: config,
GitRepository: mockGitRepo,
}
err := repo.Write(ctx, "file.yaml", "main", data, "Write file")
@@ -900,8 +900,8 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
mockGitRepo.On("Delete", ctx, "file.yaml", "main", "Delete file").Return(nil)
repo := &githubRepository{
config: config,
gitRepo: mockGitRepo,
config: config,
GitRepository: mockGitRepo,
}
err := repo.Delete(ctx, "file.yaml", "main", "Delete file")
@@ -915,8 +915,8 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
mockGitRepo.On("LatestRef", ctx).Return(expectedRef, nil)
repo := &githubRepository{
config: config,
gitRepo: mockGitRepo,
config: config,
GitRepository: mockGitRepo,
}
result, err := repo.LatestRef(ctx)
@@ -935,8 +935,8 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
mockGitRepo.On("ListRefs", ctx).Return(gitRepoRefs, nil)
repo := &githubRepository{
config: config,
gitRepo: mockGitRepo,
config: config,
GitRepository: mockGitRepo,
}
result, err := repo.ListRefs(ctx)
@@ -971,8 +971,8 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
mockGitRepo.On("CompareFiles", ctx, "main", "feature-branch").Return(expectedChanges, nil)
repo := &githubRepository{
config: config,
gitRepo: mockGitRepo,
config: config,
GitRepository: mockGitRepo,
}
result, err := repo.CompareFiles(ctx, "main", "feature-branch")
@@ -991,8 +991,8 @@ func TestGitHubRepositoryDelegation(t *testing.T) {
mockGitRepo.On("Stage", ctx, opts).Return(mockStagedRepo, nil)
repo := &githubRepository{
config: config,
gitRepo: mockGitRepo,
config: config,
GitRepository: mockGitRepo,
}
result, err := repo.Stage(ctx, opts)
@@ -1126,3 +1126,92 @@ func TestGitHubRepository_OnDelete(t *testing.T) {
})
}
}
func TestGithubRepository_Move(t *testing.T) {
tests := []struct {
name string
oldPath string
newPath string
ref string
comment string
setupMock func(*git.MockGitRepository)
expectedErr error
}{
{
name: "successful move delegates to git repository",
oldPath: "old.yaml",
newPath: "new.yaml",
ref: "main",
comment: "move file",
setupMock: func(mockGitRepo *git.MockGitRepository) {
mockGitRepo.EXPECT().Move(context.Background(), "old.yaml", "new.yaml", "main", "move file").Return(nil)
},
expectedErr: nil,
},
{
name: "move error from git repository",
oldPath: "old.yaml",
newPath: "new.yaml",
ref: "main",
comment: "move file",
setupMock: func(mockGitRepo *git.MockGitRepository) {
mockGitRepo.EXPECT().Move(context.Background(), "old.yaml", "new.yaml", "main", "move file").Return(errors.New("git move failed"))
},
expectedErr: errors.New("git move failed"),
},
{
name: "successful directory move",
oldPath: "old/",
newPath: "new/",
ref: "main",
comment: "move directory",
setupMock: func(mockGitRepo *git.MockGitRepository) {
mockGitRepo.EXPECT().Move(context.Background(), "old/", "new/", "main", "move directory").Return(nil)
},
expectedErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create mock git repository
mockGitRepo := git.NewMockGitRepository(t)
mockSecrets := &secrets.MockRepositorySecrets{}
// Setup mock expectations
tt.setupMock(mockGitRepo)
// Create GitHub repository
config := &provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "test-repo",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitHubRepositoryType,
GitHub: &provisioning.GitHubRepositoryConfig{
URL: "https://github.com/example/repo",
},
},
}
githubRepo := &githubRepository{
config: config,
GitRepository: mockGitRepo,
owner: "example",
repo: "repo",
secrets: mockSecrets,
}
// Execute move operation
err := githubRepo.Move(context.Background(), tt.oldPath, tt.newPath, tt.ref, tt.comment)
// Verify results
if tt.expectedErr != nil {
require.Error(t, err)
assert.Equal(t, tt.expectedErr.Error(), err.Error())
} else {
require.NoError(t, err)
}
})
}
}