From cee9d09fa64bd292852007187ab3e585ab8cb01b Mon Sep 17 00:00:00 2001 From: golemiso <3282656+golemiso@users.noreply.github.com> Date: Tue, 12 Nov 2024 00:23:57 +0900 Subject: [PATCH] Update application git path on piped started Signed-off-by: golemiso <3282656+golemiso@users.noreply.github.com> --- pkg/app/server/grpcapi/piped_api.go | 54 ++++ pkg/app/server/grpcapi/piped_api_test.go | 283 ++++++++++++++++++ pkg/datastore/applicationstore.go | 8 + pkg/datastore/datastoretest/datastore.mock.go | 14 + 4 files changed, 359 insertions(+) diff --git a/pkg/app/server/grpcapi/piped_api.go b/pkg/app/server/grpcapi/piped_api.go index 337e0c45f3..508fd7ef43 100644 --- a/pkg/app/server/grpcapi/piped_api.go +++ b/pkg/app/server/grpcapi/piped_api.go @@ -49,6 +49,7 @@ type pipedAPIApplicationStore interface { UpdateDeployingStatus(ctx context.Context, id string, deploying bool) error UpdateBasicInfo(ctx context.Context, id, name, desc string, labels map[string]string) error UpdateMostRecentDeployment(ctx context.Context, id string, status model.DeploymentStatus, d *model.ApplicationDeploymentReference) error + UpdateGitPath(ctx context.Context, id string, gitPath *model.ApplicationGitPath) error } type pipedAPIDeploymentStore interface { @@ -198,6 +199,12 @@ func (a *PipedAPI) ReportPipedMeta(ctx context.Context, req *pipedservice.Report if err != nil { return nil, err } + + // application git path may be changed. + if err := a.updateApplicationsGitPath(ctx, piped); err != nil { + return nil, err + } + return &pipedservice.ReportPipedMetaResponse{ Name: piped.Name, WebBaseUrl: a.webBaseURL, @@ -1197,3 +1204,50 @@ func (a *PipedAPI) validateDeploymentBelongsToPiped(ctx context.Context, deploym return nil } + +// updateApplicationsGitPath updates the git path in order to reflect the changes in the piped. +func (a *PipedAPI) updateApplicationsGitPath(ctx context.Context, piped *model.Piped) error { + opts := datastore.ListOptions{ + Filters: []datastore.ListFilter{ + { + Field: "ProjectId", + Operator: datastore.OperatorEqual, + Value: piped.ProjectId, + }, + { + Field: "PipedId", + Operator: datastore.OperatorEqual, + Value: piped.Id, + }, + { + Field: "Disabled", + Operator: datastore.OperatorEqual, + Value: false, + }, + }, + } + apps, _, err := a.applicationStore.List(ctx, opts) + if err != nil { + return gRPCStoreError(err, "fetch applications") + } + for _, app := range apps { + gitpath, err := makeGitPath( + app.GitPath.Repo.Id, + app.GitPath.Path, + app.GitPath.ConfigFilename, + piped, + a.logger, + ) + if err != nil { + return err + } + if gitpath.Repo.Branch == app.GitPath.Repo.Branch && + gitpath.Repo.Remote == app.GitPath.Repo.Remote { + continue + } + if err := a.applicationStore.UpdateGitPath(ctx, app.Id, gitpath); err != nil { + return gRPCStoreError(err, fmt.Sprintf("update git path of application %s", app.Id)) + } + } + return nil +} diff --git a/pkg/app/server/grpcapi/piped_api_test.go b/pkg/app/server/grpcapi/piped_api_test.go index fcec8bda86..49f8fc59fb 100644 --- a/pkg/app/server/grpcapi/piped_api_test.go +++ b/pkg/app/server/grpcapi/piped_api_test.go @@ -21,6 +21,7 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "go.uber.org/zap" "github.com/pipe-cd/pipecd/pkg/cache" "github.com/pipe-cd/pipecd/pkg/cache/cachetest" @@ -212,3 +213,285 @@ func TestValidateDeploymentBelongsToPiped(t *testing.T) { }) } } + +func TestUpdateApplicationsGitPath(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + tests := []struct { + name string + piped *model.Piped + applicationStore datastore.ApplicationStore + wantErr bool + }{ + { + name: "failed to list applications", + piped: &model.Piped{ + Id: "pipedID", + ProjectId: "projectID", + }, + applicationStore: func() datastore.ApplicationStore { + s := datastoretest.NewMockApplicationStore(ctrl) + opts := datastore.ListOptions{ + Filters: []datastore.ListFilter{ + { + Field: "ProjectId", + Operator: datastore.OperatorEqual, + Value: "projectID", + }, + { + Field: "PipedId", + Operator: datastore.OperatorEqual, + Value: "pipedID", + }, + { + Field: "Disabled", + Operator: datastore.OperatorEqual, + Value: false, + }, + }, + } + s.EXPECT().List(gomock.Any(), opts). + Return(nil, "", assert.AnError) + return s + }(), + wantErr: true, + }, + { + name: "no need to update", + piped: &model.Piped{ + Id: "pipedID", + ProjectId: "projectID", + Repositories: []*model.ApplicationGitRepository{ + { + Id: "repoID", + Remote: "https://test-repo.git", + Branch: "branch", + }, + }, + }, + applicationStore: func() datastore.ApplicationStore { + s := datastoretest.NewMockApplicationStore(ctrl) + opts := datastore.ListOptions{ + Filters: []datastore.ListFilter{ + { + Field: "ProjectId", + Operator: datastore.OperatorEqual, + Value: "projectID", + }, + { + Field: "PipedId", + Operator: datastore.OperatorEqual, + Value: "pipedID", + }, + { + Field: "Disabled", + Operator: datastore.OperatorEqual, + Value: false, + }, + }, + } + s.EXPECT().List(gomock.Any(), opts). + Return([]*model.Application{ + { + Id: "appID", + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{ + Id: "repoID", + Remote: "https://test-repo.git", + Branch: "branch", + }, + }, + }, + }, "", nil) + return s + }(), + wantErr: false, + }, + { + name: "failed to make git path", + piped: &model.Piped{ + Id: "pipedID", + ProjectId: "projectID", + Repositories: []*model.ApplicationGitRepository{ + { + Id: "repoID", + Remote: "https://test-repo.git", + Branch: "", + }, + }, + }, + applicationStore: func() datastore.ApplicationStore { + s := datastoretest.NewMockApplicationStore(ctrl) + opts := datastore.ListOptions{ + Filters: []datastore.ListFilter{ + { + Field: "ProjectId", + Operator: datastore.OperatorEqual, + Value: "projectID", + }, + { + Field: "PipedId", + Operator: datastore.OperatorEqual, + Value: "pipedID", + }, + { + Field: "Disabled", + Operator: datastore.OperatorEqual, + Value: false, + }, + }, + } + s.EXPECT().List(gomock.Any(), opts). + Return([]*model.Application{ + { + Id: "appID", + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{ + Id: "repoID", + Remote: "https://test-repo.git", + Branch: "branch", + }, + }, + }, + }, "", nil) + return s + }(), + wantErr: true, + }, + { + name: "failed to update git path", + piped: &model.Piped{ + Id: "pipedID", + ProjectId: "projectID", + Repositories: []*model.ApplicationGitRepository{ + { + Id: "repoID", + Remote: "https://test-repo.git", + Branch: "branch-changed", + }, + }, + }, + applicationStore: func() datastore.ApplicationStore { + s := datastoretest.NewMockApplicationStore(ctrl) + opts := datastore.ListOptions{ + Filters: []datastore.ListFilter{ + { + Field: "ProjectId", + Operator: datastore.OperatorEqual, + Value: "projectID", + }, + { + Field: "PipedId", + Operator: datastore.OperatorEqual, + Value: "pipedID", + }, + { + Field: "Disabled", + Operator: datastore.OperatorEqual, + Value: false, + }, + }, + } + s.EXPECT().List(gomock.Any(), opts). + Return([]*model.Application{ + { + Id: "appID", + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{ + Id: "repoID", + Remote: "https://test-repo.git", + Branch: "branch", + }, + }, + }, + }, "", nil) + gitpath := &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{ + Id: "repoID", + Remote: "https://test-repo.git", + Branch: "branch-changed", + }, + Url: "https://test-repo.git//tree/branch-changed/", + } + s.EXPECT().UpdateGitPath(gomock.Any(), "appID", gitpath). + Return(assert.AnError) + return s + }(), + wantErr: true, + }, + { + name: "successfully updated", + piped: &model.Piped{ + Id: "pipedID", + ProjectId: "projectID", + Repositories: []*model.ApplicationGitRepository{ + { + Id: "repoID", + Remote: "https://test-repo.git", + Branch: "branch-changed", + }, + }, + }, + applicationStore: func() datastore.ApplicationStore { + s := datastoretest.NewMockApplicationStore(ctrl) + opts := datastore.ListOptions{ + Filters: []datastore.ListFilter{ + { + Field: "ProjectId", + Operator: datastore.OperatorEqual, + Value: "projectID", + }, + { + Field: "PipedId", + Operator: datastore.OperatorEqual, + Value: "pipedID", + }, + { + Field: "Disabled", + Operator: datastore.OperatorEqual, + Value: false, + }, + }, + } + s.EXPECT().List(gomock.Any(), opts). + Return([]*model.Application{ + { + Id: "appID", + GitPath: &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{ + Id: "repoID", + Remote: "https://test-repo.git", + Branch: "branch", + }, + }, + }, + }, "", nil) + gitpath := &model.ApplicationGitPath{ + Repo: &model.ApplicationGitRepository{ + Id: "repoID", + Remote: "https://test-repo.git", + Branch: "branch-changed", + }, + Url: "https://test-repo.git//tree/branch-changed/", + } + s.EXPECT().UpdateGitPath(gomock.Any(), "appID", gitpath). + Return(nil) + return s + }(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + api := &PipedAPI{ + applicationStore: tt.applicationStore, + logger: zap.NewNop(), + } + err := api.updateApplicationsGitPath(ctx, tt.piped) + assert.Equal(t, tt.wantErr, err != nil) + }) + } +} diff --git a/pkg/datastore/applicationstore.go b/pkg/datastore/applicationstore.go index 6f405e49ca..ad596e7d52 100644 --- a/pkg/datastore/applicationstore.go +++ b/pkg/datastore/applicationstore.go @@ -198,6 +198,7 @@ type ApplicationStore interface { UpdateBasicInfo(ctx context.Context, id, name, description string, labels map[string]string) error UpdateConfiguration(ctx context.Context, id, pipedID, platformProvider, configFilename string) error UpdatePlatformProvider(ctx context.Context, id string, provider string) error + UpdateGitPath(ctx context.Context, id string, gitPath *model.ApplicationGitPath) error } type applicationStore struct { @@ -377,3 +378,10 @@ func (s *applicationStore) UpdatePlatformProvider(ctx context.Context, id string return nil }) } + +func (s *applicationStore) UpdateGitPath(ctx context.Context, id string, gitPath *model.ApplicationGitPath) error { + return s.update(ctx, id, func(app *model.Application) error { + app.GitPath = gitPath + return nil + }) +} diff --git a/pkg/datastore/datastoretest/datastore.mock.go b/pkg/datastore/datastoretest/datastore.mock.go index 89e63b834a..e21a3e4045 100644 --- a/pkg/datastore/datastoretest/datastore.mock.go +++ b/pkg/datastore/datastoretest/datastore.mock.go @@ -552,6 +552,20 @@ func (mr *MockApplicationStoreMockRecorder) UpdateDeployingStatus(arg0, arg1, ar return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDeployingStatus", reflect.TypeOf((*MockApplicationStore)(nil).UpdateDeployingStatus), arg0, arg1, arg2) } +// UpdateGitPath mocks base method. +func (m *MockApplicationStore) UpdateGitPath(arg0 context.Context, arg1 string, arg2 *model.ApplicationGitPath) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateGitPath", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateGitPath indicates an expected call of UpdateGitPath. +func (mr *MockApplicationStoreMockRecorder) UpdateGitPath(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateGitPath", reflect.TypeOf((*MockApplicationStore)(nil).UpdateGitPath), arg0, arg1, arg2) +} + // UpdateMostRecentDeployment mocks base method. func (m *MockApplicationStore) UpdateMostRecentDeployment(arg0 context.Context, arg1 string, arg2 model.DeploymentStatus, arg3 *model.ApplicationDeploymentReference) error { m.ctrl.T.Helper()