From 537df54cf5aa05522e88117c4eafd919887992d0 Mon Sep 17 00:00:00 2001 From: closetool Date: Fri, 25 Aug 2023 14:19:26 +0800 Subject: [PATCH 01/11] feat: support release admit Signed-off-by: closetool --- core/cmd/cmd.go | 4 +- core/common/common.go | 6 + core/common/group.go | 19 + core/common/user.go | 1 + core/controller/application/controller.go | 4 +- core/controller/cloudevent/controller.go | 14 +- core/controller/cloudevent/controller_test.go | 6 +- core/controller/cluster/controller.go | 13 +- core/controller/cluster/controller_basic.go | 4 +- .../controller/cluster/controller_basic_v2.go | 171 ++++- .../cluster/controller_build_deploy.go | 8 +- .../controller/cluster/controller_internal.go | 8 +- .../cluster/controller_internal_v2.go | 8 +- .../cluster/controller_operation.go | 29 +- core/controller/cluster/controller_status.go | 10 +- core/controller/cluster/controller_test.go | 20 +- core/controller/cluster/models_basic_v2.go | 10 + core/controller/pipelinerun/controller.go | 420 ++++++++--- .../controller/pipelinerun/controller_test.go | 39 +- core/controller/pipelinerun/models.go | 66 +- core/errors/horizonerrors.go | 3 + core/http/api/v1/pipelinerun/apis.go | 4 +- core/http/api/v2/cluster/apis_basic.go | 28 + core/http/api/v2/cluster/routers.go | 5 + core/http/api/v2/pipelinerun/apis.go | 184 +++-- core/http/api/v2/pipelinerun/routers.go | 35 + db/20230817.sql | 669 ++++++++++++++++++ db/migrations/20230817_add_check.sql | 53 ++ .../tekton/collector/collector_mock.go | 2 +- mock/pkg/pipelinerun/manager/mock_manager.go | 124 ++-- pkg/cluster/manager/manager_test.go | 2 +- pkg/cluster/metrics/tekton/resolver.go | 2 +- pkg/cluster/metrics/tekton/resolver_test.go | 2 +- pkg/cluster/tekton/collector/collector.go | 2 +- .../tekton/collector/collector_dummy.go | 5 +- .../tekton/collector/collector_dummy_test.go | 5 +- pkg/cluster/tekton/collector/collector_s3.go | 2 +- .../tekton/collector/collector_s3_test.go | 5 +- pkg/common/db_scripts.go | 4 +- pkg/group/manager/manager.go | 14 +- pkg/jobs/autofree/autofree.go | 5 +- pkg/jobs/autofree/autofree_test.go | 15 +- pkg/member/service/service.go | 10 +- pkg/member/service/service_test.go | 17 +- pkg/param/managerparam/managerparam.go | 8 +- pkg/param/param.go | 2 + pkg/pr/dao/check.go | 122 ++++ pkg/pr/dao/message.go | 54 ++ .../dao/dao.go => pr/dao/pipelinerun.go} | 64 +- pkg/pr/manager/check.go | 62 ++ pkg/pr/manager/message.go | 37 + .../manager.go => pr/manager/pipelinerun.go} | 56 +- .../manager/pipelinerun_test.go} | 4 +- pkg/pr/manager/pr.go | 19 + pkg/pr/models/check.go | 52 ++ pkg/pr/models/message.go | 17 + pkg/{pipelinerun => pr}/models/pipelinerun.go | 53 +- pkg/{pipelinerun => pr}/pipeline/dao/dao.go | 2 +- .../pipeline/manager/manager.go | 4 +- .../pipeline/manager/manager_test.go | 2 +- .../pipeline/models/pipeline.go | 0 .../pipeline/models/stats.go | 0 .../pipeline/models/step.go | 0 .../pipeline/models/task.go | 0 pkg/pr/service/service.go | 135 ++++ pkg/server/global/model.go | 8 +- pkg/user/dao/dao.go | 10 +- pkg/util/ormcallbacks/callbacks.go | 11 +- 68 files changed, 2345 insertions(+), 434 deletions(-) create mode 100644 core/common/common.go create mode 100644 core/common/group.go create mode 100644 db/20230817.sql create mode 100644 db/migrations/20230817_add_check.sql create mode 100644 pkg/pr/dao/check.go create mode 100644 pkg/pr/dao/message.go rename pkg/{pipelinerun/dao/dao.go => pr/dao/pipelinerun.go} (75%) create mode 100644 pkg/pr/manager/check.go create mode 100644 pkg/pr/manager/message.go rename pkg/{pipelinerun/manager/manager.go => pr/manager/pipelinerun.go} (60%) rename pkg/{pipelinerun/manager/manager_test.go => pr/manager/pipelinerun_test.go} (98%) create mode 100644 pkg/pr/manager/pr.go create mode 100644 pkg/pr/models/check.go create mode 100644 pkg/pr/models/message.go rename pkg/{pipelinerun => pr}/models/pipelinerun.go (59%) rename pkg/{pipelinerun => pr}/pipeline/dao/dao.go (99%) rename pkg/{pipelinerun => pr}/pipeline/manager/manager.go (93%) rename pkg/{pipelinerun => pr}/pipeline/manager/manager_test.go (98%) rename pkg/{pipelinerun => pr}/pipeline/models/pipeline.go (100%) rename pkg/{pipelinerun => pr}/pipeline/models/stats.go (100%) rename pkg/{pipelinerun => pr}/pipeline/models/step.go (100%) rename pkg/{pipelinerun => pr}/pipeline/models/task.go (100%) create mode 100644 pkg/pr/service/service.go diff --git a/core/cmd/cmd.go b/core/cmd/cmd.go index 9e37ab66a..824e20472 100644 --- a/core/cmd/cmd.go +++ b/core/cmd/cmd.go @@ -118,6 +118,7 @@ import ( "github.com/horizoncd/horizon/pkg/jobs/grafanasync" "github.com/horizoncd/horizon/pkg/jobs/k8sevent" jobwebhook "github.com/horizoncd/horizon/pkg/jobs/webhook" + prservice "github.com/horizoncd/horizon/pkg/pr/service" "github.com/horizoncd/horizon/pkg/regioninformers" "github.com/horizoncd/horizon/pkg/token/generator" tokenservice "github.com/horizoncd/horizon/pkg/token/service" @@ -465,6 +466,7 @@ func Init(ctx context.Context, flags *Flags, coreConfig *config.Config) { OutputGetter: outputGetter, TektonFty: tektonFty, ClusterGitRepo: clusterGitRepo, + PRService: prservice.NewService(manager), GitGetter: gitGetter, GrafanaService: grafanaService, BuildSchema: buildSchema, @@ -494,7 +496,7 @@ func Init(ctx context.Context, flags *Flags, coreConfig *config.Config) { applicationCtl = applicationctl.NewController(parameter) envTemplateCtl = envtemplatectl.NewController(parameter) clusterCtl = clusterctl.NewController(coreConfig, parameter) - prCtl = prctl.NewController(parameter) + prCtl = prctl.NewController(coreConfig, parameter) templateCtl = templatectl.NewController(parameter, templateRepo) roleCtl = roltctl.NewController(parameter) terminalCtl = terminalctl.NewController(parameter) diff --git a/core/common/common.go b/core/common/common.go new file mode 100644 index 000000000..86786bb22 --- /dev/null +++ b/core/common/common.go @@ -0,0 +1,6 @@ +package common + +type Resource struct { + ID uint `json:"resource_id" yaml:"resourceID"` + Type string `json:"resource_type" yaml:"resourceType"` +} diff --git a/core/common/group.go b/core/common/group.go new file mode 100644 index 000000000..7c9b6e367 --- /dev/null +++ b/core/common/group.go @@ -0,0 +1,19 @@ +package common + +import ( + "strconv" + "strings" +) + +func UnmarshalTraversalIDS(traversalIDs string) ([]uint, error) { + splitIds := strings.Split(traversalIDs, ",") + var ids = make([]uint, len(splitIds)) + for i, id := range splitIds { + ii, err := strconv.Atoi(id) + if err != nil { + return nil, err + } + ids[i] = uint(ii) + } + return ids, nil +} diff --git a/core/common/user.go b/core/common/user.go index cb6a9f63e..0c8cbb890 100644 --- a/core/common/user.go +++ b/core/common/user.go @@ -28,6 +28,7 @@ import ( const ( UserQueryName = "filter" UserQueryType = "userType" + UserQueryID = "id" ) const ( diff --git a/core/controller/application/controller.go b/core/controller/application/controller.go index f36b97504..c6f85d0f1 100644 --- a/core/controller/application/controller.go +++ b/core/controller/application/controller.go @@ -39,8 +39,8 @@ import ( "github.com/horizoncd/horizon/pkg/member" membermodels "github.com/horizoncd/horizon/pkg/member/models" "github.com/horizoncd/horizon/pkg/param" - pipelinemanager "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/manager" - pipelinemodels "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/models" + pipelinemanager "github.com/horizoncd/horizon/pkg/pr/pipeline/manager" + pipelinemodels "github.com/horizoncd/horizon/pkg/pr/pipeline/models" regionmodels "github.com/horizoncd/horizon/pkg/region/models" tagmanager "github.com/horizoncd/horizon/pkg/tag/manager" tagmodels "github.com/horizoncd/horizon/pkg/tag/models" diff --git a/core/controller/cloudevent/controller.go b/core/controller/cloudevent/controller.go index 9f8fe57df..5dea4810c 100644 --- a/core/controller/cloudevent/controller.go +++ b/core/controller/cloudevent/controller.go @@ -27,9 +27,9 @@ import ( "github.com/horizoncd/horizon/pkg/cluster/tekton/factory" perror "github.com/horizoncd/horizon/pkg/errors" "github.com/horizoncd/horizon/pkg/param" - prmanager "github.com/horizoncd/horizon/pkg/pipelinerun/manager" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" - pipelinemanager "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/manager" + prmanager "github.com/horizoncd/horizon/pkg/pr/manager" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" + pipelinemanager "github.com/horizoncd/horizon/pkg/pr/pipeline/manager" "github.com/horizoncd/horizon/pkg/server/global" trmanager "github.com/horizoncd/horizon/pkg/templaterelease/manager" usermanager "github.com/horizoncd/horizon/pkg/user/manager" @@ -45,7 +45,7 @@ type Controller interface { type controller struct { tektonFty factory.Factory - pipelinerunMgr prmanager.Manager + prMgr *prmanager.PRManager pipelineMgr pipelinemanager.Manager clusterMgr clustermanager.Manager clusterGitRepo gitrepo.ClusterGitRepo @@ -57,7 +57,7 @@ type controller struct { func NewController(tektonFty factory.Factory, parameter *param.Param) Controller { return &controller{ tektonFty: tektonFty, - pipelinerunMgr: parameter.PipelinerunMgr, + prMgr: parameter.PRMgr, pipelineMgr: parameter.PipelineMgr, clusterMgr: parameter.ClusterMgr, clusterGitRepo: parameter.ClusterGitRepo, @@ -100,7 +100,7 @@ func (c *controller) CloudEvent(ctx context.Context, wpr *WrappedPipelineRun) (e pipelinerunID, result.Result, result.StartTime, result.CompletionTime) // 2. update pipelinerun in db - if err := c.pipelinerunMgr.UpdateResultByID(ctx, pipelinerunID, &prmodels.Result{ + if err := c.prMgr.PipelineRun.UpdateResultByID(ctx, pipelinerunID, &prmodels.Result{ S3Bucket: result.Bucket, LogObject: result.LogObject, PrObject: result.PrObject, @@ -180,7 +180,7 @@ func (c *controller) handleJibBuild(ctx context.Context, result *tekton.Pipeline func (c *controller) getHorizonMetaData(ctx context.Context, wpr *WrappedPipelineRun) ( *global.HorizonMetaData, error) { eventID := wpr.PipelineRun.Labels[common.TektonTriggersEventIDKey] - pipelinerun, err := c.pipelinerunMgr.GetByCIEventID(ctx, eventID) + pipelinerun, err := c.prMgr.PipelineRun.GetByCIEventID(ctx, eventID) if err != nil { return nil, err } diff --git a/core/controller/cloudevent/controller_test.go b/core/controller/cloudevent/controller_test.go index 9146cb014..07bbcf98f 100644 --- a/core/controller/cloudevent/controller_test.go +++ b/core/controller/cloudevent/controller_test.go @@ -40,8 +40,8 @@ import ( membermodels "github.com/horizoncd/horizon/pkg/member/models" "github.com/horizoncd/horizon/pkg/param" "github.com/horizoncd/horizon/pkg/param/managerparam" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" - pipelinemodels "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" + pipelinemodels "github.com/horizoncd/horizon/pkg/pr/pipeline/models" trmodels "github.com/horizoncd/horizon/pkg/templaterelease/models" usermodels "github.com/horizoncd/horizon/pkg/user/models" @@ -267,7 +267,7 @@ func Test(t *testing.T) { ApplicationID: application.ID, Name: "cluster", }, nil, nil) - pipelinerunMgr := manager.PipelinerunMgr + pipelinerunMgr := manager.PRMgr.PipelineRun _, err := pipelinerunMgr.Create(ctx, &prmodels.Pipelinerun{ ClusterID: cluster.ID, Action: "builddeploy", diff --git a/core/controller/cluster/controller.go b/core/controller/cluster/controller.go index 1eaa58b43..046bf0238 100644 --- a/core/controller/cluster/controller.go +++ b/core/controller/cluster/controller.go @@ -45,8 +45,10 @@ import ( groupsvc "github.com/horizoncd/horizon/pkg/group/service" "github.com/horizoncd/horizon/pkg/member" "github.com/horizoncd/horizon/pkg/param" - prmanager "github.com/horizoncd/horizon/pkg/pipelinerun/manager" - pipelinemanager "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/manager" + prmanager "github.com/horizoncd/horizon/pkg/pr/manager" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" + pipelinemanager "github.com/horizoncd/horizon/pkg/pr/pipeline/manager" + prservice "github.com/horizoncd/horizon/pkg/pr/service" regionmanager "github.com/horizoncd/horizon/pkg/region/manager" tagmanager "github.com/horizoncd/horizon/pkg/tag/manager" trmanager "github.com/horizoncd/horizon/pkg/templaterelease/manager" @@ -122,6 +124,7 @@ type Controller interface { // Deprecated: for internal usage, v1 to v2 Upgrade(ctx context.Context, clusterID uint) error ToggleLikeStatus(ctx context.Context, clusterID uint, like *WhetherLike) (err error) + CreatePipelineRun(ctx context.Context, clusterID uint, r *CreatePipelineRunRequest) (*prmodels.PipelineBasic, error) } type controller struct { @@ -142,7 +145,8 @@ type controller struct { envRegionMgr environmentregionmapper.Manager regionMgr regionmanager.Manager groupSvc groupsvc.Service - pipelinerunMgr prmanager.Manager + prMgr *prmanager.PRManager + prSvc *prservice.Service pipelineMgr pipelinemanager.Manager tektonFty factory.Factory registryFty registryfty.RegistryGetter @@ -183,7 +187,8 @@ func NewController(config *config.Config, param *param.Param) Controller { envRegionMgr: param.EnvRegionMgr, regionMgr: param.RegionMgr, groupSvc: param.GroupSvc, - pipelinerunMgr: param.PipelinerunMgr, + prMgr: param.PRMgr, + prSvc: param.PRService, pipelineMgr: param.PipelineMgr, tektonFty: param.TektonFty, registryFty: registryfty.Fty, diff --git a/core/controller/cluster/controller_basic.go b/core/controller/cluster/controller_basic.go index 6e6c772d3..b71d86798 100644 --- a/core/controller/cluster/controller_basic.go +++ b/core/controller/cluster/controller_basic.go @@ -314,7 +314,7 @@ func (c *controller) GetCluster(ctx context.Context, clusterID uint) (_ *GetClus clusterFiles.PipelineJSONBlob, clusterFiles.ApplicationJSONBlob, tags...) // 9. get latest deployed commit - latestPR, err := c.pipelinerunMgr.GetLatestSuccessByClusterID(ctx, clusterID) + latestPR, err := c.prMgr.PipelineRun.GetLatestSuccessByClusterID(ctx, clusterID) if err != nil { return nil, err } @@ -891,7 +891,7 @@ func (c *controller) DeleteCluster(ctx context.Context, clusterID uint, hard boo log.Errorf(newctx, "failed to delete members of cluster: %v, err: %v", cluster.Name, err) } // delete pipelinerun - if err := c.pipelinerunMgr.DeleteByClusterID(ctx, clusterID); err != nil { + if err := c.prMgr.PipelineRun.DeleteByClusterID(ctx, clusterID); err != nil { log.Errorf(newctx, "failed to delete pipelineruns of cluster: %v, err: %v", cluster.Name, err) } // delete tag diff --git a/core/controller/cluster/controller_basic_v2.go b/core/controller/cluster/controller_basic_v2.go index 0b6028bc9..eb05fa9f1 100644 --- a/core/controller/cluster/controller_basic_v2.go +++ b/core/controller/cluster/controller_basic_v2.go @@ -27,6 +27,8 @@ import ( "github.com/horizoncd/horizon/pkg/cluster/gitrepo" collectionmodels "github.com/horizoncd/horizon/pkg/collection/models" eventmodels "github.com/horizoncd/horizon/pkg/event/models" + "github.com/horizoncd/horizon/pkg/git" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" tagmodels "github.com/horizoncd/horizon/pkg/tag/models" "github.com/horizoncd/horizon/pkg/templaterelease/models" templateschema "github.com/horizoncd/horizon/pkg/templaterelease/schema" @@ -358,7 +360,7 @@ func (c *controller) GetClusterV2(ctx context.Context, clusterID uint) (*GetClus } // 8. get latest deployed commit - latestPR, err := c.pipelinerunMgr.GetLatestSuccessByClusterID(ctx, clusterID) + latestPR, err := c.prMgr.PipelineRun.GetLatestSuccessByClusterID(ctx, clusterID) if err != nil { return nil, err } @@ -659,3 +661,170 @@ func (c *controller) ToggleLikeStatus(ctx context.Context, clusterID uint, like } return nil } + +func (c *controller) CreatePipelineRun(ctx context.Context, clusterID uint, + r *CreatePipelineRunRequest) (*prmodels.PipelineBasic, error) { + const op = "pipelinerun controller: create pipelinerun" + defer wlog.Start(ctx, op).StopPrint() + + pipelineRun, err := c.createPipelineRun(ctx, clusterID, r) + if err != nil { + return nil, err + } + + // 找一下是否需要check,如果不需要则直接设为ready + checks, err := c.prSvc.GetCheckByResource(ctx, clusterID, common.ResourceCluster) + if err != nil { + return nil, err + } + if len(checks) == 0 { + pipelineRun.Status = string(prmodels.StatusReady) + } + + if pipelineRun, err = c.prMgr.PipelineRun.Create(ctx, pipelineRun); err != nil { + return nil, err + } + + firstCanRollbackPipelinerun, err := c.prMgr.PipelineRun.GetFirstCanRollbackPipelinerun(ctx, pipelineRun.ClusterID) + if err != nil { + return nil, err + } + return c.prSvc.OfPipelineBasic(ctx, pipelineRun, firstCanRollbackPipelinerun) +} + +func (c *controller) createPipelineRun(ctx context.Context, clusterID uint, + r *CreatePipelineRunRequest) (*prmodels.Pipelinerun, error) { + defer wlog.Start(ctx, "cluster controller: create pipeline run").StopPrint() + var action string + var err error + + cluster, err := c.clusterMgr.GetByID(ctx, clusterID) + if err != nil { + return nil, err + } + if r.Action == prmodels.ActionBuildDeploy && cluster.GitURL == "" { + return nil, herrors.ErrBuildDeployNotSupported + } + + var gitURL, gitRef, gitRefType, imageURL, codeCommitID = cluster.GitURL, + cluster.GitRef, cluster.GitRefType, cluster.Image, cluster.GitRef + + application, err := c.applicationMgr.GetByID(ctx, cluster.ApplicationID) + if err != nil { + return nil, err + } + + regionEntity, err := c.regionMgr.GetRegionEntity(ctx, cluster.RegionName) + if err != nil { + return nil, err + } + + configCommit, err := c.clusterGitRepo.GetConfigCommit(ctx, application.Name, cluster.Name) + if err != nil { + return nil, err + } + + var lastConfigCommitSHA, configCommitSHA = configCommit.Master, configCommit.Gitops + + switch r.Action { + case prmodels.ActionBuildDeploy: + action = prmodels.ActionBuildDeploy + + if r.Git != nil { + if r.Git.Commit != "" { + gitRefType = codemodels.GitRefTypeCommit + gitRef = r.Git.Commit + } else if r.Git.Tag != "" { + gitRefType = codemodels.GitRefTypeTag + gitRef = r.Git.Tag + } else if r.Git.Branch != "" { + gitRefType = codemodels.GitRefTypeBranch + gitRef = r.Git.Branch + } + } + + commit, err := c.commitGetter.GetCommit(ctx, cluster.GitURL, gitRefType, gitRef) + if err != nil { + commit = &git.Commit{ + Message: "commit not found", + ID: gitRef, + } + } + codeCommitID = commit.ID + + imageURL = assembleImageURL(regionEntity, application.Name, cluster.Name, gitRef, commit.ID) + + case prmodels.ActionDeploy: + action = prmodels.ActionDeploy + + clusterFiles, err := c.clusterGitRepo.GetCluster(ctx, application.Name, cluster.Name, cluster.Template) + if err != nil { + return nil, err + } + + if cluster.GitURL != "" { + err = c.checkAllowDeploy(ctx, application, cluster, clusterFiles, configCommit) + if err != nil { + return nil, err + } + + commit, err := c.commitGetter.GetCommit(ctx, cluster.GitURL, cluster.GitRefType, cluster.GitRef) + if err == nil { + codeCommitID = commit.ID + } + } else if cluster.Image != "" { + imageURL, err = getDeployImage(cluster.Image, r.ImageTag) + if err != nil { + return nil, err + } + } + + case prmodels.ActionRollback: + action = prmodels.ActionRollback + + // get pipelinerun to rollback, and do some validation + pipelinerun, err := c.prMgr.PipelineRun.GetByID(ctx, r.PipelinerunID) + if err != nil { + return nil, err + } + + if pipelinerun.Action == prmodels.ActionRestart || pipelinerun.Status != string(prmodels.StatusOK) || + pipelinerun.ConfigCommit == "" { + return nil, perror.Wrapf(herrors.ErrParamInvalid, + "the pipelinerun with id: %v can not be rolled back", r.PipelinerunID) + } + + if pipelinerun.ClusterID != cluster.ID { + return nil, perror.Wrapf(herrors.ErrParamInvalid, + "the pipelinerun with id: %v is not belongs to cluster: %v", r.PipelinerunID, clusterID) + } + + // Deprecated: for internal usage + err = c.checkAndSyncGitOpsBranch(ctx, application.Name, cluster.Name, pipelinerun.ConfigCommit) + if err != nil { + return nil, err + } + + gitURL, gitRefType, gitRef, codeCommitID, imageURL = + cluster.GitURL, cluster.GitRefType, cluster.GitRef, pipelinerun.GitCommit, pipelinerun.ImageURL + configCommitSHA = configCommit.Master + + default: + return nil, perror.Wrapf(herrors.ErrParamInvalid, "unsupported action %v", r.Action) + } + + return &prmodels.Pipelinerun{ + ClusterID: clusterID, + Action: action, + Status: string(prmodels.StatusPending), + Title: r.Title, + Description: r.Description, + GitURL: gitURL, + GitRefType: gitRefType, + GitRef: gitRef, + GitCommit: codeCommitID, + ImageURL: imageURL, + LastConfigCommit: lastConfigCommitSHA, + ConfigCommit: configCommitSHA, + }, nil +} diff --git a/core/controller/cluster/controller_build_deploy.go b/core/controller/cluster/controller_build_deploy.go index 334675963..7ee26a083 100644 --- a/core/controller/cluster/controller_build_deploy.go +++ b/core/controller/cluster/controller_build_deploy.go @@ -28,7 +28,7 @@ import ( codemodels "github.com/horizoncd/horizon/pkg/cluster/code" "github.com/horizoncd/horizon/pkg/cluster/tekton" "github.com/horizoncd/horizon/pkg/git" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" regionmodels "github.com/horizoncd/horizon/pkg/region/models" tokensvc "github.com/horizoncd/horizon/pkg/token/service" "github.com/horizoncd/horizon/pkg/util/log" @@ -100,7 +100,7 @@ func (c *controller) BuildDeploy(ctx context.Context, clusterID uint, pr := &prmodels.Pipelinerun{ ClusterID: clusterID, Action: prmodels.ActionBuildDeploy, - Status: string(prmodels.StatusCreated), + Status: string(prmodels.StatusRunning), Title: r.Title, Description: r.Description, GitURL: cluster.GitURL, @@ -111,7 +111,7 @@ func (c *controller) BuildDeploy(ctx context.Context, clusterID uint, LastConfigCommit: configCommit.Master, ConfigCommit: configCommit.Gitops, } - prCreated, err := c.pipelinerunMgr.Create(ctx, pr) + prCreated, err := c.prMgr.PipelineRun.Create(ctx, pr) if err != nil { return nil, err } @@ -174,7 +174,7 @@ func (c *controller) BuildDeploy(ctx context.Context, clusterID uint, // update event id returned from tekton-trigger EventListener log.Infof(ctx, "received event id: %s from tekton-trigger EventListener, pipelinerunID: %d", ciEventID, pr.ID) - err = c.pipelinerunMgr.UpdateCIEventIDByID(ctx, pr.ID, ciEventID) + err = c.prMgr.PipelineRun.UpdateCIEventIDByID(ctx, pr.ID, ciEventID) if err != nil { return nil, err } diff --git a/core/controller/cluster/controller_internal.go b/core/controller/cluster/controller_internal.go index 631ea93af..49bd1e956 100644 --- a/core/controller/cluster/controller_internal.go +++ b/core/controller/cluster/controller_internal.go @@ -25,7 +25,7 @@ import ( "github.com/horizoncd/horizon/pkg/cluster/gitrepo" perror "github.com/horizoncd/horizon/pkg/errors" eventmodels "github.com/horizoncd/horizon/pkg/event/models" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" "github.com/horizoncd/horizon/pkg/util/log" "github.com/horizoncd/horizon/pkg/util/wlog" ) @@ -36,7 +36,7 @@ func (c *controller) InternalDeploy(ctx context.Context, clusterID uint, defer wlog.Start(ctx, op).StopPrint() // 1. get pr, and do some validate - pr, err := c.pipelinerunMgr.GetByID(ctx, r.PipelinerunID) + pr, err := c.prMgr.PipelineRun.GetByID(ctx, r.PipelinerunID) if err != nil { return nil, err } @@ -80,11 +80,11 @@ func (c *controller) InternalDeploy(ctx context.Context, clusterID uint, } // 4. update config commit and status - if err := c.pipelinerunMgr.UpdateConfigCommitByID(ctx, pr.ID, commit); err != nil { + if err := c.prMgr.PipelineRun.UpdateConfigCommitByID(ctx, pr.ID, commit); err != nil { return nil, err } updatePRStatus := func(pState prmodels.PipelineStatus, revision string) error { - if err = c.pipelinerunMgr.UpdateStatusByID(ctx, pr.ID, pState); err != nil { + if err = c.prMgr.PipelineRun.UpdateStatusByID(ctx, pr.ID, pState); err != nil { log.Errorf(ctx, "UpdateStatusByID error, pr = %d, status = %s, err = %v", pr.ID, pState, err) return err diff --git a/core/controller/cluster/controller_internal_v2.go b/core/controller/cluster/controller_internal_v2.go index 5abe8ea70..5faa31821 100644 --- a/core/controller/cluster/controller_internal_v2.go +++ b/core/controller/cluster/controller_internal_v2.go @@ -27,7 +27,7 @@ import ( "github.com/horizoncd/horizon/pkg/cluster/models" perror "github.com/horizoncd/horizon/pkg/errors" eventmodels "github.com/horizoncd/horizon/pkg/event/models" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" tokenservice "github.com/horizoncd/horizon/pkg/token/service" usermodel "github.com/horizoncd/horizon/pkg/user/models" "github.com/horizoncd/horizon/pkg/util/log" @@ -60,7 +60,7 @@ func (c *controller) InternalDeployV2(ctx context.Context, clusterID uint, } // 1. get pr, and do some validate - pr, err := c.pipelinerunMgr.GetByID(ctx, r.PipelinerunID) + pr, err := c.prMgr.PipelineRun.GetByID(ctx, r.PipelinerunID) if err != nil { return nil, err } @@ -84,7 +84,7 @@ func (c *controller) InternalDeployV2(ctx context.Context, clusterID uint, } updatePRStatus := func(pState prmodels.PipelineStatus, revision string) error { - if err = c.pipelinerunMgr.UpdateStatusByID(ctx, pr.ID, pState); err != nil { + if err = c.prMgr.PipelineRun.UpdateStatusByID(ctx, pr.ID, pState); err != nil { log.Errorf(ctx, "UpdateStatusByID error, pr = %d, status = %s, err = %v", pr.ID, pState, err) return err @@ -104,7 +104,7 @@ func (c *controller) InternalDeployV2(ctx context.Context, clusterID uint, return nil, perror.WithMessage(err, op) } // 4. update config commit and status - if err := c.pipelinerunMgr.UpdateConfigCommitByID(ctx, pr.ID, commit); err != nil { + if err := c.prMgr.PipelineRun.UpdateConfigCommitByID(ctx, pr.ID, commit); err != nil { return nil, err } if err := updatePRStatus(prmodels.StatusCommitted, commit); err != nil { diff --git a/core/controller/cluster/controller_operation.go b/core/controller/cluster/controller_operation.go index df4698a02..4e747fd3b 100644 --- a/core/controller/cluster/controller_operation.go +++ b/core/controller/cluster/controller_operation.go @@ -22,6 +22,8 @@ import ( "time" "github.com/google/go-containerregistry/pkg/name" + "k8s.io/apimachinery/pkg/runtime/schema" + "github.com/horizoncd/horizon/core/common" herrors "github.com/horizoncd/horizon/core/errors" amodels "github.com/horizoncd/horizon/pkg/application/models" @@ -32,14 +34,13 @@ import ( "github.com/horizoncd/horizon/pkg/cluster/tekton" perror "github.com/horizoncd/horizon/pkg/errors" eventmodels "github.com/horizoncd/horizon/pkg/event/models" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" regionmodels "github.com/horizoncd/horizon/pkg/region/models" tmodels "github.com/horizoncd/horizon/pkg/tag/models" trmodels "github.com/horizoncd/horizon/pkg/templaterelease/models" tokensvc "github.com/horizoncd/horizon/pkg/token/service" "github.com/horizoncd/horizon/pkg/util/log" "github.com/horizoncd/horizon/pkg/util/wlog" - "k8s.io/apimachinery/pkg/runtime/schema" ) func (c *controller) Restart(ctx context.Context, clusterID uint) (_ *PipelinerunIDResponse, err error) { @@ -63,10 +64,10 @@ func (c *controller) Restart(ctx context.Context, clusterID uint) (_ *Pipelineru } // 2. create pipeline record - prCreated, err := c.pipelinerunMgr.Create(ctx, &prmodels.Pipelinerun{ + prCreated, err := c.prMgr.PipelineRun.Create(ctx, &prmodels.Pipelinerun{ ClusterID: clusterID, Action: prmodels.ActionRestart, - Status: string(prmodels.StatusCreated), + Status: string(prmodels.StatusRunning), Title: prmodels.ActionRestart, LastConfigCommit: lastConfigCommit.Master, ConfigCommit: lastConfigCommit.Master, @@ -77,7 +78,7 @@ func (c *controller) Restart(ctx context.Context, clusterID uint) (_ *Pipelineru if err != nil { return nil, err } - if err := c.pipelinerunMgr.UpdateConfigCommitByID(ctx, prCreated.ID, commit); err != nil { + if err := c.prMgr.PipelineRun.UpdateConfigCommitByID(ctx, prCreated.ID, commit); err != nil { log.Errorf(ctx, "UpdateConfigCommitByID error, pr = %d, commit = %s, err = %v", prCreated.ID, commit, err) } @@ -164,10 +165,10 @@ func (c *controller) Deploy(ctx context.Context, clusterID uint, } // 2. create pipeline record - prCreated, err := c.pipelinerunMgr.Create(ctx, &prmodels.Pipelinerun{ + prCreated, err := c.prMgr.PipelineRun.Create(ctx, &prmodels.Pipelinerun{ ClusterID: clusterID, Action: prmodels.ActionDeploy, - Status: string(prmodels.StatusCreated), + Status: string(prmodels.StatusRunning), Title: r.Title, Description: r.Description, GitURL: cluster.GitURL, @@ -234,7 +235,7 @@ func (c *controller) Deploy(ctx context.Context, clusterID uint, // update event id returned from tekton-trigger EventListener log.Infof(ctx, "received event id: %s from tekton-trigger EventListener, pipelinerunID: %d", ciEventID, prCreated.ID) - err = c.pipelinerunMgr.UpdateCIEventIDByID(ctx, prCreated.ID, ciEventID) + err = c.prMgr.PipelineRun.UpdateCIEventIDByID(ctx, prCreated.ID, ciEventID) if err != nil { return nil, err } @@ -290,7 +291,7 @@ func (c *controller) Rollback(ctx context.Context, defer wlog.Start(ctx, op).StopPrint() // 1. get pipelinerun to rollback, and do some validation - pipelinerun, err := c.pipelinerunMgr.GetByID(ctx, r.PipelinerunID) + pipelinerun, err := c.prMgr.PipelineRun.GetByID(ctx, r.PipelinerunID) if err != nil { return nil, err } @@ -323,10 +324,10 @@ func (c *controller) Rollback(ctx context.Context, } // 3. create record - prCreated, err := c.pipelinerunMgr.Create(ctx, &prmodels.Pipelinerun{ + prCreated, err := c.prMgr.PipelineRun.Create(ctx, &prmodels.Pipelinerun{ ClusterID: clusterID, Action: prmodels.ActionRollback, - Status: string(prmodels.StatusCreated), + Status: string(prmodels.StatusRunning), Title: prmodels.ActionRollback, GitURL: pipelinerun.GitURL, GitRefType: pipelinerun.GitRefType, @@ -363,7 +364,7 @@ func (c *controller) Rollback(ctx context.Context, if err != nil { return nil, err } - if err := c.pipelinerunMgr.UpdateConfigCommitByID(ctx, prCreated.ID, masterRevision); err != nil { + if err := c.prMgr.PipelineRun.UpdateConfigCommitByID(ctx, prCreated.ID, masterRevision); err != nil { log.Errorf(ctx, "UpdateConfigCommitByID error, pr = %d, commit = %s, err = %v", prCreated.ID, masterRevision, err) } @@ -724,10 +725,10 @@ func (c *controller) updatePipelineRunStatus(ctx context.Context, action string, prID uint, pState prmodels.PipelineStatus, revision string) error { var err error if pState != prmodels.StatusOK { - err = c.pipelinerunMgr.UpdateStatusByID(ctx, prID, pState) + err = c.prMgr.PipelineRun.UpdateStatusByID(ctx, prID, pState) } else { finishedAt := time.Now() - err = c.pipelinerunMgr.UpdateResultByID(ctx, prID, &prmodels.Result{ + err = c.prMgr.PipelineRun.UpdateResultByID(ctx, prID, &prmodels.Result{ Result: string(pState), FinishedAt: &finishedAt, }) diff --git a/core/controller/cluster/controller_status.go b/core/controller/cluster/controller_status.go index 64fd626a2..ec8c97cd0 100644 --- a/core/controller/cluster/controller_status.go +++ b/core/controller/cluster/controller_status.go @@ -27,7 +27,7 @@ import ( clustermodels "github.com/horizoncd/horizon/pkg/cluster/models" "github.com/horizoncd/horizon/pkg/cluster/tekton" perror "github.com/horizoncd/horizon/pkg/errors" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" "github.com/horizoncd/horizon/pkg/util/log" "github.com/horizoncd/horizon/pkg/util/wlog" @@ -257,7 +257,7 @@ func isClusterActuallyHealthy(ctx context.Context, clusterState *cd.ClusterState func (c *controller) getLatestPipelinerunByClusterID(ctx context.Context, clusterID uint) (*prmodels.Pipelinerun, error) { - _, pipelineruns, err := c.pipelinerunMgr.GetByClusterID(ctx, clusterID, false, q.Query{ + _, pipelineruns, err := c.prMgr.PipelineRun.GetByClusterID(ctx, clusterID, false, q.Query{ PageNumber: 1, PageSize: 1, }) @@ -569,7 +569,11 @@ func willExpireIn(ttl uint, tms ...time.Time) *uint { } func isNonRunningTask(latestPipelinerun *prmodels.Pipelinerun) bool { - if latestPipelinerun == nil || latestPipelinerun.Status == string(prmodels.StatusOK) { + if latestPipelinerun == nil || + latestPipelinerun.Status == string(prmodels.StatusOK) || + latestPipelinerun.Status == string(prmodels.StatusReady) || + latestPipelinerun.Status == string(prmodels.StatusCancelled) || + latestPipelinerun.Status == string(prmodels.StatusPending) { return true } if latestPipelinerun.Action == prmodels.ActionRestart || diff --git a/core/controller/cluster/controller_test.go b/core/controller/cluster/controller_test.go index 93dd5f67c..2a5ad7fc2 100644 --- a/core/controller/cluster/controller_test.go +++ b/core/controller/cluster/controller_test.go @@ -70,7 +70,7 @@ import ( membermodels "github.com/horizoncd/horizon/pkg/member/models" "github.com/horizoncd/horizon/pkg/param" "github.com/horizoncd/horizon/pkg/param/managerparam" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" regionmodels "github.com/horizoncd/horizon/pkg/region/models" registrydao "github.com/horizoncd/horizon/pkg/registry/dao" registrymodels "github.com/horizoncd/horizon/pkg/registry/models" @@ -645,7 +645,7 @@ func test(t *testing.T) { regionMgr: regionMgr, autoFreeSvc: param.AutoFreeSvc, groupSvc: groupservice.NewService(manager), - pipelinerunMgr: manager.PipelinerunMgr, + prMgr: manager.PRMgr, tektonFty: tektonFty, registryFty: registryFty, userManager: manager.UserMgr, @@ -977,7 +977,7 @@ func test(t *testing.T) { assert.NotNil(t, resp) b, _ = json.Marshal(restartResp) t.Logf("%s", string(b)) - pr, err := manager.PipelinerunMgr.GetByID(ctx, restartResp.PipelinerunID) + pr, err := manager.PRMgr.PipelineRun.GetByID(ctx, restartResp.PipelinerunID) assert.Nil(t, err) assert.Equal(t, string(prmodels.StatusOK), pr.Status) assert.NotNil(t, pr.FinishedAt) @@ -1022,9 +1022,9 @@ func test(t *testing.T) { b, _ = json.Marshal(deployResp) t.Logf("%s", string(b)) - pr, err = manager.PipelinerunMgr.GetByID(ctx, deployResp.PipelinerunID) + pr, err = manager.PRMgr.PipelineRun.GetByID(ctx, deployResp.PipelinerunID) assert.Nil(t, err) - assert.Equal(t, string(prmodels.StatusCreated), pr.Status) + assert.Equal(t, string(prmodels.StatusRunning), pr.Status) // test next k8sutil.EXPECT().ExecuteAction(ctx, gomock.Any()).Return(nil) @@ -1088,7 +1088,7 @@ func test(t *testing.T) { clusterGitRepo.EXPECT().GetManifest(ctx, application.Name, resp.Name, gomock.Any()). Return(nil, herrors.NewErrNotFound(herrors.GitlabResource, "")).Times(2) // update status to 'ok' - err = manager.PipelinerunMgr.UpdateResultByID(ctx, buildDeployResp.PipelinerunID, &prmodels.Result{ + err = manager.PRMgr.PipelineRun.UpdateResultByID(ctx, buildDeployResp.PipelinerunID, &prmodels.Result{ Result: string(prmodels.StatusOK), }) assert.Nil(t, err) @@ -1101,7 +1101,7 @@ func test(t *testing.T) { assert.NotNil(t, rollbackResp) b, _ = json.Marshal(rollbackResp) t.Logf("%s", string(b)) - pr, err = manager.PipelinerunMgr.GetByID(ctx, rollbackResp.PipelinerunID) + pr, err = manager.PRMgr.PipelineRun.GetByID(ctx, rollbackResp.PipelinerunID) assert.Nil(t, err) assert.Equal(t, string(prmodels.StatusOK), pr.Status) assert.NotNil(t, pr.FinishedAt) @@ -1411,9 +1411,9 @@ func testV2(t *testing.T) { envRegionMgr: envRegionMgr, regionMgr: regionMgr, groupSvc: groupservice.NewService(manager), - pipelinerunMgr: manager.PipelinerunMgr, + prMgr: manager.PRMgr, userManager: manager.UserMgr, - autoFreeSvc: service.New([]string{"dev2", "test2"}), + autoFreeSvc: param.AutoFreeSvc, userSvc: userservice.NewService(manager), schemaTagManager: manager.ClusterSchemaTagMgr, applicationGitRepo: applicationGitRepo, @@ -1636,7 +1636,7 @@ func testUpgrade(t *testing.T) { envRegionMgr: envRegionMgr, regionMgr: regionMgr, groupSvc: groupservice.NewService(manager), - pipelinerunMgr: manager.PipelinerunMgr, + prMgr: manager.PRMgr, userManager: manager.UserMgr, autoFreeSvc: parameter.AutoFreeSvc, userSvc: userservice.NewService(manager), diff --git a/core/controller/cluster/models_basic_v2.go b/core/controller/cluster/models_basic_v2.go index cc9c978ec..e3c5fbfdb 100644 --- a/core/controller/cluster/models_basic_v2.go +++ b/core/controller/cluster/models_basic_v2.go @@ -237,3 +237,13 @@ type GetClusterResponseV2 struct { type WhetherLike struct { IsFavorite bool `json:"isFavorite"` } + +type CreatePipelineRunRequest struct { + Title string `json:"title"` + Description string `json:"description"` + Action string `json:"action"` + // for build deploy + Git *BuildDeployRequestGit `json:"git,omitempty"` + ImageTag string `json:"imageTag,omitempty"` + PipelinerunID uint `json:"pipelinerunID,omitempty"` +} diff --git a/core/controller/pipelinerun/controller.go b/core/controller/pipelinerun/controller.go index f1a07beda..749b1027f 100644 --- a/core/controller/pipelinerun/controller.go +++ b/core/controller/pipelinerun/controller.go @@ -18,23 +18,36 @@ import ( "context" "fmt" "net/http" + "strconv" + "github.com/horizoncd/horizon/core/common" + "github.com/horizoncd/horizon/core/config" + herrors "github.com/horizoncd/horizon/core/errors" "github.com/horizoncd/horizon/lib/q" appmanager "github.com/horizoncd/horizon/pkg/application/manager" "github.com/horizoncd/horizon/pkg/cluster/code" codemodels "github.com/horizoncd/horizon/pkg/cluster/code" "github.com/horizoncd/horizon/pkg/cluster/gitrepo" clustermanager "github.com/horizoncd/horizon/pkg/cluster/manager" + "github.com/horizoncd/horizon/pkg/cluster/tekton" "github.com/horizoncd/horizon/pkg/cluster/tekton/collector" "github.com/horizoncd/horizon/pkg/cluster/tekton/factory" + "github.com/horizoncd/horizon/pkg/config/token" envmanager "github.com/horizoncd/horizon/pkg/environment/manager" perror "github.com/horizoncd/horizon/pkg/errors" + membermanager "github.com/horizoncd/horizon/pkg/member" "github.com/horizoncd/horizon/pkg/param" - prmanager "github.com/horizoncd/horizon/pkg/pipelinerun/manager" - "github.com/horizoncd/horizon/pkg/pipelinerun/models" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmanager "github.com/horizoncd/horizon/pkg/pr/manager" + "github.com/horizoncd/horizon/pkg/pr/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" + prservice "github.com/horizoncd/horizon/pkg/pr/service" + regionmanager "github.com/horizoncd/horizon/pkg/region/manager" + trmanager "github.com/horizoncd/horizon/pkg/templaterelease/manager" + tokensvc "github.com/horizoncd/horizon/pkg/token/service" usermanager "github.com/horizoncd/horizon/pkg/user/manager" + usermodels "github.com/horizoncd/horizon/pkg/user/models" "github.com/horizoncd/horizon/pkg/util/errors" + "github.com/horizoncd/horizon/pkg/util/log" "github.com/horizoncd/horizon/pkg/util/wlog" ) @@ -42,35 +55,62 @@ type Controller interface { GetPipelinerunLog(ctx context.Context, pipelinerunID uint) (*collector.Log, error) GetClusterLatestLog(ctx context.Context, clusterID uint) (*collector.Log, error) GetDiff(ctx context.Context, pipelinerunID uint) (*GetDiffResponse, error) - Get(ctx context.Context, pipelinerunID uint) (*PipelineBasic, error) - List(ctx context.Context, clusterID uint, canRollback bool, query q.Query) (int, []*PipelineBasic, error) + GetPipelinerun(ctx context.Context, pipelinerunID uint) (*prmodels.PipelineBasic, error) + ListPipelineruns(ctx context.Context, clusterID uint, canRollback bool, + query q.Query) (int, []*prmodels.PipelineBasic, error) StopPipelinerun(ctx context.Context, pipelinerunID uint) error StopPipelinerunForCluster(ctx context.Context, clusterID uint) error + + CreateCheck(ctx context.Context, check *models.Check) (*models.Check, error) + UpdateCheckRunByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error + + ListMessagesByPipelinerun(ctx context.Context, pipelinerunID uint, query *q.Query) (int, []*models.PRMessage, error) + // Execute runs a pipelineRun only if its state is ready. + Execute(ctx context.Context, pipelinerunID uint, force bool) error + // Cancel withdraws a pipelineRun only if its state is pending. + Cancel(ctx context.Context, pipelinerunID uint) error + + ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) + CreateCheckRun(ctx context.Context, pipelineRunID uint, request *CreateCheckRunRequest) (*models.CheckRun, error) + ListPRMessages(ctx context.Context, pipelineRunID uint, q *q.Query) (int, []*PrMessage, error) + CreatePRMessage(ctx context.Context, pipelineRunID uint, request *CreatePrMessageRequest) (*models.PRMessage, error) } type controller struct { - pipelinerunMgr prmanager.Manager - applicationMgr appmanager.Manager - clusterMgr clustermanager.Manager - envMgr envmanager.Manager - tektonFty factory.Factory - commitGetter code.GitGetter - clusterGitRepo gitrepo.ClusterGitRepo - userManager usermanager.Manager + prMgr *prmanager.PRManager + appMgr appmanager.Manager + clusterMgr clustermanager.Manager + envMgr envmanager.Manager + prSvc *prservice.Service + regionMgr regionmanager.Manager + tektonFty factory.Factory + tokenSvc tokensvc.Service + tokenConfig token.Config + memberMgr membermanager.Manager + templateReleaseMgr trmanager.Manager + commitGetter code.GitGetter + clusterGitRepo gitrepo.ClusterGitRepo + userMgr usermanager.Manager } var _ Controller = (*controller)(nil) -func NewController(param *param.Param) Controller { +func NewController(config *config.Config, param *param.Param) Controller { return &controller{ - pipelinerunMgr: param.PipelinerunMgr, - clusterMgr: param.ClusterMgr, - envMgr: param.EnvMgr, - tektonFty: param.TektonFty, - commitGetter: param.GitGetter, - applicationMgr: param.ApplicationMgr, - clusterGitRepo: param.ClusterGitRepo, - userManager: param.UserMgr, + prMgr: param.PRMgr, + prSvc: param.PRService, + clusterMgr: param.ClusterMgr, + envMgr: param.EnvMgr, + tektonFty: param.TektonFty, + tokenSvc: param.TokenSvc, + tokenConfig: config.TokenConfig, + commitGetter: param.GitGetter, + appMgr: param.ApplicationMgr, + memberMgr: param.MemberMgr, + regionMgr: param.RegionMgr, + clusterGitRepo: param.ClusterGitRepo, + userMgr: param.UserMgr, + templateReleaseMgr: param.TemplateReleaseMgr, } } @@ -78,7 +118,7 @@ func (c *controller) GetPipelinerunLog(ctx context.Context, pipelinerunID uint) const op = "pipelinerun controller: get pipelinerun log" defer wlog.Start(ctx, op).StopPrint() - pr, err := c.pipelinerunMgr.GetByID(ctx, pipelinerunID) + pr, err := c.prMgr.PipelineRun.GetByID(ctx, pipelinerunID) if err != nil { return nil, errors.E(op, err) } @@ -100,7 +140,7 @@ func (c *controller) GetClusterLatestLog(ctx context.Context, clusterID uint) (_ const op = "pipelinerun controller: get cluster latest log" defer wlog.Start(ctx, op).StopPrint() - pr, err := c.pipelinerunMgr.GetLatestByClusterIDAndActions(ctx, clusterID, + pr, err := c.prMgr.PipelineRun.GetLatestByClusterIDAndActions(ctx, clusterID, prmodels.ActionBuildDeploy, prmodels.ActionDeploy) if err != nil { return nil, errors.E(op, err) @@ -134,7 +174,7 @@ func (c *controller) GetDiff(ctx context.Context, pipelinerunID uint) (_ *GetDif defer wlog.Start(ctx, op).StopPrint() // 1. get pipeline - pipelinerun, err := c.pipelinerunMgr.GetByID(ctx, pipelinerunID) + pipelinerun, err := c.prMgr.PipelineRun.GetByID(ctx, pipelinerunID) if err != nil { return nil, err } @@ -144,7 +184,7 @@ func (c *controller) GetDiff(ctx context.Context, pipelinerunID uint) (_ *GetDif if err != nil { return nil, err } - application, err := c.applicationMgr.GetByID(ctx, cluster.ApplicationID) + application, err := c.appMgr.GetByID(ctx, cluster.ApplicationID) if err != nil { return nil, err } @@ -196,112 +236,55 @@ func (c *controller) GetDiff(ctx context.Context, pipelinerunID uint) (_ *GetDif }, nil } -func (c *controller) Get(ctx context.Context, pipelineID uint) (_ *PipelineBasic, err error) { +func (c *controller) GetPipelinerun(ctx context.Context, pipelineID uint) (_ *prmodels.PipelineBasic, err error) { const op = "pipelinerun controller: get pipelinerun basic" defer wlog.Start(ctx, op).StopPrint() - pipelinerun, err := c.pipelinerunMgr.GetByID(ctx, pipelineID) + pipelinerun, err := c.prMgr.PipelineRun.GetByID(ctx, pipelineID) if err != nil { return nil, err } - firstCanRollbackPipelinerun, err := c.pipelinerunMgr.GetFirstCanRollbackPipelinerun(ctx, pipelinerun.ClusterID) + firstCanRollbackPipelinerun, err := c.prMgr.PipelineRun.GetFirstCanRollbackPipelinerun(ctx, pipelinerun.ClusterID) if err != nil { return nil, err } - return c.ofPipelineBasic(ctx, pipelinerun, firstCanRollbackPipelinerun) + return c.prSvc.OfPipelineBasic(ctx, pipelinerun, firstCanRollbackPipelinerun) } -func (c *controller) List(ctx context.Context, - clusterID uint, canRollback bool, query q.Query) (_ int, _ []*PipelineBasic, err error) { +func (c *controller) ListPipelineruns(ctx context.Context, + clusterID uint, canRollback bool, query q.Query) (_ int, _ []*prmodels.PipelineBasic, err error) { const op = "pipelinerun controller: list pipelinerun" defer wlog.Start(ctx, op).StopPrint() - totalCount, pipelineruns, err := c.pipelinerunMgr.GetByClusterID(ctx, clusterID, canRollback, query) + totalCount, pipelineruns, err := c.prMgr.PipelineRun.GetByClusterID(ctx, clusterID, canRollback, query) if err != nil { return 0, nil, err } // remove the first pipelinerun than can be rollback - firstCanRollbackPipelinerun, err := c.pipelinerunMgr.GetFirstCanRollbackPipelinerun(ctx, clusterID) + firstCanRollbackPipelinerun, err := c.prMgr.PipelineRun.GetFirstCanRollbackPipelinerun(ctx, clusterID) if err != nil { return 0, nil, err } - pipelineBasics, err := c.ofPipelineBasics(ctx, pipelineruns, firstCanRollbackPipelinerun) + pipelineBasics, err := c.prSvc.OfPipelineBasics(ctx, pipelineruns, firstCanRollbackPipelinerun) if err != nil { return 0, nil, err } return totalCount, pipelineBasics, nil } -func (c *controller) ofPipelineBasic(ctx context.Context, - pr, firstCanRollbackPipelinerun *models.Pipelinerun) (*PipelineBasic, error) { - user, err := c.userManager.GetUserByID(ctx, pr.CreatedBy) - if err != nil { - return nil, err - } - - canRollback := func() bool { - // set the firstCanRollbackPipelinerun that cannot rollback - if firstCanRollbackPipelinerun != nil && pr.ID == firstCanRollbackPipelinerun.ID { - return false - } - return pr.Action != prmodels.ActionRestart && pr.Status == string(prmodels.StatusOK) - }() - - prBasic := &PipelineBasic{ - ID: pr.ID, - Title: pr.Title, - Description: pr.Description, - Action: pr.Action, - Status: pr.Status, - GitURL: pr.GitURL, - GitCommit: pr.GitCommit, - ImageURL: pr.ImageURL, - LastConfigCommit: pr.LastConfigCommit, - ConfigCommit: pr.ConfigCommit, - CreatedAt: pr.CreatedAt, - UpdatedAt: pr.UpdatedAt, - StartedAt: pr.StartedAt, - FinishedAt: pr.FinishedAt, - CanRollback: canRollback, - CreatedBy: UserInfo{ - UserID: pr.CreatedBy, - UserName: user.Name, - }, - } - switch pr.GitRefType { - case codemodels.GitRefTypeTag: - prBasic.GitTag = pr.GitRef - case codemodels.GitRefTypeBranch: - prBasic.GitBranch = pr.GitRef - } - return prBasic, nil -} - -func (c *controller) ofPipelineBasics(ctx context.Context, prs []*models.Pipelinerun, - firstCanRollbackPipelinerun *models.Pipelinerun) ([]*PipelineBasic, error) { - var pipelineBasics []*PipelineBasic - for _, pr := range prs { - pipelineBasic, err := c.ofPipelineBasic(ctx, pr, firstCanRollbackPipelinerun) - if err != nil { - return nil, err - } - pipelineBasics = append(pipelineBasics, pipelineBasic) - } - return pipelineBasics, nil -} - func (c *controller) StopPipelinerun(ctx context.Context, pipelinerunID uint) (err error) { const op = "pipelinerun controller: stop pipelinerun" defer wlog.Start(ctx, op).StopPrint() - pipelinerun, err := c.pipelinerunMgr.GetByID(ctx, pipelinerunID) + pipelinerun, err := c.prMgr.PipelineRun.GetByID(ctx, pipelinerunID) if err != nil { return errors.E(op, err) } - if pipelinerun.Status != string(prmodels.StatusCreated) { + if pipelinerun.Status != string(prmodels.StatusCreated) && + pipelinerun.Status != string(prmodels.StatusRunning) { return errors.E(op, http.StatusBadRequest, errors.ErrorCode("BadRequest"), "pipelinerun is already completed") } cluster, err := c.clusterMgr.GetByID(ctx, pipelinerun.ClusterID) @@ -325,10 +308,11 @@ func (c *controller) StopPipelinerunForCluster(ctx context.Context, clusterID ui return errors.E(op, err) } // get cluster latest builddeploy pipelinerun - pipelinerun, err := c.pipelinerunMgr.GetLatestByClusterIDAndActions(ctx, clusterID, prmodels.ActionBuildDeploy) + pipelinerun, err := c.prMgr.PipelineRun.GetLatestByClusterIDAndActions(ctx, clusterID, prmodels.ActionBuildDeploy) // if pipelinerun.Status is not created, ignore, and return success - if pipelinerun.Status != string(prmodels.StatusCreated) { + if pipelinerun.Status != string(prmodels.StatusCreated) && + pipelinerun.Status != string(prmodels.StatusRunning) { return nil } cluster, err := c.clusterMgr.GetByID(ctx, pipelinerun.ClusterID) @@ -343,3 +327,245 @@ func (c *controller) StopPipelinerunForCluster(ctx context.Context, clusterID ui return tektonClient.StopPipelineRun(ctx, pipelinerun.CIEventID) } + +func (c *controller) CreateCheck(ctx context.Context, check *models.Check) (*models.Check, error) { + const op = "pipelinerun controller: create check" + defer wlog.Start(ctx, op).StopPrint() + + return c.prMgr.Check.Create(ctx, check) +} + +func (c *controller) UpdateCheckRunByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error { + const op = "pipelinerun controller: update check run" + defer wlog.Start(ctx, op).StopPrint() + + return c.prMgr.Check.UpdateByID(ctx, checkRunID, newCheckRun) +} + +func (c *controller) ListMessagesByPipelinerun(ctx context.Context, + pipelinerunID uint, query *q.Query) (int, []*models.PRMessage, error) { + const op = "pipelinerun controller: list pr message" + defer wlog.Start(ctx, op).StopPrint() + + return c.prMgr.Message.List(ctx, pipelinerunID, query) +} + +func (c *controller) Execute(ctx context.Context, pipelinerunID uint, force bool) error { + const op = "pipelinerun controller: execute pipelinerun" + defer wlog.Start(ctx, op).StopPrint() + + pr, err := c.prMgr.PipelineRun.GetByID(ctx, pipelinerunID) + if err != nil { + return err + } + + if !force { + if pr.Status != string(prmodels.StatusReady) { + return perror.Wrapf(herrors.ErrParamInvalid, "pipelinerun is not ready to execute") + } + } + + return c.execute(ctx, pr) +} + +func (c *controller) execute(ctx context.Context, pr *models.Pipelinerun) error { + currentUser, err := common.UserFromContext(ctx) + if err != nil { + return err + } + + // 1. get cluster + cluster, err := c.clusterMgr.GetByID(ctx, pr.ClusterID) + if err != nil { + return err + } + + // 2. get application + application, err := c.appMgr.GetByID(ctx, cluster.ApplicationID) + if err != nil { + return err + } + + // 3. generate a JWT token for tekton callback + token, err := c.tokenSvc.CreateJWTToken(strconv.Itoa(int(currentUser.GetID())), + c.tokenConfig.CallbackTokenExpireIn, tokensvc.WithPipelinerunID(pr.ID)) + if err != nil { + return err + } + + // 4. create pipelinerun in k8s + tektonClient, err := c.tektonFty.GetTekton(cluster.EnvironmentName) + if err != nil { + return err + } + + regionEntity, err := c.regionMgr.GetRegionEntity(ctx, cluster.RegionName) + if err != nil { + return err + } + + tr, err := c.templateReleaseMgr.GetByTemplateNameAndRelease(ctx, cluster.Template, cluster.TemplateRelease) + if err != nil { + return err + } + clusterFiles, err := c.clusterGitRepo.GetCluster(ctx, + application.Name, cluster.Name, tr.ChartName) + if err != nil { + return err + } + + prGit := tekton.PipelineRunGit{ + URL: cluster.GitURL, + Subfolder: cluster.GitSubfolder, + Commit: pr.GitCommit, + } + switch pr.GitRefType { + case codemodels.GitRefTypeTag: + prGit.Tag = pr.GitRef + case codemodels.GitRefTypeBranch: + prGit.Branch = pr.GitRef + } + + ciEventID, err := tektonClient.CreatePipelineRun(ctx, &tekton.PipelineRun{ + Action: pr.Action, + Application: application.Name, + ApplicationID: application.ID, + Cluster: cluster.Name, + ClusterID: cluster.ID, + Environment: cluster.EnvironmentName, + Git: prGit, + ImageURL: pr.ImageURL, + Operator: currentUser.GetEmail(), + PipelinerunID: pr.ID, + PipelineJSONBlob: clusterFiles.PipelineJSONBlob, + Region: cluster.RegionName, + RegionID: regionEntity.ID, + Template: cluster.Template, + Token: token, + }) + if err != nil { + return err + } + + // update event id returned from tekton-trigger EventListener + log.Infof(ctx, "received event id: %s from tekton-trigger EventListener, pipelinerunID: %d", ciEventID, pr.ID) + err = c.prMgr.PipelineRun.UpdateColumns(ctx, pr.ID, map[string]interface{}{ + "ci_event_id": ciEventID, + "status": prmodels.StatusRunning, + }) + if err != nil { + return err + } + err = c.prMgr.PipelineRun.UpdateCIEventIDByID(ctx, pr.ID, ciEventID) + if err != nil { + return err + } + + return nil +} + +func (c *controller) Cancel(ctx context.Context, pipelinerunID uint) error { + const op = "pipelinerun controller: cancel pipelinerun" + defer wlog.Start(ctx, op).StopPrint() + return c.prMgr.PipelineRun.UpdateStatusByID(ctx, pipelinerunID, prmodels.StatusCancelled) +} + +func (c *controller) ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) { + const op = "pipelinerun controller: list check runs" + defer wlog.Start(context.Background(), op).StopPrint() + return c.prMgr.Check.ListCheckRuns(ctx, pipelineRunID) +} + +func (c *controller) CreateCheckRun(ctx context.Context, pipelineRunID uint, + request *CreateCheckRunRequest) (*models.CheckRun, error) { + const op = "pipelinerun controller: create check run" + defer wlog.Start(context.Background(), op).StopPrint() + + return c.prMgr.Check.CreateCheckRun(ctx, &models.CheckRun{ + Name: request.Name, + CheckID: request.CheckID, + Status: models.String2CheckRunStatus(request.Status), + Message: request.Message, + PipilineRunID: pipelineRunID, + DetailURL: request.DetailURL, + }) +} + +func (c *controller) CreatePRMessage(ctx context.Context, pipelineRunID uint, + request *CreatePrMessageRequest) (*models.PRMessage, error) { + const op = "pipelinerun controller: create pr message" + defer wlog.Start(context.Background(), op).StopPrint() + + currentUser, err := common.UserFromContext(ctx) + if err != nil { + return nil, err + } + + return c.prMgr.Message.Create(ctx, &models.PRMessage{ + PipelineRunID: pipelineRunID, + Content: request.Content, + CreatedBy: currentUser.GetID(), + }) +} + +func (c *controller) ListPRMessages(ctx context.Context, + pipelineRunID uint, query *q.Query) (int, []*PrMessage, error) { + const op = "pipelinerun controller: list pr messages" + defer wlog.Start(context.Background(), op).StopPrint() + + count, messages, err := c.prMgr.Message.List(ctx, pipelineRunID, query) + if err != nil { + return 0, nil, err + } + userIDs := make([]uint, 0, len(messages)) + m := make(map[uint]struct{}, 0) + for _, message := range messages { + if _, ok := m[message.CreatedBy]; !ok { + userIDs = append(userIDs, message.CreatedBy) + m[message.CreatedBy] = struct{}{} + } + if _, ok := m[message.UpdatedBy]; !ok { + userIDs = append(userIDs, message.UpdatedBy) + m[message.UpdatedBy] = struct{}{} + } + } + query = &q.Query{ + WithoutPagination: true, + Keywords: map[string]interface{}{common.UserQueryID: userIDs}, + } + _, users, err := c.userMgr.List(ctx, query) + if err != nil { + return 0, nil, err + } + userMap := make(map[uint]*usermodels.User, 0) + for _, user := range users { + userMap[user.ID] = user + } + result := make([]*PrMessage, 0, len(messages)) + for _, message := range messages { + resultMsg := &PrMessage{ + Content: message.Content, + CreatedAt: message.CreatedAt, + } + if user, ok := userMap[message.CreatedBy]; ok { + resultMsg.CreatedBy = User{ + ID: user.ID, + Name: user.FullName, + } + if user.UserType == usermodels.UserTypeRobot { + resultMsg.CreatedBy.UserType = "bot" + } + } + if user, ok := userMap[message.UpdatedBy]; ok { + resultMsg.UpdatedBy = User{ + ID: user.ID, + Name: user.FullName, + } + if user.UserType == usermodels.UserTypeRobot { + resultMsg.CreatedBy.UserType = "bot" + } + } + result = append(result, resultMsg) + } + return count, result, nil +} diff --git a/core/controller/pipelinerun/controller_test.go b/core/controller/pipelinerun/controller_test.go index 761046184..d74604f30 100644 --- a/core/controller/pipelinerun/controller_test.go +++ b/core/controller/pipelinerun/controller_test.go @@ -47,10 +47,11 @@ import ( groupmodels "github.com/horizoncd/horizon/pkg/group/models" membermodels "github.com/horizoncd/horizon/pkg/member/models" "github.com/horizoncd/horizon/pkg/param/managerparam" - "github.com/horizoncd/horizon/pkg/pipelinerun/models" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmanager "github.com/horizoncd/horizon/pkg/pr/manager" + "github.com/horizoncd/horizon/pkg/pr/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" - pipelinemodel "github.com/horizoncd/horizon/pkg/pipelinerun/models" + pipelinemodel "github.com/horizoncd/horizon/pkg/pr/models" usermodel "github.com/horizoncd/horizon/pkg/user/models" ) @@ -66,18 +67,18 @@ func TestGetAndListPipelinerun(t *testing.T) { mockCommitGetter := commitmock.NewMockGitGetter(mockCtl) mockClusterManager := clustermockmananger.NewMockManager(mockCtl) mockApplicationMananger := applicationmockmanager.NewMockManager(mockCtl) - mockPipelineManager := pipelinemockmanager.NewMockManager(mockCtl) + mockPipelineManager := pipelinemockmanager.NewMockPipelineRunManager(mockCtl) mockClusterGitRepo := clustergitrepomock.NewMockClusterGitRepo(mockCtl) mockUserManager := usermock.NewMockManager(mockCtl) var ctl Controller = &controller{ - pipelinerunMgr: mockPipelineManager, + prMgr: &prmanager.PRManager{PipelineRun: mockPipelineManager}, clusterMgr: mockClusterManager, - applicationMgr: mockApplicationMananger, + appMgr: mockApplicationMananger, envMgr: nil, tektonFty: nil, commitGetter: mockCommitGetter, clusterGitRepo: mockClusterGitRepo, - userManager: mockUserManager, + userMgr: mockUserManager, } // 1. test Get PipelineBasic @@ -93,10 +94,10 @@ func TestGetAndListPipelinerun(t *testing.T) { Name: UserName, }, nil).Times(1) - pipelineBasic, err := ctl.Get(ctx, pipelineID) + pipelineBasic, err := ctl.GetPipelinerun(ctx, pipelineID) assert.Nil(t, err) assert.Equal(t, pipelineBasic.ID, pipelineID) - assert.Equal(t, pipelineBasic.CreatedBy, UserInfo{ + assert.Equal(t, pipelineBasic.CreatedBy, models.UserInfo{ UserID: createUser, UserName: UserName, }) @@ -129,7 +130,7 @@ func TestGetAndListPipelinerun(t *testing.T) { PageNumber: 1, PageSize: 10, } - count, pipelineBasics, err := ctl.List(ctx, clusterID, false, query) + count, pipelineBasics, err := ctl.ListPipelineruns(ctx, clusterID, false, query) assert.Nil(t, err) assert.Equal(t, count, totalCount) assert.Equal(t, len(pipelineBasics), 2) @@ -145,13 +146,13 @@ func TestGetDiff(t *testing.T) { mockCommitGetter := commitmock.NewMockGitGetter(mockCtl) mockClusterManager := clustermockmananger.NewMockManager(mockCtl) mockApplicationMananger := applicationmockmanager.NewMockManager(mockCtl) - mockPipelineManager := pipelinemockmanager.NewMockManager(mockCtl) + mockPipelineManager := pipelinemockmanager.NewMockPipelineRunManager(mockCtl) mockClusterGitRepo := clustergitrepomock.NewMockClusterGitRepo(mockCtl) var ctl Controller = &controller{ - pipelinerunMgr: mockPipelineManager, + prMgr: &prmanager.PRManager{PipelineRun: mockPipelineManager}, clusterMgr: mockClusterManager, - applicationMgr: mockApplicationMananger, + appMgr: mockApplicationMananger, envMgr: nil, tektonFty: nil, commitGetter: mockCommitGetter, @@ -265,7 +266,7 @@ func Test(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, cluster) - pipelinerunMgr := manager.PipelinerunMgr + pipelinerunMgr := manager.PRMgr.PipelineRun pipelinerun, err := pipelinerunMgr.Create(ctx, &prmodels.Pipelinerun{ ClusterID: cluster.ID, Action: "builddeploy", @@ -279,10 +280,10 @@ func Test(t *testing.T) { assert.NotNil(t, pipelinerun) c := &controller{ - pipelinerunMgr: pipelinerunMgr, - clusterMgr: clusterMgr, - envMgr: envMgr, - tektonFty: tektonFty, + prMgr: manager.PRMgr, + clusterMgr: clusterMgr, + envMgr: envMgr, + tektonFty: tektonFty, } logBytes := []byte("this is a log") @@ -363,7 +364,7 @@ func Test(t *testing.T) { pipelinerun, err = pipelinerunMgr.Create(ctx, &prmodels.Pipelinerun{ ClusterID: cluster.ID, Action: "builddeploy", - Status: string(prmodels.StatusCreated), + Status: string(prmodels.StatusRunning), S3Bucket: "", LogObject: "", PrObject: "", diff --git a/core/controller/pipelinerun/models.go b/core/controller/pipelinerun/models.go index bf3ebb0f0..7cd2e763e 100644 --- a/core/controller/pipelinerun/models.go +++ b/core/controller/pipelinerun/models.go @@ -14,9 +14,7 @@ package pipelinerun -import ( - "time" -) +import "time" type GetDiffResponse struct { CodeInfo *CodeInfo `json:"codeInfo"` @@ -42,49 +40,33 @@ type ConfigDiff struct { Diff string `json:"diff"` } -type PipelineBasic struct { - // ID pipelinerun id - ID uint `json:"id"` - Title string `json:"title"` - // Description of this pipelinerun - Description string `json:"description"` +type BuildDeployRequestGit struct { + Branch string `json:"branch"` + Tag string `json:"tag"` + Commit string `json:"commit"` +} - // Action type, which can be builddeploy, deploy, restart, rollback - Action string `json:"action"` - // Status of this pipelinerun, which can be created, ok, failed, cancelled, unknown - Status string `json:"status"` - // Title of this pipelinerun +type CreatePrMessageRequest struct { + Content string `json:"string"` +} - // GitURL the git url this pipelinerun to build with, can be empty when action is not builddeploy - GitURL string `json:"gitURL"` - // GitBranch the git branch this pipelinerun to build with, can be empty when action is not builddeploy - GitBranch string `json:"gitBranch,omitempty"` - // GitTag the git tag this pipelinerun to build with, can be empty when action is not builddeploy - GitTag string `json:"gitTag,omitempty"` - // GitCommit the git commit this pipelinerun to build with, can be empty when action is not builddeploy - GitCommit string `json:"gitCommit"` - // ImageURL image url of this pipelinerun to build image - ImageURL string `json:"imageURL"` +type User struct { + ID uint `json:"id"` + Name string `json:"name"` + UserType string `json:"userType,omitempty"` +} - // LastConfigCommit config commit in master branch of this pipelinerun, can be empty when action is restart - LastConfigCommit string `json:"lastConfigCommit"` - // ConfigCommit config commit of this pipelinerun - ConfigCommit string `json:"configCommit"` - // CreatedAt create time of this pipelinerun +type PrMessage struct { + Content string `json:"content"` + CreatedBy User `json:"createdBy"` + UpdatedBy User `json:"updatedBy"` CreatedAt time.Time `json:"createdAt"` - // UpdatedAt update time of this pipelinerun - UpdatedAt time.Time `json:"updatedAt"` - // StartedAt start time of this pipelinerun - StartedAt *time.Time `json:"startedAt"` - // FinishedAt finish time of this pipelinerun - FinishedAt *time.Time `json:"finishedAt"` - // CanRollback can this pipelinerun be rollback, default is false - CanRollback bool `json:"canRollback"` - // createInfo - CreatedBy UserInfo `json:"createdBy"` } -type UserInfo struct { - UserID uint `json:"userID"` - UserName string `json:"userName"` +type CreateCheckRunRequest struct { + Name string `json:"name"` + CheckID uint `json:"checkId"` + Status string `json:"status"` + Message string `json:"message"` + DetailURL string `json:"detailUrl"` } diff --git a/core/errors/horizonerrors.go b/core/errors/horizonerrors.go index ef2d7b387..4eb795e96 100644 --- a/core/errors/horizonerrors.go +++ b/core/errors/horizonerrors.go @@ -71,6 +71,9 @@ var ( WebhookInDB = sourceType{name: "WebhookInDB"} WebhookLogInDB = sourceType{name: "WebhookLogInDB"} MetatagInDB = sourceType{name: "MetatagInDB"} + CheckInDB = sourceType{name: "CheckInDB"} + CheckRunInDB = sourceType{name: "CheckRunInDB"} + PRMessageInDB = sourceType{name: "PRMessageInDB"} // S3 PipelinerunLog = sourceType{name: "PipelinerunLog"} diff --git a/core/http/api/v1/pipelinerun/apis.go b/core/http/api/v1/pipelinerun/apis.go index 832d0a5e7..118176186 100644 --- a/core/http/api/v1/pipelinerun/apis.go +++ b/core/http/api/v1/pipelinerun/apis.go @@ -132,7 +132,7 @@ func (a *API) Get(c *gin.Context) { response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) return } - resp, err := a.prCtl.Get(c, uint(pipelinerunID)) + resp, err := a.prCtl.GetPipelinerun(c, uint(pipelinerunID)) if err != nil { response.AbortWithError(c, err) return @@ -160,7 +160,7 @@ func (a *API) List(c *gin.Context) { canRollback = false } - total, pipelines, err := a.prCtl.List(c, uint(clusterID), canRollback, q.Query{ + total, pipelines, err := a.prCtl.ListPipelineruns(c, uint(clusterID), canRollback, q.Query{ PageNumber: pageNumber, PageSize: pageSize, }) diff --git a/core/http/api/v2/cluster/apis_basic.go b/core/http/api/v2/cluster/apis_basic.go index d9ac5328c..0e01b1dd7 100644 --- a/core/http/api/v2/cluster/apis_basic.go +++ b/core/http/api/v2/cluster/apis_basic.go @@ -20,6 +20,7 @@ import ( "strings" "github.com/gin-gonic/gin" + "github.com/horizoncd/horizon/core/common" "github.com/horizoncd/horizon/core/controller/cluster" herrors "github.com/horizoncd/horizon/core/errors" @@ -527,3 +528,30 @@ func (a *API) DeleteFavorite(c *gin.Context) { } response.Success(c) } + +func (a *API) CreatePipelineRun(c *gin.Context) { + op := "cluster: create pipeline run" + clusterIDStr := c.Param(common.ParamClusterID) + clusterID, err := strconv.ParseUint(clusterIDStr, 10, 0) + if err != nil { + response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) + return + } + + var req cluster.CreatePipelineRunRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) + return + } + pipelineRun, err := a.clusterCtl.CreatePipelineRun(c, uint(clusterID), &req) + if err != nil { + if e, ok := perror.Cause(err).(*herrors.HorizonErrNotFound); ok && e.Source == herrors.ClusterInDB { + response.AbortWithRPCError(c, rpcerror.NotFoundError.WithErrMsg(err.Error())) + return + } + log.WithFiled(c, "op", op).Errorf("%+v", err) + response.AbortWithRPCError(c, rpcerror.InternalError.WithErrMsg(err.Error())) + return + } + response.SuccessWithData(c, pipelineRun) +} diff --git a/core/http/api/v2/cluster/routers.go b/core/http/api/v2/cluster/routers.go index b07628316..fc02fc440 100644 --- a/core/http/api/v2/cluster/routers.go +++ b/core/http/api/v2/cluster/routers.go @@ -19,6 +19,7 @@ import ( "net/http" "github.com/gin-gonic/gin" + "github.com/horizoncd/horizon/core/common" "github.com/horizoncd/horizon/pkg/server/route" ) @@ -134,6 +135,10 @@ func (api *API) RegisterRoute(engine *gin.Engine) { Method: http.MethodDelete, Pattern: fmt.Sprintf("/clusters/:%v/favorite", common.ParamClusterID), HandlerFunc: api.DeleteFavorite, + }, { + Method: http.MethodPost, + Pattern: fmt.Sprintf("/clusters/:%v/pipelinerun", common.ParamClusterID), + HandlerFunc: api.CreatePipelineRun, }, } diff --git a/core/http/api/v2/pipelinerun/apis.go b/core/http/api/v2/pipelinerun/apis.go index 11231d2a3..55226554a 100644 --- a/core/http/api/v2/pipelinerun/apis.go +++ b/core/http/api/v2/pipelinerun/apis.go @@ -20,10 +20,13 @@ import ( "github.com/horizoncd/horizon/core/common" prctl "github.com/horizoncd/horizon/core/controller/pipelinerun" + herrors "github.com/horizoncd/horizon/core/errors" "github.com/horizoncd/horizon/lib/q" "github.com/horizoncd/horizon/pkg/cluster/tekton/collector" + perror "github.com/horizoncd/horizon/pkg/errors" "github.com/horizoncd/horizon/pkg/server/request" "github.com/horizoncd/horizon/pkg/server/response" + "github.com/horizoncd/horizon/pkg/server/rpcerror" "github.com/horizoncd/horizon/pkg/util/errors" "github.com/gin-gonic/gin" @@ -46,21 +49,17 @@ func NewAPI(prCtl prctl.Controller) *API { } func (a *API) Log(c *gin.Context) { - prIDStr := c.Param(_pipelinerunIDParam) - prID, err := strconv.ParseUint(prIDStr, 10, 0) - if err != nil { - response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) - return - } - l, err := a.prCtl.GetPipelinerunLog(c, uint(prID)) - if err != nil { - l := &collector.Log{ - LogBytes: []byte(errors.Message(err)), + a.withID(c, func(prID uint) { + l, err := a.prCtl.GetPipelinerunLog(c, uint(prID)) + if err != nil { + l := &collector.Log{ + LogBytes: []byte(errors.Message(err)), + } + a.writeLog(c, l) + return } a.writeLog(c, l) - return - } - a.writeLog(c, l) + }) } func (a *API) writeLog(c *gin.Context, l *collector.Log) { @@ -95,33 +94,25 @@ func (a *API) writeLog(c *gin.Context, l *collector.Log) { } func (a *API) GetDiff(c *gin.Context) { - pipelinerunIDStr := c.Param(_pipelinerunIDParam) - pipelinerunID, err := strconv.ParseUint(pipelinerunIDStr, 10, 0) - if err != nil { - response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) - return - } - diff, err := a.prCtl.GetDiff(c, uint(pipelinerunID)) - if err != nil { - response.AbortWithError(c, err) - return - } - response.SuccessWithData(c, diff) + a.withID(c, func(pipelinerunID uint) { + diff, err := a.prCtl.GetDiff(c, uint(pipelinerunID)) + if err != nil { + response.AbortWithError(c, err) + return + } + response.SuccessWithData(c, diff) + }) } func (a *API) Get(c *gin.Context) { - pipelinerunIDStr := c.Param(_pipelinerunIDParam) - pipelinerunID, err := strconv.ParseUint(pipelinerunIDStr, 10, 0) - if err != nil { - response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) - return - } - resp, err := a.prCtl.Get(c, uint(pipelinerunID)) - if err != nil { - response.AbortWithError(c, err) - return - } - response.SuccessWithData(c, resp) + a.withID(c, func(pipelinerunID uint) { + resp, err := a.prCtl.GetPipelinerun(c, uint(pipelinerunID)) + if err != nil { + response.AbortWithError(c, err) + return + } + response.SuccessWithData(c, resp) + }) } func (a *API) List(c *gin.Context) { @@ -144,7 +135,7 @@ func (a *API) List(c *gin.Context) { canRollback = false } - total, pipelines, err := a.prCtl.List(c, uint(clusterID), canRollback, q.Query{ + total, pipelines, err := a.prCtl.ListPipelineruns(c, uint(clusterID), canRollback, q.Query{ PageNumber: pageNumber, PageSize: pageSize, }) @@ -159,16 +150,123 @@ func (a *API) List(c *gin.Context) { } func (a *API) Stop(c *gin.Context) { - pipelinerunIDStr := c.Param(_pipelinerunIDParam) - pipelinerunID, err := strconv.ParseUint(pipelinerunIDStr, 10, 0) + a.withID(c, func(prID uint) { + err := a.prCtl.StopPipelinerun(c, uint(prID)) + if err != nil { + response.AbortWithError(c, err) + return + } + response.Success(c) + }) +} + +func (a *API) ExecuteForce(c *gin.Context) { + a.execute(c, true) +} + +func (a *API) Execute(c *gin.Context) { + a.execute(c, false) +} + +func (a *API) execute(c *gin.Context, force bool) { + a.withID(c, func(prID uint) { + err := a.prCtl.Execute(c, prID, force) + if err != nil { + if e, ok := perror.Cause(err).(*herrors.HorizonErrNotFound); ok { + response.AbortWithRPCError(c, rpcerror.NotFoundError.WithErrMsg(e.Error())) + return + } + response.AbortWithRPCError(c, rpcerror.InternalError.WithErrMsg(err.Error())) + return + } + response.Success(c) + }) +} + +func (a *API) Cancel(c *gin.Context) { + a.withID(c, func(prID uint) { + err := a.prCtl.Cancel(c, prID) + if err != nil { + response.AbortWithError(c, err) + return + } + response.Success(c) + }) +} + +func (a *API) ListCheckRuns(c *gin.Context) { + a.withID(c, func(prID uint) { + checkRuns, err := a.prCtl.ListCheckRuns(c, prID) + if err != nil { + response.AbortWithError(c, err) + return + } + response.SuccessWithData(c, checkRuns) + }) +} + +func (a *API) CreateCheckRuns(c *gin.Context) { + var req prctl.CreateCheckRunRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) + return + } + a.withID(c, func(prID uint) { + checkrun, err := a.prCtl.CreateCheckRun(c, prID, &req) + if err != nil { + response.AbortWithError(c, err) + return + } + response.SuccessWithData(c, checkrun) + }) +} + +func (a *API) CreatePrMessage(c *gin.Context) { + var req prctl.CreatePrMessageRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) + return + } + + a.withID(c, func(prID uint) { + checkMessage, err := a.prCtl.CreatePRMessage(c, prID, &req) + if err != nil { + response.AbortWithError(c, err) + return + } + response.SuccessWithData(c, checkMessage) + }) +} + +func (a *API) ListPrMessages(c *gin.Context) { + pageNumber, pageSize, err := request.GetPageParam(c) if err != nil { response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) return } - err = a.prCtl.StopPipelinerun(c, uint(pipelinerunID)) + query := &q.Query{ + PageNumber: pageNumber, + PageSize: pageSize, + } + a.withID(c, func(prID uint) { + count, messages, err := a.prCtl.ListPRMessages(c, prID, query) + if err != nil { + response.AbortWithError(c, err) + return + } + response.SuccessWithData(c, response.DataWithTotal{ + Total: int64(count), + Items: messages, + }) + }) +} + +func (a *API) withID(c *gin.Context, f func(pipelineRunID uint)) { + idStr := c.Param(_pipelinerunIDParam) + id, err := strconv.ParseUint(idStr, 10, 0) if err != nil { - response.AbortWithError(c, err) + response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) return } - response.Success(c) + f(uint(id)) } diff --git a/core/http/api/v2/pipelinerun/routers.go b/core/http/api/v2/pipelinerun/routers.go index 567deae77..3ef501f0f 100644 --- a/core/http/api/v2/pipelinerun/routers.go +++ b/core/http/api/v2/pipelinerun/routers.go @@ -49,6 +49,41 @@ func (api *API) RegisterRoute(engine *gin.Engine) { Pattern: fmt.Sprintf("/clusters/:%v/pipelineruns", _clusterIDParam), HandlerFunc: api.List, }, + { + Method: http.MethodPost, + Pattern: fmt.Sprintf("/pipelineruns/:%v/run", _pipelinerunIDParam), + HandlerFunc: api.Execute, + }, + { + Method: http.MethodPost, + Pattern: fmt.Sprintf("/pipelineruns/:%v/forcerun", _pipelinerunIDParam), + HandlerFunc: api.ExecuteForce, + }, + { + Method: http.MethodPost, + Pattern: fmt.Sprintf("/pipelineruns/:%v/cancel", _pipelinerunIDParam), + HandlerFunc: api.Cancel, + }, + { + Method: http.MethodGet, + Pattern: fmt.Sprintf("/pipelineruns/:%v/checkrun", _pipelinerunIDParam), + HandlerFunc: api.ListCheckRuns, + }, + { + Method: http.MethodPost, + Pattern: fmt.Sprintf("/pipelineruns/:%v/checkrun", _pipelinerunIDParam), + HandlerFunc: api.CreateCheckRuns, + }, + { + Method: http.MethodGet, + Pattern: fmt.Sprintf("/pipelineruns/:%v/message", _pipelinerunIDParam), + HandlerFunc: api.ListPrMessages, + }, + { + Method: http.MethodPost, + Pattern: fmt.Sprintf("/pipelineruns/:%v/message", _pipelinerunIDParam), + HandlerFunc: api.CreatePrMessage, + }, } route.RegisterRoutes(apiGroup, routes) diff --git a/db/20230817.sql b/db/20230817.sql new file mode 100644 index 000000000..40dd64566 --- /dev/null +++ b/db/20230817.sql @@ -0,0 +1,669 @@ +-- Copyright © 2023 Horizoncd. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +-- check table +CREATE TABLE `tb_check` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `resource_type` varchar(64) NOT NULL DEFAULT '' COMMENT 'resource type', + `resource_id` bigint(20) unsigned NOT NULL COMMENT 'resource id', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_resource_deleted` (`resource_type`, `resource_id`, `deleted_ts`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- check run table +CREATE TABLE `tb_checkrun` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(256) NOT NULL DEFAULT '' COMMENT 'the name of check run', + `status` varchar(64) NOT NULL DEFAULT '' COMMENT 'the status of check run', + `pipeline_run_id` bigint(20) unsigned NOT NULL COMMENT 'pipeline run id', + `check_id` bigint(20) unsigned NOT NULL COMMENT 'check id', + `message` varchar(256) NOT NULL DEFAULT '', + `detail_url` varchar(256) NOT NULL DEFAULT '' COMMENT 'the detail url of check run', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_pipeline_run_id_check_id_deleted` (`pipeline_run_id`, `check_id`, `deleted_ts`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- pr_msg table +CREATE TABLE `tb_pr_msg` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `pipeline_run_id` bigint(20) unsigned NOT NULL COMMENT 'pipeline run id', + `content` text NOT NULL DEFAULT '' COMMENT 'content of message', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + PRIMARY KEY (`id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- group table +CREATE TABLE `tb_group` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL DEFAULT '', + `path` varchar(32) NOT NULL DEFAULT '', + `description` varchar(256) DEFAULT NULL, + `visibility_level` varchar(16) NOT NULL COMMENT 'public or private', + `parent_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'ID of the parent group', + `traversal_ids` varchar(32) NOT NULL DEFAULT '' COMMENT 'ID path from the root, like 1,2,3', + `region_selector` varchar(512) NOT NULL DEFAULT '' COMMENT 'used for filtering kubernetes', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_parentId_name_deletedTs` (`parent_id`, `name`, `deleted_ts`), + UNIQUE KEY `uk_parentId_path_deletedTs` (`parent_id`, `path`, `deleted_ts`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- user table +CREATE TABLE `tb_user` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(64) NOT NULL DEFAULT '', + `full_name` varchar(128) DEFAULT '', + `email` varchar(64) NOT NULL DEFAULT '', + `phone` varchar(32) DEFAULT NULL, + `oidc_id` varchar(64) NOT NULL COMMENT 'oidc id, which is a unique index in oidc system.', + `oidc_type` varchar(64) NOT NULL COMMENT 'oidc type, such as google, github, gitlab etc.', + `admin` tinyint(1) NOT NULL COMMENT 'is system admin,0-false,1-true', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT 0, + `user_type` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT 'the option type is: 0 (common user), 1(robot user)', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_name` (`name`), + UNIQUE KEY `idx_email` (`email`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- template table +CREATE TABLE `tb_template` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(64) NOT NULL DEFAULT '' COMMENT 'the name of template', + `description` varchar(256) DEFAULT NULL COMMENT 'the template description', + `repository` varchar(256) NOT NULL DEFAULT '', + `group_id` bigint(20) unsigned NOT NULL DEFAULT '0', + `chart_name` varchar(256) DEFAULT '', + `only_owner` tinyint(1) NOT NULL DEFAULT '0', + `without_ci` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'without_ci configuration, 0 means with ci', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_name` (`name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- template release table +CREATE TABLE `tb_template_release` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `template_name` varchar(64) NOT NULL COMMENT 'the name of template', + `name` varchar(64) NOT NULL DEFAULT '' COMMENT 'the name of template release', + `description` varchar(256) NOT NULL COMMENT 'description about this template release', + `recommended` tinyint(1) NOT NULL COMMENT 'is the most recommended template, 0-false, 1-true', + `template` bigint(20) unsigned NOT NULL DEFAULT '0', + `chart_name` varchar(256) NOT NULL DEFAULT '', + `only_owner` tinyint(1) NOT NULL DEFAULT '0', + `chart_version` varchar(256) NOT NULL DEFAULT '' COMMENT 'chart version on template repository', + `sync_status` varchar(64) NOT NULL DEFAULT 'status_unknown' COMMENT 'shows sync status', + `failed_reason` varchar(2048) NOT NULL DEFAULT '' COMMENT 'failed reason at last time', + `commit_id` varchar(256) NOT NULL DEFAULT '' COMMENT 'commit id at last sync', + `last_sync_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_template_name_name` (`template_name`, `name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- member table +CREATE TABLE `tb_member` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `resource_type` varchar(64) NOT NULL COMMENT 'groupapplicationcluster', + `resource_id` bigint(20) unsigned NOT NULL COMMENT 'resource id', + `role` varchar(64) NOT NULL COMMENT 'binding role name', + `member_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0-USER, 1-group', + `membername_id` bigint(20) unsigned NOT NULL COMMENT 'UserID or GroupID', + `granted_by` bigint(20) unsigned NOT NULL COMMENT 'who grant the role', + `created_by` bigint(20) unsigned NOT NULL COMMENT 'who create the role', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) NOT NULL DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_resource_member_deleted` (`resource_type`, `resource_id`, `member_type`, `membername_id`, + `deleted_ts`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- application table +CREATE TABLE `tb_application` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `group_id` bigint(20) unsigned NOT NULL COMMENT 'group id', + `name` varchar(64) NOT NULL DEFAULT '' COMMENT 'the name of application', + `description` varchar(256) DEFAULT NULL COMMENT 'the description of application', + `priority` varchar(16) NOT NULL DEFAULT 'P3' COMMENT 'the priority of application', + `git_url` varchar(128) DEFAULT NULL COMMENT 'git repo url', + `git_subfolder` varchar(128) DEFAULT NULL COMMENT 'git repo subfolder', + `git_branch` varchar(128) DEFAULT NULL COMMENT 'git default branch', + `git_ref` varchar(128) DEFAULT NULL, + `git_ref_type` varchar(64) DEFAULT NULL, + `template` varchar(64) NOT NULL COMMENT 'template name', + `template_release` varchar(64) NOT NULL COMMENT 'template release', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_name_deletedTs` (`name`, `deleted_ts`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- registry table +CREATE TABLE `tb_registry` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL DEFAULT '' COMMENT 'name of the harbor registry', + `server` varchar(256) NOT NULL DEFAULT '' COMMENT 'harbor server address', + `token` varchar(512) NOT NULL DEFAULT '' COMMENT 'harbor server token', + `path` varchar(256) NOT NULL DEFAULT '' COMMENT 'path of image', + `insecure_skip_tls_verify` tinyint(1) NOT NULL DEFAULT false COMMENT 'skip tls verify', + `kind` varchar(256) NOT NULL DEFAULT 'harbor' COMMENT 'which kind registry it is', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 12 + DEFAULT CHARSET = utf8mb4; + +-- environment table +CREATE TABLE `tb_environment` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL DEFAULT '' COMMENT 'env name', + `display_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'display name', + `default_region` varchar(128) DEFAULT NULL COMMENT 'default region of the environment', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + `auto_free` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'auto free configuration, 0 means disabled', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_name_deletedTs` (`name`, `deleted_ts`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- region table +CREATE TABLE `tb_region` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL DEFAULT '' COMMENT 'region name', + `display_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'region display name', + `server` varchar(256) DEFAULT NULL COMMENT 'k8s server url', + `certificate` text COMMENT 'k8s kube config', + `ingress_domain` text COMMENT 'k8s ingress domain', + `prometheus_url` varchar(128) COMMENT 'prometheus url', + `registry_id` bigint(20) unsigned NOT NULL COMMENT 'registry id', + `disabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0 means not disabled, 1 means disabled', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_name` (`name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- environment_region table +CREATE TABLE `tb_environment_region` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `environment_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'environment name', + `region_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'region name', + `is_default` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0 means not default region, 1 means default region', + `disabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'is disabled,0-false,1-true', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_env_region_deletedTs` (`environment_name`, `region_name`, `deleted_ts`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- cluster table +CREATE TABLE `tb_cluster` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `application_id` bigint(20) unsigned NOT NULL COMMENT 'application id', + `name` varchar(64) NOT NULL DEFAULT '' COMMENT 'the name of cluster', + `environment_name` varchar(128) NOT NULL DEFAULT '', + `region_name` varchar(128) NOT NULL DEFAULT '', + `description` varchar(256) DEFAULT NULL COMMENT 'the description of cluster', + `git_url` varchar(128) DEFAULT NULL COMMENT 'git repo url', + `git_subfolder` varchar(128) DEFAULT NULL COMMENT 'git repo subfolder', + `git_branch` varchar(128) DEFAULT NULL COMMENT 'git branch', + `git_ref` varchar(128) DEFAULT NULL, + `git_ref_type` varchar(64) DEFAULT NULL, + `template` varchar(64) NOT NULL COMMENT 'template name', + `template_release` varchar(64) NOT NULL COMMENT 'template release', + `status` varchar(64) DEFAULT NULL, + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + `expire_seconds` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'expiration seconds, 0 means permanent', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_name_deletedTs` (`name`, `deleted_ts`), + KEY `idx_application_id` (`application_id`), + KEY `idx_deleted_ts` (`deleted_ts`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- tag table +CREATE TABLE `tb_tag` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `resource_id` bigint(20) unsigned NOT NULL COMMENT 'resource id', + `resource_type` varchar(64) NOT NULL DEFAULT '' COMMENT 'resource type', + `tag_key` varchar(64) NOT NULL DEFAULT '' COMMENT 'key of tag', + `tag_value` varchar(1280) NOT NULL DEFAULT '' COMMENT 'value of tag', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_rType_cId_tKey` (`resource_type`, `resource_id`, `tag_key`), + KEY `idx_cluster_id` (`resource_id`), + KEY `idx_key` (`tag_key`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- cluster template schema tag table +CREATE TABLE `tb_cluster_template_schema_tag` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `cluster_id` bigint(20) unsigned NOT NULL COMMENT 'cluster id', + `tag_key` varchar(64) NOT NULL DEFAULT '' COMMENT 'key of tag', + `tag_value` varchar(1280) NOT NULL DEFAULT '' COMMENT 'value of tag', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_cluster_id_key` (`cluster_id`, `tag_key`), + KEY `idx_key` (`tag_key`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- pipelinerun table +CREATE TABLE `tb_pipelinerun` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `cluster_id` bigint(20) unsigned NOT NULL COMMENT 'cluster id', + `action` varchar(64) NOT NULL COMMENT 'action', + `status` varchar(64) NOT NULL DEFAULT '' COMMENT 'the pipelinerun status', + `title` varchar(256) NOT NULL DEFAULT '' COMMENT 'the title of pipelinerun', + `description` varchar(2048) DEFAULT NULL COMMENT 'the description of pipelinerun', + `git_url` varchar(128) DEFAULT NULL COMMENT 'git repo url', + `git_branch` varchar(128) DEFAULT NULL COMMENT 'the branch to build of this pipelinerun', + `git_ref` varchar(128) DEFAULT NULL, + `git_ref_type` varchar(64) DEFAULT NULL, + `git_commit` varchar(128) DEFAULT NULL COMMENT 'the commit to build of this pipelinerun', + `image_url` varchar(256) DEFAULT NULL COMMENT 'image url', + `last_config_commit` varchar(128) DEFAULT NULL COMMENT 'the last commit of cluster config', + `config_commit` varchar(128) DEFAULT NULL COMMENT 'the new commit of cluster config', + `s3_bucket` varchar(128) NOT NULL DEFAULT '' COMMENT 's3 bucket to storage this pipelinerun log', + `log_object` varchar(258) NOT NULL DEFAULT '' COMMENT 's3 object for log', + `pr_object` varchar(258) NOT NULL DEFAULT '' COMMENT 's3 object for pipelinerun', + `ci_event_id` varchar(36) NOT NULL DEFAULT '' COMMENT 'event id returned from ci component', + `started_at` datetime DEFAULT NULL COMMENT 'start time of this pipelinerun', + `finished_at` datetime DEFAULT NULL COMMENT 'finish time of this pipelinerun', + `rollback_from` bigint(20) unsigned DEFAULT NULL COMMENT 'the pipelinerun id that this pipelinerun rollback from', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + PRIMARY KEY (`id`), + KEY `idx_cluster_action` (`cluster_id`, `action`), + KEY `idx_cluster_config_commit` (`cluster_id`, `config_commit`), + KEY `idx_ci_event_id` (`ci_event_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- application region table +CREATE TABLE `tb_application_region` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `application_id` bigint(20) unsigned NOT NULL COMMENT 'application id', + `environment_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'environment name', + `region_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'default deploy region of the environment', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_application_environment` (`application_id`, `environment_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- tekton pipeline +CREATE TABLE `tb_pipeline` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `pipelinerun_id` bigint(20) unsigned NOT NULL COMMENT 'pipelinerun id', + `application` varchar(64) NOT NULL COMMENT 'application name', + `cluster` varchar(64) NOT NULL COMMENT 'cluster name', + `region` varchar(16) NOT NULL COMMENT 'region name', + `pipeline` varchar(16) NOT NULL DEFAULT '' COMMENT 'pipeline name', + `result` varchar(16) NOT NULL DEFAULT '' COMMENT 'result of the step, ok、failed or others', + `duration` int(16) NOT NULL COMMENT 'duration', + `started_at` datetime NOT NULL COMMENT 'start time of this pipelinerun', + `finished_at` datetime NOT NULL COMMENT 'finish time of this pipelinerun', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_region_application_created_at` (`region`, `application`, `created_at`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- tekton pipeline task +CREATE TABLE `tb_task` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `pipelinerun_id` bigint(20) unsigned NOT NULL COMMENT 'pipelinerun id', + `application` varchar(64) NOT NULL COMMENT 'application name', + `cluster` varchar(64) NOT NULL COMMENT 'cluster name', + `region` varchar(16) NOT NULL COMMENT 'region name', + `pipeline` varchar(16) NOT NULL DEFAULT '' COMMENT 'pipeline name', + `task` varchar(16) NOT NULL DEFAULT '' COMMENT 'task name', + `result` varchar(16) NOT NULL DEFAULT '' COMMENT 'result of the step, ok or failed', + `duration` int(16) NOT NULL COMMENT 'duration', + `started_at` datetime NOT NULL COMMENT 'start time of this pipelinerun', + `finished_at` datetime NOT NULL COMMENT 'finish time of this pipelinerun', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_region_application_created_at` (`region`, `application`, `created_at`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- tekton task step +CREATE TABLE `tb_step` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `pipelinerun_id` bigint(20) unsigned NOT NULL COMMENT 'pipelinerun id', + `application` varchar(64) NOT NULL COMMENT 'application name', + `cluster` varchar(64) NOT NULL COMMENT 'cluster name', + `region` varchar(16) NOT NULL COMMENT 'region name', + `pipeline` varchar(16) NOT NULL DEFAULT '' COMMENT 'pipeline name', + `task` varchar(16) NOT NULL DEFAULT '' COMMENT 'task name', + `step` varchar(16) NOT NULL DEFAULT '' COMMENT 'step name', + `result` varchar(16) NOT NULL DEFAULT '' COMMENT 'result of the step, ok or failed', + `duration` int(16) NOT NULL COMMENT 'duration', + `started_at` datetime NOT NULL COMMENT 'start time of this pipelinerun', + `finished_at` datetime NOT NULL COMMENT 'finish time of this pipelinerun', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_region_application_created_at` (`region`, `application`, `created_at`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- oauth app table +CREATE TABLE `tb_oauth_app` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(128) DEFAULT NULL COMMENT 'short name of app client', + `client_id` varchar(128) DEFAULT NULL COMMENT 'oauth app client', + `redirect_url` varchar(256) DEFAULT NULL COMMENT 'the authorization callback url', + `home_url` varchar(256) DEFAULT NULL COMMENT 'the oauth app home url', + `description` varchar(256) DEFAULT NULL COMMENT 'the desc of app', + `app_type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1 for HorizonOAuthAPP, 2 for DirectOAuthAPP', + `owner_type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1 for group, 2 for user', + `owner_id` bigint(20) DEFAULT NULL COMMENT 'group owner id', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'created_at', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_client_id` (`client_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- oauth client secret table +CREATE TABLE `tb_oauth_client_secret` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `client_id` varchar(256) DEFAULT NULL COMMENT 'oauth app client', + `client_secret` varchar(256) DEFAULT NULL COMMENT 'oauth app secret', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_client_id_secret` (`client_id`, `client_secret`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- token table +CREATE TABLE `tb_token` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(64) NOT NULL DEFAULT '', + `client_id` varchar(256) DEFAULT NULL COMMENT 'oauth app client', + `redirect_uri` varchar(256) DEFAULT NULL, + `state` varchar(256) DEFAULT NULL COMMENT ' authorize_code state info', + `code` varchar(256) NOT NULL DEFAULT '' COMMENT 'private-token-code/authorize_code/access_token/refresh-token', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `expires_in` bigint(20) DEFAULT NULL, + `scope` varchar(256) DEFAULT NULL, + `user_id` bigint(20) unsigned NOT NULL DEFAULT '0', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_code` (`code`), + KEY `idx_client_id` (`client_id`), + KEY `idx_user_id` (`user_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- identity provider table +create table `tb_identity_provider` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `display_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'name displayed on web', + `name` varchar(128) NOT NULL DEFAULT '' COMMENT 'name to generate index in db, unique', + `avatar` varchar(256) NOT NULL DEFAULT '' COMMENT 'link to avatar', + `authorization_endpoint` varchar(256) NOT NULL DEFAULT '' COMMENT 'authorization endpoint of idp', + `token_endpoint` varchar(256) NOT NULL DEFAULT '' COMMENT 'token endpoint of idp', + `userinfo_endpoint` varchar(256) NOT NULL DEFAULT '' COMMENT 'userinfo endpoint of idp', + `revocation_endpoint` varchar(256) NOT NULL DEFAULT '' COMMENT 'revocation endpoint of idp', + `issuer` varchar(256) NOT NULL DEFAULT '' COMMENT 'issuer of idp, generating discovery endpoint', + `scopes` varchar(256) NOT NULL DEFAULT '' COMMENT 'scopes when asking for authorization', + `signing_algs` varchar(256) NOT NULL DEFAULT '' COMMENT 'algs for verifying signing', + `token_endpoint_auth_method` varchar(256) NOT NULL DEFAULT 'client_secret_sent_as_post' COMMENT 'how to carry client secret', + `jwks` varchar(256) NOT NULL DEFAULT '' COMMENT 'jwks endpoint, describe how to identify a token', + `client_id` varchar(256) NOT NULL DEFAULT '' COMMENT 'client id issued by idp', + `client_secret` varchar(256) NOT NULL DEFAULT '' COMMENT 'client secret issued by idp', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'time of first creating', + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'time of last updating', + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_name` (`name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- idp and user relationship table +create table `tb_idp_user` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `sub` varchar(256) NOT NULL DEFAULT '' COMMENT 'user id in idp', + `idp_id` bigint(20) NOT NULL DEFAULT 0 COMMENT 'refer to tb_identify_provider', + `user_id` bigint(20) NOT NULL DEFAULT 0 COMMENT 'refer to tb_user', + `name` varchar(256) NOT NULL DEFAULT '' COMMENT 'user name from idp', + `email` varchar(256) NOT NULL DEFAULT '' COMMENT 'user email from idp', + `deletable` bool NOT NULL DEFAULT false COMMENT 'whether this link can be deleted', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'time of first creating', + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'time of last updating', + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `uni_idx_idp_sub` (`idp_id`, `sub`, `deleted_ts`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +CREATE TABLE `tb_event` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `req_id` varchar(256) NOT NULL DEFAULT '', + `resource_type` varchar(256) NOT NULL DEFAULT '', + `resource_id` varchar(256) NOT NULL DEFAULT '', + `event_type` varchar(256) NOT NULL DEFAULT '', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0', + `extra` varchar(255) NOT NULL DEFAULT '' COMMENT 'extra infos to describe the event', + PRIMARY KEY (`id`), + KEY `idx_req_id` (`req_id`), + KEY `idx_resource_action` (`resource_id`, `resource_type`, `event_type`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +CREATE TABLE `tb_event_cursor` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `position` bigint(20) NOT NULL DEFAULT '0', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `idx_value` (`position`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +CREATE TABLE `tb_webhook` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `enabled` tinyint(1) NOT NULL DEFAULT '1', + `url` text NOT NULL, + `ssl_verify_enabled` tinyint(1) NOT NULL DEFAULT '0', + `description` varchar(256) NOT NULL DEFAULT '', + `secret` text NOT NULL, + `triggers` text NOT NULL, + `resource_type` varchar(256) NOT NULL DEFAULT '', + `resource_id` bigint(20) NOT NULL DEFAULT '0', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +CREATE TABLE `tb_webhook_log` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `webhook_id` bigint(20) unsigned NOT NULL, + `event_id` bigint(20) unsigned NOT NULL, + `url` text NOT NULL, + `request_headers` text NOT NULL, + `request_data` text NOT NULL, + `response_headers` text NOT NULL, + `response_body` text NOT NULL, + `status` varchar(256) NOT NULL, + `error_message` text NOT NULL, + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0', + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_webhook_id_status` (`webhook_id`, `status`), + KEY `idx_event_id` (`event_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- metatag table +CREATE TABLE `tb_metatag` +( + `tag_key` varchar(64) NOT NULL DEFAULT '' comment 'key of the metatag', + `tag_value` varchar(128) NOT NULL DEFAULT '' comment 'value of the metatag', + `description` varchar(64) NOT NULL DEFAULT '' comment 'description', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY `idx_key_value` (`tag_key`, `tag_value`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; diff --git a/db/migrations/20230817_add_check.sql b/db/migrations/20230817_add_check.sql new file mode 100644 index 000000000..ecad1a9f1 --- /dev/null +++ b/db/migrations/20230817_add_check.sql @@ -0,0 +1,53 @@ +-- check table +CREATE TABLE `tb_check` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `resource_type` varchar(64) NOT NULL DEFAULT '' COMMENT 'resource type', + `resource_id` bigint(20) unsigned NOT NULL COMMENT 'resource id', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_resource_deleted` (`resource_type`, `resource_id`, `deleted_ts`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- check run table +CREATE TABLE `tb_checkrun` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(256) NOT NULL DEFAULT '' COMMENT 'the name of check run', + `status` varchar(64) NOT NULL DEFAULT '' COMMENT 'the status of check run', + `pipeline_run_id` bigint(20) unsigned NOT NULL COMMENT 'pipeline run id', + `check_id` bigint(20) unsigned NOT NULL COMMENT 'check id', + `message` varchar(256) NOT NULL DEFAULT '', + `detail_url` varchar(256) NOT NULL DEFAULT '' COMMENT 'the detail url of check run', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_pipeline_run_id_check_id_deleted` (`pipeline_run_id`, `check_id`, `deleted_ts`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; + +-- pr_msg table +CREATE TABLE `tb_pr_msg` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `pipeline_run_id` bigint(20) unsigned NOT NULL COMMENT 'pipeline run id', + `content` text NOT NULL DEFAULT '' COMMENT 'content of message', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', + `updated_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'updater', + `deleted_ts` bigint(20) DEFAULT '0' COMMENT 'deleted timestamp, 0 means not deleted', + PRIMARY KEY (`id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4; diff --git a/mock/pkg/cluster/tekton/collector/collector_mock.go b/mock/pkg/cluster/tekton/collector/collector_mock.go index 4e1ac643f..4f024aee2 100644 --- a/mock/pkg/cluster/tekton/collector/collector_mock.go +++ b/mock/pkg/cluster/tekton/collector/collector_mock.go @@ -10,7 +10,7 @@ import ( gomock "github.com/golang/mock/gomock" collector "github.com/horizoncd/horizon/pkg/cluster/tekton/collector" - models "github.com/horizoncd/horizon/pkg/pipelinerun/models" + models "github.com/horizoncd/horizon/pkg/pr/models" global "github.com/horizoncd/horizon/pkg/server/global" v1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" ) diff --git a/mock/pkg/pipelinerun/manager/mock_manager.go b/mock/pkg/pipelinerun/manager/mock_manager.go index 50d53bc88..46cff48fd 100644 --- a/mock/pkg/pipelinerun/manager/mock_manager.go +++ b/mock/pkg/pipelinerun/manager/mock_manager.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: manager.go +// Source: pipelinerun.go // Package mock_manager is a generated GoMock package. package mock_manager @@ -10,34 +10,34 @@ import ( gomock "github.com/golang/mock/gomock" q "github.com/horizoncd/horizon/lib/q" - models "github.com/horizoncd/horizon/pkg/pipelinerun/models" + models "github.com/horizoncd/horizon/pkg/pr/models" ) -// MockManager is a mock of Manager interface. -type MockManager struct { +// MockPipelineRunManager is a mock of PipelineRunManager interface. +type MockPipelineRunManager struct { ctrl *gomock.Controller - recorder *MockManagerMockRecorder + recorder *MockPipelineRunManagerMockRecorder } -// MockManagerMockRecorder is the mock recorder for MockManager. -type MockManagerMockRecorder struct { - mock *MockManager +// MockPipelineRunManagerMockRecorder is the mock recorder for MockPipelineRunManager. +type MockPipelineRunManagerMockRecorder struct { + mock *MockPipelineRunManager } -// NewMockManager creates a new mock instance. -func NewMockManager(ctrl *gomock.Controller) *MockManager { - mock := &MockManager{ctrl: ctrl} - mock.recorder = &MockManagerMockRecorder{mock} +// NewMockPipelineRunManager creates a new mock instance. +func NewMockPipelineRunManager(ctrl *gomock.Controller) *MockPipelineRunManager { + mock := &MockPipelineRunManager{ctrl: ctrl} + mock.recorder = &MockPipelineRunManagerMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockManager) EXPECT() *MockManagerMockRecorder { +func (m *MockPipelineRunManager) EXPECT() *MockPipelineRunManagerMockRecorder { return m.recorder } // Create mocks base method. -func (m *MockManager) Create(ctx context.Context, pipelinerun *models.Pipelinerun) (*models.Pipelinerun, error) { +func (m *MockPipelineRunManager) Create(ctx context.Context, pipelinerun *models.Pipelinerun) (*models.Pipelinerun, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Create", ctx, pipelinerun) ret0, _ := ret[0].(*models.Pipelinerun) @@ -46,13 +46,13 @@ func (m *MockManager) Create(ctx context.Context, pipelinerun *models.Pipelineru } // Create indicates an expected call of Create. -func (mr *MockManagerMockRecorder) Create(ctx, pipelinerun interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) Create(ctx, pipelinerun interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockManager)(nil).Create), ctx, pipelinerun) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockPipelineRunManager)(nil).Create), ctx, pipelinerun) } // DeleteByClusterID mocks base method. -func (m *MockManager) DeleteByClusterID(ctx context.Context, clusterID uint) error { +func (m *MockPipelineRunManager) DeleteByClusterID(ctx context.Context, clusterID uint) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DeleteByClusterID", ctx, clusterID) ret0, _ := ret[0].(error) @@ -60,13 +60,13 @@ func (m *MockManager) DeleteByClusterID(ctx context.Context, clusterID uint) err } // DeleteByClusterID indicates an expected call of DeleteByClusterID. -func (mr *MockManagerMockRecorder) DeleteByClusterID(ctx, clusterID interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) DeleteByClusterID(ctx, clusterID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteByClusterID", reflect.TypeOf((*MockManager)(nil).DeleteByClusterID), ctx, clusterID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteByClusterID", reflect.TypeOf((*MockPipelineRunManager)(nil).DeleteByClusterID), ctx, clusterID) } // DeleteByID mocks base method. -func (m *MockManager) DeleteByID(ctx context.Context, pipelinerunID uint) error { +func (m *MockPipelineRunManager) DeleteByID(ctx context.Context, pipelinerunID uint) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DeleteByID", ctx, pipelinerunID) ret0, _ := ret[0].(error) @@ -74,13 +74,13 @@ func (m *MockManager) DeleteByID(ctx context.Context, pipelinerunID uint) error } // DeleteByID indicates an expected call of DeleteByID. -func (mr *MockManagerMockRecorder) DeleteByID(ctx, pipelinerunID interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) DeleteByID(ctx, pipelinerunID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteByID", reflect.TypeOf((*MockManager)(nil).DeleteByID), ctx, pipelinerunID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteByID", reflect.TypeOf((*MockPipelineRunManager)(nil).DeleteByID), ctx, pipelinerunID) } // GetByCIEventID mocks base method. -func (m *MockManager) GetByCIEventID(ctx context.Context, ciEventID string) (*models.Pipelinerun, error) { +func (m *MockPipelineRunManager) GetByCIEventID(ctx context.Context, ciEventID string) (*models.Pipelinerun, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetByCIEventID", ctx, ciEventID) ret0, _ := ret[0].(*models.Pipelinerun) @@ -89,13 +89,13 @@ func (m *MockManager) GetByCIEventID(ctx context.Context, ciEventID string) (*mo } // GetByCIEventID indicates an expected call of GetByCIEventID. -func (mr *MockManagerMockRecorder) GetByCIEventID(ctx, ciEventID interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) GetByCIEventID(ctx, ciEventID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByCIEventID", reflect.TypeOf((*MockManager)(nil).GetByCIEventID), ctx, ciEventID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByCIEventID", reflect.TypeOf((*MockPipelineRunManager)(nil).GetByCIEventID), ctx, ciEventID) } // GetByClusterID mocks base method. -func (m *MockManager) GetByClusterID(ctx context.Context, clusterID uint, canRollback bool, query q.Query) (int, []*models.Pipelinerun, error) { +func (m *MockPipelineRunManager) GetByClusterID(ctx context.Context, clusterID uint, canRollback bool, query q.Query) (int, []*models.Pipelinerun, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetByClusterID", ctx, clusterID, canRollback, query) ret0, _ := ret[0].(int) @@ -105,13 +105,13 @@ func (m *MockManager) GetByClusterID(ctx context.Context, clusterID uint, canRol } // GetByClusterID indicates an expected call of GetByClusterID. -func (mr *MockManagerMockRecorder) GetByClusterID(ctx, clusterID, canRollback, query interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) GetByClusterID(ctx, clusterID, canRollback, query interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByClusterID", reflect.TypeOf((*MockManager)(nil).GetByClusterID), ctx, clusterID, canRollback, query) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByClusterID", reflect.TypeOf((*MockPipelineRunManager)(nil).GetByClusterID), ctx, clusterID, canRollback, query) } // GetByID mocks base method. -func (m *MockManager) GetByID(ctx context.Context, pipelinerunID uint) (*models.Pipelinerun, error) { +func (m *MockPipelineRunManager) GetByID(ctx context.Context, pipelinerunID uint) (*models.Pipelinerun, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetByID", ctx, pipelinerunID) ret0, _ := ret[0].(*models.Pipelinerun) @@ -120,13 +120,13 @@ func (m *MockManager) GetByID(ctx context.Context, pipelinerunID uint) (*models. } // GetByID indicates an expected call of GetByID. -func (mr *MockManagerMockRecorder) GetByID(ctx, pipelinerunID interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) GetByID(ctx, pipelinerunID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByID", reflect.TypeOf((*MockManager)(nil).GetByID), ctx, pipelinerunID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByID", reflect.TypeOf((*MockPipelineRunManager)(nil).GetByID), ctx, pipelinerunID) } // GetFirstCanRollbackPipelinerun mocks base method. -func (m *MockManager) GetFirstCanRollbackPipelinerun(ctx context.Context, clusterID uint) (*models.Pipelinerun, error) { +func (m *MockPipelineRunManager) GetFirstCanRollbackPipelinerun(ctx context.Context, clusterID uint) (*models.Pipelinerun, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetFirstCanRollbackPipelinerun", ctx, clusterID) ret0, _ := ret[0].(*models.Pipelinerun) @@ -135,13 +135,13 @@ func (m *MockManager) GetFirstCanRollbackPipelinerun(ctx context.Context, cluste } // GetFirstCanRollbackPipelinerun indicates an expected call of GetFirstCanRollbackPipelinerun. -func (mr *MockManagerMockRecorder) GetFirstCanRollbackPipelinerun(ctx, clusterID interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) GetFirstCanRollbackPipelinerun(ctx, clusterID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFirstCanRollbackPipelinerun", reflect.TypeOf((*MockManager)(nil).GetFirstCanRollbackPipelinerun), ctx, clusterID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFirstCanRollbackPipelinerun", reflect.TypeOf((*MockPipelineRunManager)(nil).GetFirstCanRollbackPipelinerun), ctx, clusterID) } // GetLatestByClusterIDAndActionAndStatus mocks base method. -func (m *MockManager) GetLatestByClusterIDAndActionAndStatus(ctx context.Context, clusterID uint, action, status string) (*models.Pipelinerun, error) { +func (m *MockPipelineRunManager) GetLatestByClusterIDAndActionAndStatus(ctx context.Context, clusterID uint, action, status string) (*models.Pipelinerun, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetLatestByClusterIDAndActionAndStatus", ctx, clusterID, action, status) ret0, _ := ret[0].(*models.Pipelinerun) @@ -150,13 +150,13 @@ func (m *MockManager) GetLatestByClusterIDAndActionAndStatus(ctx context.Context } // GetLatestByClusterIDAndActionAndStatus indicates an expected call of GetLatestByClusterIDAndActionAndStatus. -func (mr *MockManagerMockRecorder) GetLatestByClusterIDAndActionAndStatus(ctx, clusterID, action, status interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) GetLatestByClusterIDAndActionAndStatus(ctx, clusterID, action, status interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestByClusterIDAndActionAndStatus", reflect.TypeOf((*MockManager)(nil).GetLatestByClusterIDAndActionAndStatus), ctx, clusterID, action, status) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestByClusterIDAndActionAndStatus", reflect.TypeOf((*MockPipelineRunManager)(nil).GetLatestByClusterIDAndActionAndStatus), ctx, clusterID, action, status) } // GetLatestByClusterIDAndActions mocks base method. -func (m *MockManager) GetLatestByClusterIDAndActions(ctx context.Context, clusterID uint, actions ...string) (*models.Pipelinerun, error) { +func (m *MockPipelineRunManager) GetLatestByClusterIDAndActions(ctx context.Context, clusterID uint, actions ...string) (*models.Pipelinerun, error) { m.ctrl.T.Helper() varargs := []interface{}{ctx, clusterID} for _, a := range actions { @@ -169,14 +169,14 @@ func (m *MockManager) GetLatestByClusterIDAndActions(ctx context.Context, cluste } // GetLatestByClusterIDAndActions indicates an expected call of GetLatestByClusterIDAndActions. -func (mr *MockManagerMockRecorder) GetLatestByClusterIDAndActions(ctx, clusterID interface{}, actions ...interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) GetLatestByClusterIDAndActions(ctx, clusterID interface{}, actions ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{ctx, clusterID}, actions...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestByClusterIDAndActions", reflect.TypeOf((*MockManager)(nil).GetLatestByClusterIDAndActions), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestByClusterIDAndActions", reflect.TypeOf((*MockPipelineRunManager)(nil).GetLatestByClusterIDAndActions), varargs...) } // GetLatestSuccessByClusterID mocks base method. -func (m *MockManager) GetLatestSuccessByClusterID(ctx context.Context, clusterID uint) (*models.Pipelinerun, error) { +func (m *MockPipelineRunManager) GetLatestSuccessByClusterID(ctx context.Context, clusterID uint) (*models.Pipelinerun, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetLatestSuccessByClusterID", ctx, clusterID) ret0, _ := ret[0].(*models.Pipelinerun) @@ -185,13 +185,13 @@ func (m *MockManager) GetLatestSuccessByClusterID(ctx context.Context, clusterID } // GetLatestSuccessByClusterID indicates an expected call of GetLatestSuccessByClusterID. -func (mr *MockManagerMockRecorder) GetLatestSuccessByClusterID(ctx, clusterID interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) GetLatestSuccessByClusterID(ctx, clusterID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestSuccessByClusterID", reflect.TypeOf((*MockManager)(nil).GetLatestSuccessByClusterID), ctx, clusterID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestSuccessByClusterID", reflect.TypeOf((*MockPipelineRunManager)(nil).GetLatestSuccessByClusterID), ctx, clusterID) } // UpdateCIEventIDByID mocks base method. -func (m *MockManager) UpdateCIEventIDByID(ctx context.Context, pipelinerunID uint, ciEventID string) error { +func (m *MockPipelineRunManager) UpdateCIEventIDByID(ctx context.Context, pipelinerunID uint, ciEventID string) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateCIEventIDByID", ctx, pipelinerunID, ciEventID) ret0, _ := ret[0].(error) @@ -199,13 +199,27 @@ func (m *MockManager) UpdateCIEventIDByID(ctx context.Context, pipelinerunID uin } // UpdateCIEventIDByID indicates an expected call of UpdateCIEventIDByID. -func (mr *MockManagerMockRecorder) UpdateCIEventIDByID(ctx, pipelinerunID, ciEventID interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) UpdateCIEventIDByID(ctx, pipelinerunID, ciEventID interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateCIEventIDByID", reflect.TypeOf((*MockManager)(nil).UpdateCIEventIDByID), ctx, pipelinerunID, ciEventID) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateCIEventIDByID", reflect.TypeOf((*MockPipelineRunManager)(nil).UpdateCIEventIDByID), ctx, pipelinerunID, ciEventID) +} + +// UpdateColumns mocks base method. +func (m *MockPipelineRunManager) UpdateColumns(ctx context.Context, pipelinerunID uint, columns map[string]interface{}) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateColumns", ctx, pipelinerunID, columns) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateColumns indicates an expected call of UpdateColumns. +func (mr *MockPipelineRunManagerMockRecorder) UpdateColumns(ctx, pipelinerunID, columns interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateColumns", reflect.TypeOf((*MockPipelineRunManager)(nil).UpdateColumns), ctx, pipelinerunID, columns) } // UpdateConfigCommitByID mocks base method. -func (m *MockManager) UpdateConfigCommitByID(ctx context.Context, pipelinerunID uint, commit string) error { +func (m *MockPipelineRunManager) UpdateConfigCommitByID(ctx context.Context, pipelinerunID uint, commit string) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateConfigCommitByID", ctx, pipelinerunID, commit) ret0, _ := ret[0].(error) @@ -213,13 +227,13 @@ func (m *MockManager) UpdateConfigCommitByID(ctx context.Context, pipelinerunID } // UpdateConfigCommitByID indicates an expected call of UpdateConfigCommitByID. -func (mr *MockManagerMockRecorder) UpdateConfigCommitByID(ctx, pipelinerunID, commit interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) UpdateConfigCommitByID(ctx, pipelinerunID, commit interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateConfigCommitByID", reflect.TypeOf((*MockManager)(nil).UpdateConfigCommitByID), ctx, pipelinerunID, commit) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateConfigCommitByID", reflect.TypeOf((*MockPipelineRunManager)(nil).UpdateConfigCommitByID), ctx, pipelinerunID, commit) } // UpdateResultByID mocks base method. -func (m *MockManager) UpdateResultByID(ctx context.Context, pipelinerunID uint, result *models.Result) error { +func (m *MockPipelineRunManager) UpdateResultByID(ctx context.Context, pipelinerunID uint, result *models.Result) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateResultByID", ctx, pipelinerunID, result) ret0, _ := ret[0].(error) @@ -227,13 +241,13 @@ func (m *MockManager) UpdateResultByID(ctx context.Context, pipelinerunID uint, } // UpdateResultByID indicates an expected call of UpdateResultByID. -func (mr *MockManagerMockRecorder) UpdateResultByID(ctx, pipelinerunID, result interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) UpdateResultByID(ctx, pipelinerunID, result interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateResultByID", reflect.TypeOf((*MockManager)(nil).UpdateResultByID), ctx, pipelinerunID, result) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateResultByID", reflect.TypeOf((*MockPipelineRunManager)(nil).UpdateResultByID), ctx, pipelinerunID, result) } // UpdateStatusByID mocks base method. -func (m *MockManager) UpdateStatusByID(ctx context.Context, pipelinerunID uint, result models.PipelineStatus) error { +func (m *MockPipelineRunManager) UpdateStatusByID(ctx context.Context, pipelinerunID uint, result models.PipelineStatus) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateStatusByID", ctx, pipelinerunID, result) ret0, _ := ret[0].(error) @@ -241,7 +255,7 @@ func (m *MockManager) UpdateStatusByID(ctx context.Context, pipelinerunID uint, } // UpdateStatusByID indicates an expected call of UpdateStatusByID. -func (mr *MockManagerMockRecorder) UpdateStatusByID(ctx, pipelinerunID, result interface{}) *gomock.Call { +func (mr *MockPipelineRunManagerMockRecorder) UpdateStatusByID(ctx, pipelinerunID, result interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStatusByID", reflect.TypeOf((*MockManager)(nil).UpdateStatusByID), ctx, pipelinerunID, result) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStatusByID", reflect.TypeOf((*MockPipelineRunManager)(nil).UpdateStatusByID), ctx, pipelinerunID, result) } diff --git a/pkg/cluster/manager/manager_test.go b/pkg/cluster/manager/manager_test.go index b1590bca3..571ce3bca 100644 --- a/pkg/cluster/manager/manager_test.go +++ b/pkg/cluster/manager/manager_test.go @@ -30,7 +30,7 @@ import ( envregionmodels "github.com/horizoncd/horizon/pkg/environmentregion/models" membermanager "github.com/horizoncd/horizon/pkg/member" membermodels "github.com/horizoncd/horizon/pkg/member/models" - pipelinemodel "github.com/horizoncd/horizon/pkg/pipelinerun/models" + pipelinemodel "github.com/horizoncd/horizon/pkg/pr/models" "github.com/horizoncd/horizon/pkg/rbac/role" regionmanager "github.com/horizoncd/horizon/pkg/region/manager" regionmodels "github.com/horizoncd/horizon/pkg/region/models" diff --git a/pkg/cluster/metrics/tekton/resolver.go b/pkg/cluster/metrics/tekton/resolver.go index f017974dc..b9e80e508 100644 --- a/pkg/cluster/metrics/tekton/resolver.go +++ b/pkg/cluster/metrics/tekton/resolver.go @@ -21,7 +21,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" ) type WrappedPipelineRun struct { diff --git a/pkg/cluster/metrics/tekton/resolver_test.go b/pkg/cluster/metrics/tekton/resolver_test.go index 668873254..0e629e07a 100644 --- a/pkg/cluster/metrics/tekton/resolver_test.go +++ b/pkg/cluster/metrics/tekton/resolver_test.go @@ -25,7 +25,7 @@ import ( "knative.dev/pkg/apis" duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" ) const _layout = "2006-01-02T15:04:05Z" diff --git a/pkg/cluster/tekton/collector/collector.go b/pkg/cluster/tekton/collector/collector.go index f69d4c9d3..de88c3b12 100644 --- a/pkg/cluster/tekton/collector/collector.go +++ b/pkg/cluster/tekton/collector/collector.go @@ -23,7 +23,7 @@ import ( "github.com/horizoncd/horizon/pkg/cluster/metrics/tekton" "github.com/horizoncd/horizon/pkg/cluster/tekton/log" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" "github.com/horizoncd/horizon/pkg/server/global" timeutil "github.com/horizoncd/horizon/pkg/util/time" diff --git a/pkg/cluster/tekton/collector/collector_dummy.go b/pkg/cluster/tekton/collector/collector_dummy.go index 62336fcf0..3fcd270f6 100644 --- a/pkg/cluster/tekton/collector/collector_dummy.go +++ b/pkg/cluster/tekton/collector/collector_dummy.go @@ -17,14 +17,15 @@ package collector import ( "context" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + herrors "github.com/horizoncd/horizon/core/errors" "github.com/horizoncd/horizon/pkg/cluster/tekton" perror "github.com/horizoncd/horizon/pkg/errors" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" "github.com/horizoncd/horizon/pkg/server/global" logutil "github.com/horizoncd/horizon/pkg/util/log" "github.com/horizoncd/horizon/pkg/util/wlog" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" ) type DummyCollector struct { diff --git a/pkg/cluster/tekton/collector/collector_dummy_test.go b/pkg/cluster/tekton/collector/collector_dummy_test.go index 464d7a1a4..8daf91806 100644 --- a/pkg/cluster/tekton/collector/collector_dummy_test.go +++ b/pkg/cluster/tekton/collector/collector_dummy_test.go @@ -20,11 +20,12 @@ import ( "testing" "github.com/golang/mock/gomock" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" - "github.com/horizoncd/horizon/pkg/server/global" "github.com/stretchr/testify/assert" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" + "github.com/horizoncd/horizon/pkg/server/global" + tektonmock "github.com/horizoncd/horizon/mock/pkg/cluster/tekton" ) diff --git a/pkg/cluster/tekton/collector/collector_s3.go b/pkg/cluster/tekton/collector/collector_s3.go index 50dfa29d4..ebce74d45 100644 --- a/pkg/cluster/tekton/collector/collector_s3.go +++ b/pkg/cluster/tekton/collector/collector_s3.go @@ -29,7 +29,7 @@ import ( herrors "github.com/horizoncd/horizon/core/errors" perror "github.com/horizoncd/horizon/pkg/errors" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" "github.com/horizoncd/horizon/pkg/server/global" "github.com/aws/aws-sdk-go/aws/awserr" diff --git a/pkg/cluster/tekton/collector/collector_s3_test.go b/pkg/cluster/tekton/collector/collector_s3_test.go index c4577ab0b..eaa5f3440 100644 --- a/pkg/cluster/tekton/collector/collector_s3_test.go +++ b/pkg/cluster/tekton/collector/collector_s3_test.go @@ -24,13 +24,14 @@ import ( "time" "github.com/golang/mock/gomock" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" - "github.com/horizoncd/horizon/pkg/server/global" "github.com/johannesboyne/gofakes3" "github.com/johannesboyne/gofakes3/backend/s3mem" "github.com/stretchr/testify/assert" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" + "github.com/horizoncd/horizon/pkg/server/global" + "github.com/horizoncd/horizon/lib/s3" tektonmock "github.com/horizoncd/horizon/mock/pkg/cluster/tekton" "github.com/horizoncd/horizon/pkg/cluster/tekton/log" diff --git a/pkg/common/db_scripts.go b/pkg/common/db_scripts.go index 64ab9bd7e..a4925b89e 100644 --- a/pkg/common/db_scripts.go +++ b/pkg/common/db_scripts.go @@ -215,9 +215,7 @@ const ( PipelinerunGetLatestSuccessByClusterID = "select * from tb_pipelinerun where cluster_id = ? and status = 'ok' and " + "git_commit != '' order by updated_at desc limit 1" - PipelinerunUpdateStatusByID = "update tb_pipelinerun set status = ? where id = ?" - PipelinerunUpdateCIEventIDByID = "update tb_pipelinerun set ci_event_id = ? where id = ?" - PipelinerunUpdateResultByID = "update tb_pipelinerun set status = ?, s3_bucket = ?, log_object = ?, " + + PipelinerunUpdateResultByID = "update tb_pipelinerun set status = ?, s3_bucket = ?, log_object = ?, " + "pr_object = ?, started_at = ?, finished_at = ? where id = ?" PipelinerunGetByClusterID = "select * from tb_pipelinerun where cluster_id = ?" + diff --git a/pkg/group/manager/manager.go b/pkg/group/manager/manager.go index 1c244b05c..4439b109d 100644 --- a/pkg/group/manager/manager.go +++ b/pkg/group/manager/manager.go @@ -17,9 +17,12 @@ package manager import ( "context" "fmt" - "strconv" "strings" + "gopkg.in/yaml.v3" + "gorm.io/gorm" + + "github.com/horizoncd/horizon/core/common" herrors "github.com/horizoncd/horizon/core/errors" "github.com/horizoncd/horizon/lib/q" applicationdao "github.com/horizoncd/horizon/pkg/application/dao" @@ -30,8 +33,6 @@ import ( groupmodels "github.com/horizoncd/horizon/pkg/group/models" regiondao "github.com/horizoncd/horizon/pkg/region/dao" regionmodels "github.com/horizoncd/horizon/pkg/region/models" - "gopkg.in/yaml.v3" - "gorm.io/gorm" ) const ( @@ -251,12 +252,7 @@ func formatListGroupQuery(id uint, pageNumber, pageSize int) *q.Query { // FormatIDsFromTraversalIDs format id array from traversalIDs(1,2,3) func FormatIDsFromTraversalIDs(traversalIDs string) []uint { - splitIds := strings.Split(traversalIDs, ",") - var ids = make([]uint, len(splitIds)) - for i, id := range splitIds { - ii, _ := strconv.Atoi(id) - ids[i] = uint(ii) - } + ids, _ := common.UnmarshalTraversalIDS(traversalIDs) return ids } diff --git a/pkg/jobs/autofree/autofree.go b/pkg/jobs/autofree/autofree.go index 252867fa2..3adf6e05b 100644 --- a/pkg/jobs/autofree/autofree.go +++ b/pkg/jobs/autofree/autofree.go @@ -18,6 +18,8 @@ import ( "context" "time" + uuid "github.com/satori/go.uuid" + "github.com/horizoncd/horizon/core/common" clusterctl "github.com/horizoncd/horizon/core/controller/cluster" prctl "github.com/horizoncd/horizon/core/controller/pipelinerun" @@ -27,7 +29,6 @@ import ( "github.com/horizoncd/horizon/pkg/config/autofree" usermanager "github.com/horizoncd/horizon/pkg/user/manager" "github.com/horizoncd/horizon/pkg/util/log" - uuid "github.com/satori/go.uuid" ) func Run(ctx context.Context, jobConfig *autofree.Config, userMgr usermanager.Manager, @@ -86,7 +87,7 @@ func process(ctx context.Context, jobConfig *autofree.Config, clusterCtr cluster // 2. Only need to free when the cluster has pipelineruns // and expired and its environment supports auto-free isNeedFree, err := func() (bool, error) { - prTotal, pipelineruns, err := prCtr.List(ctx, clr.ID, false, q.Query{ + prTotal, pipelineruns, err := prCtr.ListPipelineruns(ctx, clr.ID, false, q.Query{ PageNumber: 1, PageSize: 1, }) diff --git a/pkg/jobs/autofree/autofree_test.go b/pkg/jobs/autofree/autofree_test.go index e8e5c8b42..e347a41b5 100644 --- a/pkg/jobs/autofree/autofree_test.go +++ b/pkg/jobs/autofree/autofree_test.go @@ -48,8 +48,9 @@ import ( membermodels "github.com/horizoncd/horizon/pkg/member/models" "github.com/horizoncd/horizon/pkg/param" "github.com/horizoncd/horizon/pkg/param/managerparam" - pipelinemodel "github.com/horizoncd/horizon/pkg/pipelinerun/models" - prmodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmanager "github.com/horizoncd/horizon/pkg/pr/manager" + pipelinemodel "github.com/horizoncd/horizon/pkg/pr/models" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" regionmodels "github.com/horizoncd/horizon/pkg/region/models" registrymodels "github.com/horizoncd/horizon/pkg/registry/models" "github.com/horizoncd/horizon/pkg/server/global" @@ -129,10 +130,12 @@ func TestAutoFreeExpiredCluster(t *testing.T) { Manager: manager, CD: cd, } - mockPipelineManager := pipelinemockmanager.NewMockManager(mockCtl) - parameter.PipelinerunMgr = mockPipelineManager + mockPipelineManager := pipelinemockmanager.NewMockPipelineRunManager(mockCtl) + parameter.PRMgr = &prmanager.PRManager{ + PipelineRun: mockPipelineManager, + } clrCtl := clusterctl.NewController(conf, parameter) - prCtl := prctl.NewController(parameter) + prCtl := prctl.NewController(conf, parameter) // init data @@ -189,7 +192,7 @@ func TestAutoFreeExpiredCluster(t *testing.T) { Return(0, pipelineruns, nil).AnyTimes() } mockPipelineManager.EXPECT().GetFirstCanRollbackPipelinerun(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes() - num, pipelineBasics, err := prCtl.List(ctx, cluster.ID, false, q.Query{ + num, pipelineBasics, err := prCtl.ListPipelineruns(ctx, cluster.ID, false, q.Query{ PageNumber: 1, PageSize: 10, }) diff --git a/pkg/member/service/service.go b/pkg/member/service/service.go index e98fd160a..210808ee0 100644 --- a/pkg/member/service/service.go +++ b/pkg/member/service/service.go @@ -32,7 +32,7 @@ import ( "github.com/horizoncd/horizon/pkg/member/models" oauthmanager "github.com/horizoncd/horizon/pkg/oauth/manager" "github.com/horizoncd/horizon/pkg/param/managerparam" - pipelinerunmanager "github.com/horizoncd/horizon/pkg/pipelinerun/manager" + prmanager "github.com/horizoncd/horizon/pkg/pr/manager" roleservice "github.com/horizoncd/horizon/pkg/rbac/role" templatemanager "github.com/horizoncd/horizon/pkg/template/manager" templatereleasemanager "github.com/horizoncd/horizon/pkg/templaterelease/manager" @@ -69,7 +69,7 @@ type service struct { applicationClusterManager clustermanager.Manager templateManager templatemanager.Manager templateReleaseManager templatereleasemanager.Manager - pipelineManager pipelinerunmanager.Manager + prMgr *prmanager.PRManager roleService roleservice.Service oauthManager oauthmanager.Manager userManager usermanager.Manager @@ -83,7 +83,7 @@ func NewService(roleService roleservice.Service, oauthManager oauthmanager.Manag groupManager: manager.GroupMgr, applicationManager: manager.ApplicationMgr, applicationClusterManager: manager.ClusterMgr, - pipelineManager: manager.PipelinerunMgr, + prMgr: manager.PRMgr, templateReleaseManager: manager.TemplateReleaseMgr, templateManager: manager.TemplateMgr, roleService: roleService, @@ -175,7 +175,7 @@ func (s *service) getPipelinerunMember(ctx context.Context, pipelinerunID uint) if err != nil { return nil, err } - pipeline, err := s.pipelineManager.GetByID(ctx, pipelinerunID) + pipeline, err := s.prMgr.PipelineRun.GetByID(ctx, pipelinerunID) if err != nil { return nil, err } @@ -189,7 +189,7 @@ func (s *service) getPipelinerunMember(ctx context.Context, pipelinerunID uint) } func (s *service) listPipelinerunMember(ctx context.Context, pipelinerunID uint) ([]models.Member, error) { - pipeline, err := s.pipelineManager.GetByID(ctx, pipelinerunID) + pipeline, err := s.prMgr.PipelineRun.GetByID(ctx, pipelinerunID) if err != nil { return nil, err } diff --git a/pkg/member/service/service_test.go b/pkg/member/service/service_test.go index 75137354f..7e239acab 100644 --- a/pkg/member/service/service_test.go +++ b/pkg/member/service/service_test.go @@ -40,7 +40,8 @@ import ( groupModels "github.com/horizoncd/horizon/pkg/group/models" "github.com/horizoncd/horizon/pkg/member/models" "github.com/horizoncd/horizon/pkg/param/managerparam" - pipelinemodels "github.com/horizoncd/horizon/pkg/pipelinerun/models" + prmanager "github.com/horizoncd/horizon/pkg/pr/manager" + pipelinemodels "github.com/horizoncd/horizon/pkg/pr/models" roleservice "github.com/horizoncd/horizon/pkg/rbac/role" "github.com/horizoncd/horizon/pkg/server/global" templatemodels "github.com/horizoncd/horizon/pkg/template/models" @@ -725,7 +726,7 @@ func TestGetPipelinerunMember(t *testing.T) { }, nil }).AnyTimes() - pipelineMockManager := pipelinemock.NewMockManager(mockCtrl) + pipelineMockManager := pipelinemock.NewMockPipelineRunManager(mockCtrl) pipelineMockManager.EXPECT().GetByID(gomock.Any(), pipelineRunID).Return(&pipelinemodels.Pipelinerun{ ID: 0, ClusterID: cluster4ID, @@ -737,9 +738,11 @@ func TestGetPipelinerunMember(t *testing.T) { groupManager: groupManager, applicationManager: applicationManager, applicationClusterManager: clusterManager, - pipelineManager: pipelineMockManager, - roleService: roleSvc, - userManager: manager.UserMgr, + prMgr: &prmanager.PRManager{ + PipelineRun: pipelineMockManager, + }, + roleService: roleSvc, + userManager: manager.UserMgr, } s = originService @@ -822,7 +825,7 @@ func TestListTemplateMember(t *testing.T) { applicationManager: manager.ApplicationMgr, applicationClusterManager: manager.ClusterMgr, templateManager: manager.TemplateMgr, - pipelineManager: manager.PipelinerunMgr, + prMgr: manager.PRMgr, roleService: nil, } @@ -904,7 +907,7 @@ func TestListWebhookMember(t *testing.T) { applicationManager: manager.ApplicationMgr, applicationClusterManager: manager.ClusterMgr, templateManager: manager.TemplateMgr, - pipelineManager: manager.PipelinerunMgr, + prMgr: manager.PRMgr, roleService: nil, webhookManager: manager.WebhookMgr, } diff --git a/pkg/param/managerparam/managerparam.go b/pkg/param/managerparam/managerparam.go index 5dcbb7104..6d80ddf32 100644 --- a/pkg/param/managerparam/managerparam.go +++ b/pkg/param/managerparam/managerparam.go @@ -29,8 +29,8 @@ import ( groupmanager "github.com/horizoncd/horizon/pkg/group/manager" idpmanager "github.com/horizoncd/horizon/pkg/idp/manager" membermanager "github.com/horizoncd/horizon/pkg/member" - prmanager "github.com/horizoncd/horizon/pkg/pipelinerun/manager" - pipelinemanager "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/manager" + prmanager "github.com/horizoncd/horizon/pkg/pr/manager" + pipelinemanager "github.com/horizoncd/horizon/pkg/pr/pipeline/manager" regionmanager "github.com/horizoncd/horizon/pkg/region/manager" registrymanager "github.com/horizoncd/horizon/pkg/registry/manager" tagmanager "github.com/horizoncd/horizon/pkg/tag/manager" @@ -60,7 +60,7 @@ type Manager struct { TemplateMgr templatemanager.Manager EnvRegionMgr environmentregionmanager.Manager RegionMgr regionmanager.Manager - PipelinerunMgr prmanager.Manager + PRMgr *prmanager.PRManager PipelineMgr pipelinemanager.Manager EnvMgr envmanager.Manager GroupMgr groupmanager.Manager @@ -89,7 +89,7 @@ func InitManager(db *gorm.DB) *Manager { TemplateMgr: templatemanager.New(db), EnvRegionMgr: environmentregionmanager.New(db), RegionMgr: regionmanager.New(db), - PipelinerunMgr: prmanager.New(db), + PRMgr: prmanager.NewPRManager(db), PipelineMgr: pipelinemanager.New(db), EnvMgr: envmanager.New(db), GroupMgr: groupmanager.New(db), diff --git a/pkg/param/param.go b/pkg/param/param.go index cea65ab79..2e4e48ac6 100644 --- a/pkg/param/param.go +++ b/pkg/param/param.go @@ -30,6 +30,7 @@ import ( oauthmanager "github.com/horizoncd/horizon/pkg/oauth/manager" "github.com/horizoncd/horizon/pkg/oauth/scope" "github.com/horizoncd/horizon/pkg/param/managerparam" + prservice "github.com/horizoncd/horizon/pkg/pr/service" tokenservice "github.com/horizoncd/horizon/pkg/token/service" "github.com/horizoncd/horizon/core/controller/build" @@ -53,6 +54,7 @@ type Param struct { UserSvc userservice.Service TokenSvc tokenservice.Service RoleService role.Service + PRService *prservice.Service ScopeService scope.Service GrafanaService grafana.Service diff --git a/pkg/pr/dao/check.go b/pkg/pr/dao/check.go new file mode 100644 index 000000000..1c120de22 --- /dev/null +++ b/pkg/pr/dao/check.go @@ -0,0 +1,122 @@ +package dao + +import ( + "context" + + "gorm.io/gorm" + + "github.com/horizoncd/horizon/core/common" + herrors "github.com/horizoncd/horizon/core/errors" + "github.com/horizoncd/horizon/pkg/pr/models" +) + +type CheckDAO interface { + // Create create a check + Create(ctx context.Context, check *models.Check) (*models.Check, error) + // Update check run + UpdateByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error + // GetByResource get checks by resource + GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) + ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) + CreateCheckRun(ctx context.Context, run *models.CheckRun) (*models.CheckRun, error) + ListMessage(ctx context.Context, pipelineRunID uint) ([]*models.PRMessage, error) + CreateMessage(ctx context.Context, message *models.PRMessage) (*models.PRMessage, error) +} + +type checkDAO struct{ db *gorm.DB } + +func NewCheckDAO(db *gorm.DB) CheckDAO { + return &checkDAO{db: db} +} + +func (d *checkDAO) Create(ctx context.Context, check *models.Check) (*models.Check, error) { + result := d.db.WithContext(ctx).Create(check) + + if result.Error != nil { + return nil, herrors.NewErrInsertFailed(herrors.CheckInDB, result.Error.Error()) + } + + return check, result.Error +} + +func (d *checkDAO) UpdateByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error { + result := d.db.WithContext(ctx).Model(&models.CheckRun{}).Where("id = ?", checkRunID).Updates(newCheckRun) + + if result.Error != nil { + return herrors.NewErrUpdateFailed(herrors.CheckInDB, result.Error.Error()) + } + + return result.Error +} + +func (d *checkDAO) GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) { + var checks []*models.Check + sql := d.db.WithContext(ctx) + if len(resources) == 0 { + return []*models.Check{}, nil + } + + sql = sql.Where(d.db.Where("resource_type = ?", resources[0].Type).Where("resource_id = ?", resources[0].ID)) + for _, resource := range resources[1:] { + sql = sql.Or(d.db.Where("resource_type = ?", resource.Type).Where("resource_id = ?", resource.ID)) + } + + result := sql.Find(&checks) + + if result.RowsAffected == 0 { + return []*models.Check{}, nil + } + if result.Error != nil { + return nil, herrors.NewErrGetFailed(herrors.CheckInDB, result.Error.Error()) + } + return checks, nil +} + +func (d *checkDAO) ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) { + var checkRuns []*models.CheckRun + result := d.db.Where("pipeline_run_id = ?", pipelineRunID). + Find(&checkRuns) + + if result.RowsAffected == 0 { + return []*models.CheckRun{}, nil + } + if result.Error != nil { + return nil, herrors.NewErrGetFailed(herrors.CheckRunInDB, result.Error.Error()) + } + return checkRuns, nil +} + +func (d *checkDAO) CreateCheckRun(ctx context.Context, run *models.CheckRun) (*models.CheckRun, error) { + result := d.db.WithContext(ctx).Create(run) + + if result.Error != nil { + return nil, herrors.NewErrInsertFailed(herrors.CheckRunInDB, result.Error.Error()) + } + + return run, result.Error +} + +func (d *checkDAO) ListMessage(ctx context.Context, pipelineRunID uint) ([]*models.PRMessage, error) { + var messages []*models.PRMessage + result := d.db.WithContext(ctx).Where("pipeline_run_id = ?", pipelineRunID). + Order("updated_at asc"). + Find(&messages) + + if result.RowsAffected == 0 { + return []*models.PRMessage{}, nil + } + if result.Error != nil { + return nil, herrors.NewErrGetFailed(herrors.CheckRunInDB, result.Error.Error()) + } + return messages, nil +} + +func (d *checkDAO) CreateMessage(ctx context.Context, message *models.PRMessage) (*models.PRMessage, error) { + result := d.db.WithContext(ctx).Create(message) + + if result.Error != nil { + return nil, herrors.NewErrInsertFailed(herrors.CheckRunInDB, result.Error.Error()) + } + + return message, result.Error +} diff --git a/pkg/pr/dao/message.go b/pkg/pr/dao/message.go new file mode 100644 index 000000000..bc6995905 --- /dev/null +++ b/pkg/pr/dao/message.go @@ -0,0 +1,54 @@ +package dao + +import ( + "context" + + "gorm.io/gorm" + + herrors "github.com/horizoncd/horizon/core/errors" + "github.com/horizoncd/horizon/lib/q" + "github.com/horizoncd/horizon/pkg/pr/models" +) + +type PRMessageDAO interface { + // Create create a PRMessage + Create(ctx context.Context, prMessage *models.PRMessage) (*models.PRMessage, error) + // List list PRMessage order by created_at asc + List(ctx context.Context, pipelineRunID uint, query *q.Query) (int, []*models.PRMessage, error) +} + +type prMessageDAO struct{ db *gorm.DB } + +func NewPRMessageDAO(db *gorm.DB) PRMessageDAO { + return &prMessageDAO{db: db} +} + +func (d *prMessageDAO) Create(ctx context.Context, prMessage *models.PRMessage) (*models.PRMessage, error) { + result := d.db.WithContext(ctx).Create(prMessage) + + if result.Error != nil { + return nil, herrors.NewErrInsertFailed(herrors.PRMessageInDB, result.Error.Error()) + } + + return prMessage, result.Error +} + +func (d *prMessageDAO) List(ctx context.Context, pipelineRunID uint, query *q.Query) (int, []*models.PRMessage, error) { + var ( + total int64 + prMessages []*models.PRMessage + ) + + sql := d.db.WithContext(ctx).Table("tb_pr_msg"). + Where("pipeline_run_id = ?", pipelineRunID). + Order("created_at asc") + sql.Count(&total) + result := sql.Limit(query.Limit()).Offset(query.Offset()).Find(&prMessages) + if result.Error != nil { + return 0, nil, herrors.NewErrGetFailed(herrors.PRMessageInDB, result.Error.Error()) + } + if result.RowsAffected == 0 { + return 0, []*models.PRMessage{}, nil + } + return int(result.RowsAffected), prMessages, nil +} diff --git a/pkg/pipelinerun/dao/dao.go b/pkg/pr/dao/pipelinerun.go similarity index 75% rename from pkg/pipelinerun/dao/dao.go rename to pkg/pr/dao/pipelinerun.go index c91a63bd8..28c8dc35e 100644 --- a/pkg/pipelinerun/dao/dao.go +++ b/pkg/pr/dao/pipelinerun.go @@ -17,14 +17,15 @@ package dao import ( "context" + "gorm.io/gorm" + herrors "github.com/horizoncd/horizon/core/errors" "github.com/horizoncd/horizon/lib/q" "github.com/horizoncd/horizon/pkg/common" - "github.com/horizoncd/horizon/pkg/pipelinerun/models" - "gorm.io/gorm" + "github.com/horizoncd/horizon/pkg/pr/models" ) -type DAO interface { +type PipelineRunDAO interface { // Create create a pipelinerun Create(ctx context.Context, pipelinerun *models.Pipelinerun) (*models.Pipelinerun, error) GetByID(ctx context.Context, pipelinerunID uint) (*models.Pipelinerun, error) @@ -43,15 +44,16 @@ type DAO interface { UpdateResultByID(ctx context.Context, pipelinerunID uint, result *models.Result) error GetLatestSuccessByClusterID(ctx context.Context, clusterID uint) (*models.Pipelinerun, error) GetFirstCanRollbackPipelinerun(ctx context.Context, clusterID uint) (*models.Pipelinerun, error) + UpdateColumns(ctx context.Context, id uint, columns map[string]interface{}) error } -type dao struct{ db *gorm.DB } +type pipelinerunDAO struct{ db *gorm.DB } -func NewDAO(db *gorm.DB) DAO { - return &dao{db: db} +func NewPipelineRunDAO(db *gorm.DB) PipelineRunDAO { + return &pipelinerunDAO{db: db} } -func (d *dao) Create(ctx context.Context, pipelinerun *models.Pipelinerun) (*models.Pipelinerun, error) { +func (d *pipelinerunDAO) Create(ctx context.Context, pipelinerun *models.Pipelinerun) (*models.Pipelinerun, error) { result := d.db.WithContext(ctx).Create(pipelinerun) if result.Error != nil { @@ -61,7 +63,7 @@ func (d *dao) Create(ctx context.Context, pipelinerun *models.Pipelinerun) (*mod return pipelinerun, result.Error } -func (d *dao) GetByID(ctx context.Context, pipelinerunID uint) (*models.Pipelinerun, error) { +func (d *pipelinerunDAO) GetByID(ctx context.Context, pipelinerunID uint) (*models.Pipelinerun, error) { var pr models.Pipelinerun result := d.db.WithContext(ctx).Raw(common.PipelinerunGetByID, pipelinerunID).Scan(&pr) if result.Error != nil { @@ -73,7 +75,7 @@ func (d *dao) GetByID(ctx context.Context, pipelinerunID uint) (*models.Pipeline return &pr, nil } -func (d *dao) GetByCIEventID(ctx context.Context, ciEventID string) (*models.Pipelinerun, error) { +func (d *pipelinerunDAO) GetByCIEventID(ctx context.Context, ciEventID string) (*models.Pipelinerun, error) { var pr models.Pipelinerun result := d.db.WithContext(ctx).Raw(common.PipelinerunGetByCIEventID, ciEventID).Scan(&pr) if result.Error != nil { @@ -85,7 +87,7 @@ func (d *dao) GetByCIEventID(ctx context.Context, ciEventID string) (*models.Pip return &pr, nil } -func (d *dao) DeleteByClusterID(ctx context.Context, clusterID uint) error { +func (d *pipelinerunDAO) DeleteByClusterID(ctx context.Context, clusterID uint) error { result := d.db.WithContext(ctx).Exec(common.PipelinerunDeleteByClusterID, clusterID) if result.Error != nil { @@ -95,7 +97,7 @@ func (d *dao) DeleteByClusterID(ctx context.Context, clusterID uint) error { return result.Error } -func (d *dao) DeleteByID(ctx context.Context, pipelinerunID uint) error { +func (d *pipelinerunDAO) DeleteByID(ctx context.Context, pipelinerunID uint) error { result := d.db.WithContext(ctx).Exec(common.PipelinerunDeleteByID, pipelinerunID) if result.Error != nil { @@ -105,7 +107,7 @@ func (d *dao) DeleteByID(ctx context.Context, pipelinerunID uint) error { return result.Error } -func (d *dao) UpdateConfigCommitByID(ctx context.Context, pipelinerunID uint, commit string) error { +func (d *pipelinerunDAO) UpdateConfigCommitByID(ctx context.Context, pipelinerunID uint, commit string) error { result := d.db.WithContext(ctx).Exec(common.PipelinerunUpdateConfigCommitByID, commit, pipelinerunID) if result.Error != nil { @@ -114,7 +116,7 @@ func (d *dao) UpdateConfigCommitByID(ctx context.Context, pipelinerunID uint, co return result.Error } -func (d *dao) GetLatestByClusterIDAndActions(ctx context.Context, +func (d *pipelinerunDAO) GetLatestByClusterIDAndActions(ctx context.Context, clusterID uint, actions ...string) (*models.Pipelinerun, error) { var pipelinerun models.Pipelinerun result := d.db.WithContext(ctx).Raw(common.PipelinerunGetLatestByClusterIDAndActions, @@ -128,7 +130,7 @@ func (d *dao) GetLatestByClusterIDAndActions(ctx context.Context, return &pipelinerun, nil } -func (d *dao) GetLatestByClusterIDAndActionAndStatus(ctx context.Context, +func (d *pipelinerunDAO) GetLatestByClusterIDAndActionAndStatus(ctx context.Context, clusterID uint, action string, status string) (*models.Pipelinerun, error) { var pipelinerun models.Pipelinerun result := d.db.WithContext(ctx).Raw(common.PipelinerunGetLatestByClusterIDAndActionAndStatus, clusterID, @@ -142,7 +144,7 @@ func (d *dao) GetLatestByClusterIDAndActionAndStatus(ctx context.Context, return &pipelinerun, nil } -func (d *dao) GetLatestSuccessByClusterID(ctx context.Context, clusterID uint) (*models.Pipelinerun, error) { +func (d *pipelinerunDAO) GetLatestSuccessByClusterID(ctx context.Context, clusterID uint) (*models.Pipelinerun, error) { var pipelinerun models.Pipelinerun result := d.db.WithContext(ctx).Raw(common.PipelinerunGetLatestSuccessByClusterID, clusterID).Scan(&pipelinerun) if result.Error != nil { @@ -154,23 +156,15 @@ func (d *dao) GetLatestSuccessByClusterID(ctx context.Context, clusterID uint) ( return &pipelinerun, nil } -func (d *dao) UpdateStatusByID(ctx context.Context, pipelinerunID uint, status models.PipelineStatus) error { - res := d.db.WithContext(ctx).Exec(common.PipelinerunUpdateStatusByID, status, pipelinerunID) - if res.Error != nil { - return herrors.NewErrUpdateFailed(herrors.PipelinerunInDB, res.Error.Error()) - } - return res.Error +func (d *pipelinerunDAO) UpdateStatusByID(ctx context.Context, pipelinerunID uint, status models.PipelineStatus) error { + return d.UpdateColumns(ctx, pipelinerunID, map[string]interface{}{"status": string(status)}) } -func (d *dao) UpdateCIEventIDByID(ctx context.Context, pipelinerunID uint, ciEventID string) error { - res := d.db.WithContext(ctx).Exec(common.PipelinerunUpdateCIEventIDByID, ciEventID, pipelinerunID) - if res.Error != nil { - return herrors.NewErrUpdateFailed(herrors.PipelinerunInDB, res.Error.Error()) - } - return res.Error +func (d *pipelinerunDAO) UpdateCIEventIDByID(ctx context.Context, pipelinerunID uint, ciEventID string) error { + return d.UpdateColumns(ctx, pipelinerunID, map[string]interface{}{"ci_event_id": ciEventID}) } -func (d *dao) UpdateResultByID(ctx context.Context, pipelinerunID uint, result *models.Result) error { +func (d *pipelinerunDAO) UpdateResultByID(ctx context.Context, pipelinerunID uint, result *models.Result) error { res := d.db.WithContext(ctx).Exec(common.PipelinerunUpdateResultByID, result.Result, result.S3Bucket, result.LogObject, result.PrObject, result.StartedAt, result.FinishedAt, pipelinerunID) @@ -180,7 +174,7 @@ func (d *dao) UpdateResultByID(ctx context.Context, pipelinerunID uint, result * return res.Error } -func (d *dao) GetByClusterID(ctx context.Context, clusterID uint, +func (d *pipelinerunDAO) GetByClusterID(ctx context.Context, clusterID uint, canRollback bool, query q.Query) (int, []*models.Pipelinerun, error) { offset := (query.PageNumber - 1) * query.PageSize limit := query.PageSize @@ -214,7 +208,8 @@ func (d *dao) GetByClusterID(ctx context.Context, clusterID uint, return total, pipelineruns, result.Error } -func (d *dao) GetFirstCanRollbackPipelinerun(ctx context.Context, clusterID uint) (*models.Pipelinerun, error) { +func (d *pipelinerunDAO) GetFirstCanRollbackPipelinerun(ctx context.Context, + clusterID uint) (*models.Pipelinerun, error) { var pipelinerun models.Pipelinerun result := d.db.WithContext(ctx).Raw(common.PipelinerunGetFirstCanRollbackByClusterID, clusterID).Scan(&pipelinerun) @@ -226,3 +221,12 @@ func (d *dao) GetFirstCanRollbackPipelinerun(ctx context.Context, clusterID uint } return &pipelinerun, nil } + +func (d *pipelinerunDAO) UpdateColumns(ctx context.Context, id uint, columns map[string]interface{}) error { + res := d.db.WithContext(ctx).Model(models.Pipelinerun{}). + Where("id = ?", id).Updates(columns) + if res.Error != nil { + return herrors.NewErrUpdateFailed(herrors.PipelinerunInDB, res.Error.Error()) + } + return res.Error +} diff --git a/pkg/pr/manager/check.go b/pkg/pr/manager/check.go new file mode 100644 index 000000000..e2e7c05a1 --- /dev/null +++ b/pkg/pr/manager/check.go @@ -0,0 +1,62 @@ +package manager + +import ( + "context" + + "gorm.io/gorm" + + "github.com/horizoncd/horizon/core/common" + "github.com/horizoncd/horizon/pkg/pr/dao" + "github.com/horizoncd/horizon/pkg/pr/models" +) + +type CheckManager interface { + // Create create a check + Create(ctx context.Context, check *models.Check) (*models.Check, error) + // Update check run + UpdateByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error + // GetByResource get checks by resource + GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) + ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) + CreateCheckRun(ctx context.Context, checkRun *models.CheckRun) (*models.CheckRun, error) + ListMessage(ctx context.Context, pipelineRunID uint) ([]*models.PRMessage, error) + CreateMessage(ctx context.Context, message *models.PRMessage) (*models.PRMessage, error) +} + +type checkManager struct { + dao dao.CheckDAO +} + +func NewCheckManager(db *gorm.DB) CheckManager { + return &checkManager{ + dao: dao.NewCheckDAO(db), + } +} + +func (m *checkManager) Create(ctx context.Context, check *models.Check) (*models.Check, error) { + return m.dao.Create(ctx, check) +} + +func (m *checkManager) UpdateByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error { + return m.dao.UpdateByID(ctx, checkRunID, newCheckRun) +} + +func (m *checkManager) GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) { + return m.dao.GetByResource(ctx, resources...) +} + +func (m *checkManager) ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) { + return m.dao.ListCheckRuns(ctx, pipelineRunID) +} + +func (m *checkManager) CreateCheckRun(ctx context.Context, checkRun *models.CheckRun) (*models.CheckRun, error) { + return m.dao.CreateCheckRun(ctx, checkRun) +} + +func (m *checkManager) ListMessage(ctx context.Context, pipelineRunID uint) ([]*models.PRMessage, error) { + return m.dao.ListMessage(ctx, pipelineRunID) +} + +func (m *checkManager) CreateMessage(ctx context.Context, message *models.PRMessage) (*models.PRMessage, error) { + return m.dao.CreateMessage(ctx, message) +} diff --git a/pkg/pr/manager/message.go b/pkg/pr/manager/message.go new file mode 100644 index 000000000..5eb9a91e8 --- /dev/null +++ b/pkg/pr/manager/message.go @@ -0,0 +1,37 @@ +package manager + +import ( + "context" + + "gorm.io/gorm" + + "github.com/horizoncd/horizon/lib/q" + "github.com/horizoncd/horizon/pkg/pr/dao" + "github.com/horizoncd/horizon/pkg/pr/models" +) + +type PRMessageManager interface { + // Create create a PRMessage + Create(ctx context.Context, prMessage *models.PRMessage) (*models.PRMessage, error) + // List list PRMessage order by created_at asc + List(ctx context.Context, pipelineRunID uint, query *q.Query) (int, []*models.PRMessage, error) +} + +type prMessageManager struct { + dao dao.PRMessageDAO +} + +func NewPRMessageManager(db *gorm.DB) PRMessageManager { + return &prMessageManager{ + dao: dao.NewPRMessageDAO(db), + } +} + +func (m *prMessageManager) Create(ctx context.Context, prMessage *models.PRMessage) (*models.PRMessage, error) { + return m.dao.Create(ctx, prMessage) +} + +func (m *prMessageManager) List(ctx context.Context, pipelineRunID uint, + query *q.Query) (int, []*models.PRMessage, error) { + return m.dao.List(ctx, pipelineRunID, query) +} diff --git a/pkg/pipelinerun/manager/manager.go b/pkg/pr/manager/pipelinerun.go similarity index 60% rename from pkg/pipelinerun/manager/manager.go rename to pkg/pr/manager/pipelinerun.go index 5a97fef4b..2b44b1873 100644 --- a/pkg/pipelinerun/manager/manager.go +++ b/pkg/pr/manager/pipelinerun.go @@ -17,17 +17,18 @@ package manager import ( "context" - "github.com/horizoncd/horizon/lib/q" - "github.com/horizoncd/horizon/pkg/pipelinerun/dao" - "github.com/horizoncd/horizon/pkg/pipelinerun/models" "gorm.io/gorm" + + "github.com/horizoncd/horizon/lib/q" + "github.com/horizoncd/horizon/pkg/pr/dao" + "github.com/horizoncd/horizon/pkg/pr/models" ) // nolint // -package=mock_manager // //go:generate mockgen -source=$GOFILE -destination=../../../mock/pkg/pipelinerun/manager/mock_manager.go -type Manager interface { +type PipelineRunManager interface { Create(ctx context.Context, pipelinerun *models.Pipelinerun) (*models.Pipelinerun, error) GetByID(ctx context.Context, pipelinerunID uint) (*models.Pipelinerun, error) GetByCIEventID(ctx context.Context, ciEventID string) (*models.Pipelinerun, error) @@ -45,73 +46,82 @@ type Manager interface { UpdateCIEventIDByID(ctx context.Context, pipelinerunID uint, ciEventID string) error // UpdateResultByID update the pipelinerun restore result UpdateResultByID(ctx context.Context, pipelinerunID uint, result *models.Result) error + UpdateColumns(ctx context.Context, pipelinerunID uint, columns map[string]interface{}) error } -type manager struct { - dao dao.DAO +type pipelinerunManager struct { + dao dao.PipelineRunDAO } -func New(db *gorm.DB) Manager { - return &manager{ - dao: dao.NewDAO(db), +func NewPipelineRunManager(db *gorm.DB) PipelineRunManager { + return &pipelinerunManager{ + dao: dao.NewPipelineRunDAO(db), } } -func (m *manager) Create(ctx context.Context, pipelinerun *models.Pipelinerun) (*models.Pipelinerun, error) { +func (m *pipelinerunManager) Create(ctx context.Context, pipelinerun *models.Pipelinerun) (*models.Pipelinerun, error) { return m.dao.Create(ctx, pipelinerun) } -func (m *manager) GetByID(ctx context.Context, pipelinerunID uint) (*models.Pipelinerun, error) { +func (m *pipelinerunManager) GetByID(ctx context.Context, pipelinerunID uint) (*models.Pipelinerun, error) { return m.dao.GetByID(ctx, pipelinerunID) } -func (m *manager) GetByCIEventID(ctx context.Context, ciEventID string) (*models.Pipelinerun, error) { +func (m *pipelinerunManager) GetByCIEventID(ctx context.Context, ciEventID string) (*models.Pipelinerun, error) { return m.dao.GetByCIEventID(ctx, ciEventID) } -func (m *manager) DeleteByID(ctx context.Context, pipelinerunID uint) error { +func (m *pipelinerunManager) DeleteByID(ctx context.Context, pipelinerunID uint) error { return m.dao.DeleteByID(ctx, pipelinerunID) } -func (m *manager) DeleteByClusterID(ctx context.Context, clusterID uint) error { +func (m *pipelinerunManager) DeleteByClusterID(ctx context.Context, clusterID uint) error { return m.dao.DeleteByClusterID(ctx, clusterID) } -func (m *manager) UpdateConfigCommitByID(ctx context.Context, pipelinerunID uint, commit string) error { +func (m *pipelinerunManager) UpdateConfigCommitByID(ctx context.Context, pipelinerunID uint, commit string) error { return m.dao.UpdateConfigCommitByID(ctx, pipelinerunID, commit) } -func (m *manager) GetLatestByClusterIDAndActions(ctx context.Context, +func (m *pipelinerunManager) GetLatestByClusterIDAndActions(ctx context.Context, clusterID uint, actions ...string) (*models.Pipelinerun, error) { return m.dao.GetLatestByClusterIDAndActions(ctx, clusterID, actions...) } -func (m *manager) GetLatestSuccessByClusterID(ctx context.Context, clusterID uint) (*models.Pipelinerun, error) { +func (m *pipelinerunManager) GetLatestSuccessByClusterID(ctx context.Context, + clusterID uint) (*models.Pipelinerun, error) { return m.dao.GetLatestSuccessByClusterID(ctx, clusterID) } -func (m *manager) UpdateStatusByID(ctx context.Context, pipelinerunID uint, result models.PipelineStatus) error { +func (m *pipelinerunManager) UpdateStatusByID(ctx context.Context, + pipelinerunID uint, result models.PipelineStatus) error { return m.dao.UpdateStatusByID(ctx, pipelinerunID, result) } -func (m *manager) UpdateCIEventIDByID(ctx context.Context, pipelinerunID uint, ciEventID string) error { +func (m *pipelinerunManager) UpdateCIEventIDByID(ctx context.Context, pipelinerunID uint, ciEventID string) error { return m.dao.UpdateCIEventIDByID(ctx, pipelinerunID, ciEventID) } -func (m *manager) UpdateResultByID(ctx context.Context, pipelinerunID uint, result *models.Result) error { +func (m *pipelinerunManager) UpdateResultByID(ctx context.Context, pipelinerunID uint, result *models.Result) error { return m.dao.UpdateResultByID(ctx, pipelinerunID, result) } -func (m *manager) GetByClusterID(ctx context.Context, +func (m *pipelinerunManager) GetByClusterID(ctx context.Context, clusterID uint, canRollback bool, query q.Query) (int, []*models.Pipelinerun, error) { return m.dao.GetByClusterID(ctx, clusterID, canRollback, query) } -func (m *manager) GetFirstCanRollbackPipelinerun(ctx context.Context, clusterID uint) (*models.Pipelinerun, error) { +func (m *pipelinerunManager) GetFirstCanRollbackPipelinerun(ctx context.Context, + clusterID uint) (*models.Pipelinerun, error) { return m.dao.GetFirstCanRollbackPipelinerun(ctx, clusterID) } -func (m *manager) GetLatestByClusterIDAndActionAndStatus(ctx context.Context, clusterID uint, action, +func (m *pipelinerunManager) GetLatestByClusterIDAndActionAndStatus(ctx context.Context, clusterID uint, action, status string) (*models.Pipelinerun, error) { return m.dao.GetLatestByClusterIDAndActionAndStatus(ctx, clusterID, action, status) } + +func (m *pipelinerunManager) UpdateColumns(ctx context.Context, + pipelinerunID uint, columns map[string]interface{}) error { + return m.dao.UpdateColumns(ctx, pipelinerunID, columns) +} diff --git a/pkg/pipelinerun/manager/manager_test.go b/pkg/pr/manager/pipelinerun_test.go similarity index 98% rename from pkg/pipelinerun/manager/manager_test.go rename to pkg/pr/manager/pipelinerun_test.go index 499a58e25..f9586b30f 100644 --- a/pkg/pipelinerun/manager/manager_test.go +++ b/pkg/pr/manager/pipelinerun_test.go @@ -24,7 +24,7 @@ import ( "github.com/horizoncd/horizon/lib/orm" "github.com/horizoncd/horizon/lib/q" codemodels "github.com/horizoncd/horizon/pkg/cluster/code" - "github.com/horizoncd/horizon/pkg/pipelinerun/models" + "github.com/horizoncd/horizon/pkg/pr/models" "github.com/stretchr/testify/assert" ) @@ -32,7 +32,7 @@ import ( var ( db, _ = orm.NewSqliteDB("") ctx context.Context - mgr = New(db) + mgr = NewPipelineRunManager(db) ) func Test(t *testing.T) { diff --git a/pkg/pr/manager/pr.go b/pkg/pr/manager/pr.go new file mode 100644 index 000000000..2e7b30420 --- /dev/null +++ b/pkg/pr/manager/pr.go @@ -0,0 +1,19 @@ +package manager + +import ( + "gorm.io/gorm" +) + +type PRManager struct { + PipelineRun PipelineRunManager + Message PRMessageManager + Check CheckManager +} + +func NewPRManager(db *gorm.DB) *PRManager { + return &PRManager{ + PipelineRun: NewPipelineRunManager(db), + Message: NewPRMessageManager(db), + Check: NewCheckManager(db), + } +} diff --git a/pkg/pr/models/check.go b/pkg/pr/models/check.go new file mode 100644 index 000000000..d7afa8df4 --- /dev/null +++ b/pkg/pr/models/check.go @@ -0,0 +1,52 @@ +package models + +import ( + "github.com/horizoncd/horizon/core/common" + "github.com/horizoncd/horizon/pkg/server/global" +) + +type CheckRunStatus string + +const ( + CheckStatusQueue CheckRunStatus = "Queue" + CheckStatusInProgress CheckRunStatus = "InProgress" + CheckStatusSuccess CheckRunStatus = "Success" + CheckStatusFailure CheckRunStatus = "Failure" + CheckStatusCancelled CheckRunStatus = "Cancelled" +) + +var CheckRunStatusArr = [...]CheckRunStatus{ + CheckStatusQueue, + CheckStatusInProgress, + CheckStatusSuccess, + CheckStatusFailure, + CheckStatusCancelled, +} + +func String2CheckRunStatus(s string) CheckRunStatus { + for _, status := range CheckRunStatusArr { + if s == string(status) { + return status + } + } + return CheckStatusQueue +} + +type Check struct { + global.Model + common.Resource `json:",inline" gorm:"embedded"` +} + +type CheckRun struct { + global.Model `json:",inline"` + Name string `json:"name"` + CheckID uint `json:"checkId"` + Status CheckRunStatus `json:"status"` + Message string `json:"message"` + PipilineRunID uint `gorm:"column:pipeline_run_id" json:"pipelineRunId"` + DetailURL string `gorm:"column:detail_url" json:"detailUrl"` +} + +func (CheckRun) TableName() string { + return "tb_checkrun" +} diff --git a/pkg/pr/models/message.go b/pkg/pr/models/message.go new file mode 100644 index 000000000..fa5e027de --- /dev/null +++ b/pkg/pr/models/message.go @@ -0,0 +1,17 @@ +package models + +import ( + "github.com/horizoncd/horizon/pkg/server/global" +) + +type PRMessage struct { + global.Model + PipelineRunID uint `gorm:"column:pipeline_run_id"` + Content string + CreatedBy uint + UpdatedBy uint +} + +func (PRMessage) TableName() string { + return "tb_pr_msg" +} diff --git a/pkg/pipelinerun/models/pipelinerun.go b/pkg/pr/models/pipelinerun.go similarity index 59% rename from pkg/pipelinerun/models/pipelinerun.go rename to pkg/pr/models/pipelinerun.go index 39fbda326..9b952f663 100644 --- a/pkg/pipelinerun/models/pipelinerun.go +++ b/pkg/pr/models/pipelinerun.go @@ -28,7 +28,11 @@ const ( type PipelineStatus string const ( - StatusCreated PipelineStatus = "created" + StatusCreated PipelineStatus = "created" + StatusRunning PipelineStatus = "running" + StatusPending PipelineStatus = "pending" + // StatusReady means the pipeline is ready to be executed + StatusReady PipelineStatus = "ready" StatusCommitted PipelineStatus = "committed" StatusMerged PipelineStatus = "merged" StatusDeployed PipelineStatus = "deployed" @@ -85,6 +89,53 @@ type Pipelinerun struct { CreatedBy uint } +type PipelineBasic struct { + // ID pipelinerun id + ID uint `json:"id"` + Title string `json:"title"` + // Description of this pipelinerun + Description string `json:"description"` + + // Action type, which can be builddeploy, deploy, restart, rollback + Action string `json:"action"` + // Status of this pipelinerun, which can be created, ok, failed, cancelled, unknown + Status string `json:"status"` + // Title of this pipelinerun + + // GitURL the git url this pipelinerun to build with, can be empty when action is not builddeploy + GitURL string `json:"gitURL"` + // GitBranch the git branch this pipelinerun to build with, can be empty when action is not builddeploy + GitBranch string `json:"gitBranch,omitempty"` + // GitTag the git tag this pipelinerun to build with, can be empty when action is not builddeploy + GitTag string `json:"gitTag,omitempty"` + // GitCommit the git commit this pipelinerun to build with, can be empty when action is not builddeploy + GitCommit string `json:"gitCommit"` + // ImageURL image url of this pipelinerun to build image + ImageURL string `json:"imageURL"` + + // LastConfigCommit config commit in master branch of this pipelinerun, can be empty when action is restart + LastConfigCommit string `json:"lastConfigCommit"` + // ConfigCommit config commit of this pipelinerun + ConfigCommit string `json:"configCommit"` + // CreatedAt create time of this pipelinerun + CreatedAt time.Time `json:"createdAt"` + // UpdatedAt update time of this pipelinerun + UpdatedAt time.Time `json:"updatedAt"` + // StartedAt start time of this pipelinerun + StartedAt *time.Time `json:"startedAt"` + // FinishedAt finish time of this pipelinerun + FinishedAt *time.Time `json:"finishedAt"` + // CanRollback can this pipelinerun be rollback, default is false + CanRollback bool `json:"canRollback"` + // createInfo + CreatedBy UserInfo `json:"createdBy"` +} + +type UserInfo struct { + UserID uint `json:"userID"` + UserName string `json:"userName"` +} + type Result struct { S3Bucket string LogObject string diff --git a/pkg/pipelinerun/pipeline/dao/dao.go b/pkg/pr/pipeline/dao/dao.go similarity index 99% rename from pkg/pipelinerun/pipeline/dao/dao.go rename to pkg/pr/pipeline/dao/dao.go index cc28afb4d..c12956037 100644 --- a/pkg/pipelinerun/pipeline/dao/dao.go +++ b/pkg/pr/pipeline/dao/dao.go @@ -24,7 +24,7 @@ import ( "github.com/horizoncd/horizon/lib/q" "github.com/horizoncd/horizon/pkg/cluster/metrics/tekton" "github.com/horizoncd/horizon/pkg/errors" - "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/models" + "github.com/horizoncd/horizon/pkg/pr/pipeline/models" "github.com/horizoncd/horizon/pkg/server/global" ) diff --git a/pkg/pipelinerun/pipeline/manager/manager.go b/pkg/pr/pipeline/manager/manager.go similarity index 93% rename from pkg/pipelinerun/pipeline/manager/manager.go rename to pkg/pr/pipeline/manager/manager.go index 6e0ff47e2..ddf2376c4 100644 --- a/pkg/pipelinerun/pipeline/manager/manager.go +++ b/pkg/pr/pipeline/manager/manager.go @@ -21,8 +21,8 @@ import ( "github.com/horizoncd/horizon/lib/q" "github.com/horizoncd/horizon/pkg/cluster/metrics/tekton" - "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/dao" - "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/models" + "github.com/horizoncd/horizon/pkg/pr/pipeline/dao" + "github.com/horizoncd/horizon/pkg/pr/pipeline/models" "github.com/horizoncd/horizon/pkg/server/global" ) diff --git a/pkg/pipelinerun/pipeline/manager/manager_test.go b/pkg/pr/pipeline/manager/manager_test.go similarity index 98% rename from pkg/pipelinerun/pipeline/manager/manager_test.go rename to pkg/pr/pipeline/manager/manager_test.go index fc8a74cde..fd057fc87 100644 --- a/pkg/pipelinerun/pipeline/manager/manager_test.go +++ b/pkg/pr/pipeline/manager/manager_test.go @@ -27,7 +27,7 @@ import ( "github.com/horizoncd/horizon/lib/orm" "github.com/horizoncd/horizon/pkg/cluster/metrics/tekton" - "github.com/horizoncd/horizon/pkg/pipelinerun/pipeline/models" + "github.com/horizoncd/horizon/pkg/pr/pipeline/models" "github.com/horizoncd/horizon/pkg/server/global" ) diff --git a/pkg/pipelinerun/pipeline/models/pipeline.go b/pkg/pr/pipeline/models/pipeline.go similarity index 100% rename from pkg/pipelinerun/pipeline/models/pipeline.go rename to pkg/pr/pipeline/models/pipeline.go diff --git a/pkg/pipelinerun/pipeline/models/stats.go b/pkg/pr/pipeline/models/stats.go similarity index 100% rename from pkg/pipelinerun/pipeline/models/stats.go rename to pkg/pr/pipeline/models/stats.go diff --git a/pkg/pipelinerun/pipeline/models/step.go b/pkg/pr/pipeline/models/step.go similarity index 100% rename from pkg/pipelinerun/pipeline/models/step.go rename to pkg/pr/pipeline/models/step.go diff --git a/pkg/pipelinerun/pipeline/models/task.go b/pkg/pr/pipeline/models/task.go similarity index 100% rename from pkg/pipelinerun/pipeline/models/task.go rename to pkg/pr/pipeline/models/task.go diff --git a/pkg/pr/service/service.go b/pkg/pr/service/service.go new file mode 100644 index 000000000..3b6512d81 --- /dev/null +++ b/pkg/pr/service/service.go @@ -0,0 +1,135 @@ +package service + +import ( + "context" + + "github.com/horizoncd/horizon/core/common" + amodels "github.com/horizoncd/horizon/pkg/application/models" + codemodels "github.com/horizoncd/horizon/pkg/cluster/code" + cmodels "github.com/horizoncd/horizon/pkg/cluster/models" + gmodels "github.com/horizoncd/horizon/pkg/group/models" + "github.com/horizoncd/horizon/pkg/param/managerparam" + "github.com/horizoncd/horizon/pkg/pr/models" +) + +type Service struct { + manager *managerparam.Manager +} + +func NewService(manager *managerparam.Manager) *Service { + return &Service{ + manager, + } +} + +func (s *Service) OfPipelineBasic(ctx context.Context, + pr, firstCanRollbackPipelinerun *models.Pipelinerun) (*models.PipelineBasic, error) { + user, err := s.manager.UserMgr.GetUserByID(ctx, pr.CreatedBy) + if err != nil { + return nil, err + } + + canRollback := func() bool { + // set the firstCanRollbackPipelinerun that cannot rollback + if firstCanRollbackPipelinerun != nil && pr.ID == firstCanRollbackPipelinerun.ID { + return false + } + return pr.Action != models.ActionRestart && pr.Status == string(models.StatusOK) + }() + + prBasic := &models.PipelineBasic{ + ID: pr.ID, + Title: pr.Title, + Description: pr.Description, + Action: pr.Action, + Status: pr.Status, + GitURL: pr.GitURL, + GitCommit: pr.GitCommit, + ImageURL: pr.ImageURL, + LastConfigCommit: pr.LastConfigCommit, + ConfigCommit: pr.ConfigCommit, + CreatedAt: pr.CreatedAt, + UpdatedAt: pr.UpdatedAt, + StartedAt: pr.StartedAt, + FinishedAt: pr.FinishedAt, + CanRollback: canRollback, + CreatedBy: models.UserInfo{ + UserID: pr.CreatedBy, + UserName: user.Name, + }, + } + switch pr.GitRefType { + case codemodels.GitRefTypeTag: + prBasic.GitTag = pr.GitRef + case codemodels.GitRefTypeBranch: + prBasic.GitBranch = pr.GitRef + } + return prBasic, nil +} + +func (s *Service) OfPipelineBasics(ctx context.Context, prs []*models.Pipelinerun, + firstCanRollbackPipelinerun *models.Pipelinerun) ([]*models.PipelineBasic, error) { + var pipelineBasics []*models.PipelineBasic + for _, pr := range prs { + pipelineBasic, err := s.OfPipelineBasic(ctx, pr, firstCanRollbackPipelinerun) + if err != nil { + return nil, err + } + pipelineBasics = append(pipelineBasics, pipelineBasic) + } + return pipelineBasics, nil +} +func (s *Service) GetCheckByResource(ctx context.Context, resourceID uint, + resourceType string) ([]*models.Check, error) { + var ( + id = resourceID + app *amodels.Application + cluster *cmodels.Cluster + group *gmodels.Group + err error + ) + + resources := make([]common.Resource, 0) + + switch resourceType { + case common.ResourceCluster: + cluster, err = s.manager.ClusterMgr.GetByID(ctx, resourceID) + if err != nil { + return nil, err + } + id = cluster.ApplicationID + resources = append(resources, common.Resource{ + ID: cluster.ID, + Type: common.ResourceCluster, + }) + fallthrough + case common.ResourceApplication: + app, err = s.manager.ApplicationMgr.GetByID(ctx, id) + if err != nil { + return nil, err + } + id = app.GroupID + resources = append(resources, common.Resource{ + ID: app.ID, + Type: common.ResourceApplication, + }) + fallthrough + case common.ResourceGroup: + group, err = s.manager.GroupMgr.GetByID(ctx, id) + if err != nil { + return nil, err + } + } + ids, err := common.UnmarshalTraversalIDS(group.TraversalIDs) + if err != nil { + return nil, err + } + for _, id := range ids { + resources = append(resources, common.Resource{ + ID: id, + Type: common.ResourceGroup, + }) + } + + return s.manager.PRMgr.Check.GetByResource(ctx, resources...) +} diff --git a/pkg/server/global/model.go b/pkg/server/global/model.go index 67c23614d..003d69c37 100644 --- a/pkg/server/global/model.go +++ b/pkg/server/global/model.go @@ -21,10 +21,10 @@ import ( ) type Model struct { - ID uint `gorm:"primarykey"` - CreatedAt time.Time - UpdatedAt time.Time - DeletedTs soft_delete.DeletedAt + ID uint `gorm:"primarykey" json:"id"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + DeletedTs soft_delete.DeletedAt `json:"-"` } type HorizonMetaData struct { diff --git a/pkg/user/dao/dao.go b/pkg/user/dao/dao.go index 562857c4f..1fddafc56 100644 --- a/pkg/user/dao/dao.go +++ b/pkg/user/dao/dao.go @@ -18,6 +18,9 @@ import ( "context" "errors" "fmt" + "reflect" + + "gorm.io/gorm" corecommon "github.com/horizoncd/horizon/core/common" herrors "github.com/horizoncd/horizon/core/errors" @@ -25,7 +28,6 @@ import ( "github.com/horizoncd/horizon/pkg/common" perror "github.com/horizoncd/horizon/pkg/errors" "github.com/horizoncd/horizon/pkg/user/models" - "gorm.io/gorm" ) type DAO interface { @@ -68,6 +70,12 @@ func (d *dao) List(ctx context.Context, query *q.Query) (int64, []*models.User, tx = tx.Where("name like ?", fmt.Sprintf("%%%v%%", v)) case corecommon.UserQueryType: tx = tx.Where("user_type in ?", v) + case corecommon.UserQueryID: + if reflect.TypeOf(v).Kind() == reflect.Slice { + tx = tx.Where("id in ?", v) + } else { + tx = tx.Where("id = ?", v) + } } } } diff --git a/pkg/util/ormcallbacks/callbacks.go b/pkg/util/ormcallbacks/callbacks.go index 14cae2158..2c69412f0 100644 --- a/pkg/util/ormcallbacks/callbacks.go +++ b/pkg/util/ormcallbacks/callbacks.go @@ -15,8 +15,9 @@ package callbacks import ( - "github.com/horizoncd/horizon/core/common" "gorm.io/gorm" + + "github.com/horizoncd/horizon/core/common" ) const ( @@ -47,9 +48,11 @@ func addUpdatedByForUpdateDeleteCallback(db *gorm.DB) { if err != nil { return } - field := db.Statement.Schema.LookUpField(_updatedBy) - if field != nil { - db.Statement.SetColumn(_updatedBy, currentUser.GetID()) + if db.Statement.Schema != nil { + field := db.Statement.Schema.LookUpField(_updatedBy) + if field != nil { + db.Statement.SetColumn(_updatedBy, currentUser.GetID()) + } } } From 790ba787e89d11c0b72c3b661f136f707e50e247 Mon Sep 17 00:00:00 2001 From: kiloson <4closetool3@gmail.com> Date: Fri, 25 Aug 2023 18:06:42 +0800 Subject: [PATCH 02/11] fix: support search pipelinerun by status Signed-off-by: kiloson <4closetool3@gmail.com> --- core/cmd/cmd.go | 39 +++++++++++++--------------- core/common/pipelinerun.go | 3 +++ core/http/api/v2/pipelinerun/apis.go | 12 +++++++-- pkg/pr/dao/pipelinerun.go | 36 +++++++++++++------------ 4 files changed, 50 insertions(+), 40 deletions(-) create mode 100644 core/common/pipelinerun.go diff --git a/core/cmd/cmd.go b/core/cmd/cmd.go index 824e20472..3daf1e32f 100644 --- a/core/cmd/cmd.go +++ b/core/cmd/cmd.go @@ -24,10 +24,7 @@ import ( "log" "net/http" "os" - "os/signal" "regexp" - "sync" - "syscall" "time" "github.com/horizoncd/horizon/core/config" @@ -734,22 +731,22 @@ func Run(flags *Flags) { // setTasksBeforeExit set stop funcs which will be executed after sigterm and sigint catched func setTasksBeforeExit(stopFuncs ...func()) { - sig := make(chan os.Signal, 1) - signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT) - go func() { - s := <-sig - log.Printf("got %s signal, stop tasks...\n", s) - if len(stopFuncs) == 0 { - return - } - wg := sync.WaitGroup{} - wg.Add(len(stopFuncs)) - for _, stopFunc := range stopFuncs { - go func(stop func()) { - stop() - }(stopFunc) - } - wg.Wait() - log.Printf("all tasks stopped, exit now.") - }() + // sig := make(chan os.Signal, 1) + // signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT) + // go func() { + // s := <-sig + // log.Printf("got %s signal, stop tasks...\n", s) + // if len(stopFuncs) == 0 { + // return + // } + // wg := sync.WaitGroup{} + // wg.Add(len(stopFuncs)) + // for _, stopFunc := range stopFuncs { + // go func(stop func()) { + // stop() + // }(stopFunc) + // } + // wg.Wait() + // log.Printf("all tasks stopped, exit now.") + // }() } diff --git a/core/common/pipelinerun.go b/core/common/pipelinerun.go new file mode 100644 index 000000000..36f9db62f --- /dev/null +++ b/core/common/pipelinerun.go @@ -0,0 +1,3 @@ +package common + +const PipelineQueryByStatus = "status" diff --git a/core/http/api/v2/pipelinerun/apis.go b/core/http/api/v2/pipelinerun/apis.go index 55226554a..07f5a9271 100644 --- a/core/http/api/v2/pipelinerun/apis.go +++ b/core/http/api/v2/pipelinerun/apis.go @@ -36,6 +36,7 @@ const ( _pipelinerunIDParam = "pipelinerunID" _clusterIDParam = "clusterID" _canRollbackParam = "canRollback" + _pipelineStatus = "status" ) type API struct { @@ -134,11 +135,18 @@ func (a *API) List(c *gin.Context) { if err != nil { canRollback = false } + status := c.QueryArray(_pipelineStatus) + keywords := map[string]interface{}{} + if len(status) > 0 { + keywords[common.PipelineQueryByStatus] = status + } - total, pipelines, err := a.prCtl.ListPipelineruns(c, uint(clusterID), canRollback, q.Query{ + query := q.Query{ PageNumber: pageNumber, PageSize: pageSize, - }) + Keywords: keywords, + } + total, pipelines, err := a.prCtl.ListPipelineruns(c, uint(clusterID), canRollback, query) if err != nil { response.AbortWithError(c, err) return diff --git a/pkg/pr/dao/pipelinerun.go b/pkg/pr/dao/pipelinerun.go index 28c8dc35e..da52a4d48 100644 --- a/pkg/pr/dao/pipelinerun.go +++ b/pkg/pr/dao/pipelinerun.go @@ -19,6 +19,7 @@ import ( "gorm.io/gorm" + corecommon "github.com/horizoncd/horizon/core/common" herrors "github.com/horizoncd/horizon/core/errors" "github.com/horizoncd/horizon/lib/q" "github.com/horizoncd/horizon/pkg/common" @@ -176,36 +177,37 @@ func (d *pipelinerunDAO) UpdateResultByID(ctx context.Context, pipelinerunID uin func (d *pipelinerunDAO) GetByClusterID(ctx context.Context, clusterID uint, canRollback bool, query q.Query) (int, []*models.Pipelinerun, error) { - offset := (query.PageNumber - 1) * query.PageSize - limit := query.PageSize + offset := query.Offset() + limit := query.Limit() - var pipelineruns []*models.Pipelinerun - queryScript := common.PipelinerunGetByClusterID - countScript := common.PipelinerunGetByClusterIDTotalCount + sql := d.db.WithContext(ctx).Table("tb_pipelinerun").Where("cluster_id = ?", clusterID). + Order("created_at desc") if canRollback { // remove the first canRollback pipelinerun offset++ - queryScript = common.PipelinerunCanRollbackGetByClusterID - countScript = common.PipelinerunCanRollbackGetByClusterIDTotalCount + sql = sql.Where("action = 'restart'").Where("status = 'ok'") } - result := d.db.WithContext(ctx).Raw(queryScript, - clusterID, limit, offset).Scan(&pipelineruns) - if result.Error != nil { - return 0, nil, herrors.NewErrGetFailed(herrors.PipelinerunInDB, result.Error.Error()) + + for k, v := range query.Keywords { + switch k { + case corecommon.PipelineQueryByStatus: + sql = sql.Where("status in (?)", v) + } } - var total int - result = d.db.WithContext(ctx).Raw(countScript, - clusterID).Scan(&total) - if total < 0 { - total = 0 + var total int64 + result := sql.Count(&total) + if result.Error != nil { + return 0, nil, herrors.NewErrGetFailed(herrors.PipelinerunInDB, result.Error.Error()) } + var pipelineruns []*models.Pipelinerun + result = sql.Limit(limit).Offset(offset).Find(&pipelineruns) if result.Error != nil { return 0, nil, herrors.NewErrGetFailed(herrors.PipelinerunInDB, result.Error.Error()) } - return total, pipelineruns, result.Error + return int(total), pipelineruns, result.Error } func (d *pipelinerunDAO) GetFirstCanRollbackPipelinerun(ctx context.Context, From f8f07932df2abaa87d4acba3ee416cd97446704c Mon Sep 17 00:00:00 2001 From: kiloson <4closetool3@gmail.com> Date: Sun, 27 Aug 2023 16:30:19 +0800 Subject: [PATCH 03/11] fix: add open API Signed-off-by: kiloson <4closetool3@gmail.com> --- core/cmd/cmd.go | 39 ++-- core/controller/cluster/controller_test.go | 2 +- .../controller/pipelinerun/controller_test.go | 14 +- openapi/v2/restful/cluster.yaml | 46 ++++- openapi/v2/restful/pipelinerun.yaml | 184 ++++++++++++++++++ 5 files changed, 262 insertions(+), 23 deletions(-) diff --git a/core/cmd/cmd.go b/core/cmd/cmd.go index 3daf1e32f..824e20472 100644 --- a/core/cmd/cmd.go +++ b/core/cmd/cmd.go @@ -24,7 +24,10 @@ import ( "log" "net/http" "os" + "os/signal" "regexp" + "sync" + "syscall" "time" "github.com/horizoncd/horizon/core/config" @@ -731,22 +734,22 @@ func Run(flags *Flags) { // setTasksBeforeExit set stop funcs which will be executed after sigterm and sigint catched func setTasksBeforeExit(stopFuncs ...func()) { - // sig := make(chan os.Signal, 1) - // signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT) - // go func() { - // s := <-sig - // log.Printf("got %s signal, stop tasks...\n", s) - // if len(stopFuncs) == 0 { - // return - // } - // wg := sync.WaitGroup{} - // wg.Add(len(stopFuncs)) - // for _, stopFunc := range stopFuncs { - // go func(stop func()) { - // stop() - // }(stopFunc) - // } - // wg.Wait() - // log.Printf("all tasks stopped, exit now.") - // }() + sig := make(chan os.Signal, 1) + signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT) + go func() { + s := <-sig + log.Printf("got %s signal, stop tasks...\n", s) + if len(stopFuncs) == 0 { + return + } + wg := sync.WaitGroup{} + wg.Add(len(stopFuncs)) + for _, stopFunc := range stopFuncs { + go func(stop func()) { + stop() + }(stopFunc) + } + wg.Wait() + log.Printf("all tasks stopped, exit now.") + }() } diff --git a/core/controller/cluster/controller_test.go b/core/controller/cluster/controller_test.go index 2a5ad7fc2..29183df60 100644 --- a/core/controller/cluster/controller_test.go +++ b/core/controller/cluster/controller_test.go @@ -1280,7 +1280,7 @@ func testV2(t *testing.T) { // for test conf := config.Config{} param := param.Param{ - AutoFreeSvc: service.New([]string{"dev", "test"}), + AutoFreeSvc: service.New([]string{"dev", "test2"}), Manager: managerparam.InitManager(nil), } NewController(&conf, ¶m) diff --git a/core/controller/pipelinerun/controller_test.go b/core/controller/pipelinerun/controller_test.go index d74604f30..f7f76b710 100644 --- a/core/controller/pipelinerun/controller_test.go +++ b/core/controller/pipelinerun/controller_test.go @@ -50,6 +50,7 @@ import ( prmanager "github.com/horizoncd/horizon/pkg/pr/manager" "github.com/horizoncd/horizon/pkg/pr/models" prmodels "github.com/horizoncd/horizon/pkg/pr/models" + prservice "github.com/horizoncd/horizon/pkg/pr/service" pipelinemodel "github.com/horizoncd/horizon/pkg/pr/models" usermodel "github.com/horizoncd/horizon/pkg/user/models" @@ -71,9 +72,16 @@ func TestGetAndListPipelinerun(t *testing.T) { mockClusterGitRepo := clustergitrepomock.NewMockClusterGitRepo(mockCtl) mockUserManager := usermock.NewMockManager(mockCtl) var ctl Controller = &controller{ - prMgr: &prmanager.PRManager{PipelineRun: mockPipelineManager}, - clusterMgr: mockClusterManager, - appMgr: mockApplicationMananger, + prMgr: &prmanager.PRManager{PipelineRun: mockPipelineManager}, + clusterMgr: mockClusterManager, + appMgr: mockApplicationMananger, + prSvc: prservice.NewService( + &managerparam.Manager{ + ApplicationMgr: mockApplicationMananger, + ClusterMgr: mockClusterManager, + UserMgr: mockUserManager, + PRMgr: &prmanager.PRManager{PipelineRun: mockPipelineManager}, + }), envMgr: nil, tektonFty: nil, commitGetter: mockCommitGetter, diff --git a/openapi/v2/restful/cluster.yaml b/openapi/v2/restful/cluster.yaml index 24679cacc..65cc6ad83 100644 --- a/openapi/v2/restful/cluster.yaml +++ b/openapi/v2/restful/cluster.yaml @@ -1131,7 +1131,51 @@ paths: content: application/json: schema: {} - + /apis/core/v2/clusters/{clusterId}/pipelineruns: + parameters: + - name: clusterId + in: path + required: true + description: The ID of the cluster to get pipelineruns + schema: + type: integer + example: 60517 + post: + summary: Create a pipelinerun for a cluster + operationId: createPipelinerun + tags: [cluster] + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + action: + type: string + enum: [builddeploy, deploy, rollback] + description: type of pipelinerun + title: + type: string + description: title of pipelinerun + description: + type: string + description: description of pipelinerun + git: + type: object + properties: + branch: + type: string + description: branch of git repository + imageTag: + type: string + description: image tag of a image + pipelinerunID: + type: number + description: id of pipelinerun + responses: + '200': + description: OK components: diff --git a/openapi/v2/restful/pipelinerun.yaml b/openapi/v2/restful/pipelinerun.yaml index 1fcdc2b12..c82c7a937 100644 --- a/openapi/v2/restful/pipelinerun.yaml +++ b/openapi/v2/restful/pipelinerun.yaml @@ -227,9 +227,193 @@ paths: application/json: schema: $ref: "common.yaml#/components/schemas/Error" + /apis/core/v2/pipelineruns/{pipelinerunID}/run: + parameters: + - $ref: "common.yaml#/components/parameters/paramPipelinerunID" + post: + tags: + - pipelinerun + operationId: runPipelinerun + summary: | + Run the specified pipelinerun. + responses: + "200": + description: Success + /apis/core/v2/pipelineruns/{pipelinerunID}/forcerun: + parameters: + - $ref: "common.yaml#/components/parameters/paramPipelinerunID" + post: + tags: + - pipelinerun + operationId: forceRunPipelinerun + summary: | + Force run the specified pipelinerun. + responses: + "200": + description: Success + /apis/core/v2/pipelineruns/{pipelinerunID}/cancel: + parameters: + - $ref: "common.yaml#/components/parameters/paramPipelinerunID" + post: + tags: + - pipelinerun + operationId: cancelPipelinerun + summary: | + Cancel the specified pipelinerun. + responses: + "200": + description: Success + /apis/core/v2/pipelineruns/{pipelinerunID}/checkrun: + parameters: + - $ref: "common.yaml#/components/parameters/paramPipelinerunID" + post: + tags: + - pipelinerun + operationId: createCheckRun + summary: | + Create a check run for the specified pipelinerun. + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + type: string + description: "name of check run" + checkId: + type: integer + description: "check id of check run" + status: + type: string + description: "status of check run" + message: + type: string + description: "message of check run" + detailUrl: + type: string + description: "detail url of check run" + responses: + "200": + description: Success + get: + tags: + - pipelinerun + operationId: listCheckRuns + summary: | + List check runs of the specified pipelinerun. + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + properties: + total: + type: integer + description: "total number of check runs" + data: + type: object + properties: + items: + type: array + properties: + id: + type: integer + description: "id of check run" + name: + type: string + description: "name of check run" + checkId: + type: integer + description: "check id of check run" + status: + type: string + description: "status of check run" + pipilineRunId: + type: integer + description: "pipelinerun id of check run" + detailUrl: + type: string + description: "detail url of check run" + message: + type: string + description: "message of check run" + createdAt: + type: string + updatedAt: + type: string + /apis/core/v2/pipelineruns/{pipelinerunID}/message: + parameters: + - $ref: "common.yaml#/components/parameters/paramPipelinerunID" + post: + tags: + - pipelinerun + operationId: createMessage + summary: | + Create a message for the specified pipelinerun. + requestBody: + content: + application/json: + schema: + type: object + properties: + content: + type: string + description: "content of check run" + responses: + 200: + description: "Success" + get: + tags: + - pipelinerun + operationId: listMessage + summary: | + List message of the specified pipelinerun. + responses: + "200": + description: Success + content: + application/json: + schema: + type: object + properties: + total: + type: integer + description: "total number of message" + data: + type: array + properties: + id: + type: integer + description: "id of message" + pipilineRunId: + type: integer + description: "pipelinerun id of message" + content: + type: string + description: "content of message" + createdAt: + type: string + createdBy: + $ref: "#/components/schemas/MessageUser" + updatedBy: + $ref: "#/components/schemas/MessageUser" + + components: schemas: + MessageUser: + type: object + properties: + id: + type: integer + name: + type: string + userType: + type: string PipelineRun: type: object properties: From 953d829c16e47f96a497225d64faa7fd0bf059ad Mon Sep 17 00:00:00 2001 From: kiloson <4closetool3@gmail.com> Date: Sun, 27 Aug 2023 18:14:40 +0800 Subject: [PATCH 04/11] fix: add unit test Signed-off-by: kiloson <4closetool3@gmail.com> --- core/common/common.go | 4 +- .../cluster/controller_basic_v2_test.go | 114 ++++++++++++++++++ pkg/pr/dao/check.go | 31 +---- pkg/pr/dao/message.go | 2 +- pkg/pr/manager/check.go | 10 -- pkg/pr/manager/check_test.go | 58 +++++++++ pkg/pr/manager/message.go | 3 + pkg/pr/manager/message_test.go | 45 +++++++ pkg/pr/manager/pipelinerun.go | 6 + pkg/pr/manager/pipelinerun_test.go | 10 +- pkg/pr/service/service.go | 12 +- 11 files changed, 246 insertions(+), 49 deletions(-) create mode 100644 core/controller/cluster/controller_basic_v2_test.go create mode 100644 pkg/pr/manager/check_test.go create mode 100644 pkg/pr/manager/message_test.go diff --git a/core/common/common.go b/core/common/common.go index 86786bb22..d7e755c5d 100644 --- a/core/common/common.go +++ b/core/common/common.go @@ -1,6 +1,6 @@ package common type Resource struct { - ID uint `json:"resource_id" yaml:"resourceID"` - Type string `json:"resource_type" yaml:"resourceType"` + ResourceID uint `json:"resource_id" yaml:"resourceID"` + Type string `gorm:"column:resource_type" json:"resource_type" yaml:"resourceType"` } diff --git a/core/controller/cluster/controller_basic_v2_test.go b/core/controller/cluster/controller_basic_v2_test.go new file mode 100644 index 000000000..fa111e7ae --- /dev/null +++ b/core/controller/cluster/controller_basic_v2_test.go @@ -0,0 +1,114 @@ +package cluster + +import ( + "context" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + + "github.com/horizoncd/horizon/core/common" + "github.com/horizoncd/horizon/lib/orm" + mock_code "github.com/horizoncd/horizon/mock/pkg/cluster/code" + mock_gitrepo "github.com/horizoncd/horizon/mock/pkg/cluster/gitrepo" + appmodels "github.com/horizoncd/horizon/pkg/application/models" + userauth "github.com/horizoncd/horizon/pkg/authentication/user" + clustergitrepo "github.com/horizoncd/horizon/pkg/cluster/gitrepo" + "github.com/horizoncd/horizon/pkg/cluster/models" + "github.com/horizoncd/horizon/pkg/git" + groupmodels "github.com/horizoncd/horizon/pkg/group/models" + membermodels "github.com/horizoncd/horizon/pkg/member/models" + "github.com/horizoncd/horizon/pkg/param/managerparam" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" + prservice "github.com/horizoncd/horizon/pkg/pr/service" + regionmodels "github.com/horizoncd/horizon/pkg/region/models" + registrymodels "github.com/horizoncd/horizon/pkg/registry/models" + usermodel "github.com/horizoncd/horizon/pkg/user/models" +) + +func TestCreatePipelineRun(t *testing.T) { + db, _ := orm.NewSqliteDB("") + if err := db.AutoMigrate(&appmodels.Application{}, &models.Cluster{}, + ®ionmodels.Region{}, &membermodels.Member{}, ®istrymodels.Registry{}, + &prmodels.Pipelinerun{}, &groupmodels.Group{}, + &usermodel.User{}, &prmodels.Check{}); err != nil { + panic(err) + } + param := managerparam.InitManager(db) + ctx := context.Background() + // nolint + ctx = context.WithValue(ctx, common.UserContextKey(), &userauth.DefaultInfo{ + Name: "Tony", + ID: uint(1), + }) + // request for build deploy + r := &CreatePipelineRunRequest{ + Action: prmodels.ActionBuildDeploy, + Title: "test", + Description: "test", + Git: &BuildDeployRequestGit{ + Commit: "test", + }, + PipelinerunID: 1, + } + + mockCtl := gomock.NewController(t) + mockGitGetter := mock_code.NewMockGitGetter(mockCtl) + mockGitGetter.EXPECT().GetCommit(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(&git.Commit{Message: "test"}, nil).AnyTimes() + + mockClusterGitRepo := mock_gitrepo.NewMockClusterGitRepo(mockCtl) + mockClusterGitRepo.EXPECT().GetConfigCommit(gomock.Any(), gomock.Any(), gomock.Any()). + Return(&clustergitrepo.ClusterCommit{ + Master: "master", + Gitops: "gitops", + }, nil).AnyTimes() + + controller := &controller{ + prSvc: prservice.NewService(param), + prMgr: param.PRMgr, + clusterMgr: param.ClusterMgr, + applicationMgr: param.ApplicationMgr, + regionMgr: param.RegionMgr, + clusterGitRepo: mockClusterGitRepo, + commitGetter: mockGitGetter, + } + + _, err := param.UserMgr.Create(ctx, &usermodel.User{ + Name: "Tony", + }) + assert.NoError(t, err) + + group, err := param.GroupMgr.Create(ctx, &groupmodels.Group{ + Name: "test", + }) + assert.NoError(t, err) + + app, err := param.ApplicationMgr.Create(ctx, &appmodels.Application{ + Name: "test", + GroupID: group.ID, + }, nil) + assert.NoError(t, err) + + registryID, err := param.RegistryMgr.Create(ctx, ®istrymodels.Registry{ + Name: "test", + }) + assert.NoError(t, err) + + region, err := param.RegionMgr.Create(ctx, ®ionmodels.Region{ + Name: "test", + RegistryID: registryID, + }) + + assert.NoError(t, err) + clusterGit, err := param.ClusterMgr.Create(ctx, &models.Cluster{ + Name: "clusterGit", + ApplicationID: app.ID, + GitURL: "hello", + RegionName: region.Name, + }, nil, nil) + assert.NoError(t, err) + + _, err = controller.CreatePipelineRun(ctx, clusterGit.ID, r) + assert.NoError(t, err) +} diff --git a/pkg/pr/dao/check.go b/pkg/pr/dao/check.go index 1c120de22..423e2aa33 100644 --- a/pkg/pr/dao/check.go +++ b/pkg/pr/dao/check.go @@ -19,8 +19,6 @@ type CheckDAO interface { GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) CreateCheckRun(ctx context.Context, run *models.CheckRun) (*models.CheckRun, error) - ListMessage(ctx context.Context, pipelineRunID uint) ([]*models.PRMessage, error) - CreateMessage(ctx context.Context, message *models.PRMessage) (*models.PRMessage, error) } type checkDAO struct{ db *gorm.DB } @@ -56,9 +54,9 @@ func (d *checkDAO) GetByResource(ctx context.Context, resources ...common.Resour return []*models.Check{}, nil } - sql = sql.Where(d.db.Where("resource_type = ?", resources[0].Type).Where("resource_id = ?", resources[0].ID)) + sql = sql.Where(d.db.Where("resource_type = ?", resources[0].Type).Where("resource_id = ?", resources[0].ResourceID)) for _, resource := range resources[1:] { - sql = sql.Or(d.db.Where("resource_type = ?", resource.Type).Where("resource_id = ?", resource.ID)) + sql = sql.Or(d.db.Where("resource_type = ?", resource.Type).Where("resource_id = ?", resource.ResourceID)) } result := sql.Find(&checks) @@ -95,28 +93,3 @@ func (d *checkDAO) CreateCheckRun(ctx context.Context, run *models.CheckRun) (*m return run, result.Error } - -func (d *checkDAO) ListMessage(ctx context.Context, pipelineRunID uint) ([]*models.PRMessage, error) { - var messages []*models.PRMessage - result := d.db.WithContext(ctx).Where("pipeline_run_id = ?", pipelineRunID). - Order("updated_at asc"). - Find(&messages) - - if result.RowsAffected == 0 { - return []*models.PRMessage{}, nil - } - if result.Error != nil { - return nil, herrors.NewErrGetFailed(herrors.CheckRunInDB, result.Error.Error()) - } - return messages, nil -} - -func (d *checkDAO) CreateMessage(ctx context.Context, message *models.PRMessage) (*models.PRMessage, error) { - result := d.db.WithContext(ctx).Create(message) - - if result.Error != nil { - return nil, herrors.NewErrInsertFailed(herrors.CheckRunInDB, result.Error.Error()) - } - - return message, result.Error -} diff --git a/pkg/pr/dao/message.go b/pkg/pr/dao/message.go index bc6995905..42ff4c0ca 100644 --- a/pkg/pr/dao/message.go +++ b/pkg/pr/dao/message.go @@ -50,5 +50,5 @@ func (d *prMessageDAO) List(ctx context.Context, pipelineRunID uint, query *q.Qu if result.RowsAffected == 0 { return 0, []*models.PRMessage{}, nil } - return int(result.RowsAffected), prMessages, nil + return int(total), prMessages, nil } diff --git a/pkg/pr/manager/check.go b/pkg/pr/manager/check.go index e2e7c05a1..01c4f2ac7 100644 --- a/pkg/pr/manager/check.go +++ b/pkg/pr/manager/check.go @@ -19,8 +19,6 @@ type CheckManager interface { GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) CreateCheckRun(ctx context.Context, checkRun *models.CheckRun) (*models.CheckRun, error) - ListMessage(ctx context.Context, pipelineRunID uint) ([]*models.PRMessage, error) - CreateMessage(ctx context.Context, message *models.PRMessage) (*models.PRMessage, error) } type checkManager struct { @@ -52,11 +50,3 @@ func (m *checkManager) ListCheckRuns(ctx context.Context, pipelineRunID uint) ([ func (m *checkManager) CreateCheckRun(ctx context.Context, checkRun *models.CheckRun) (*models.CheckRun, error) { return m.dao.CreateCheckRun(ctx, checkRun) } - -func (m *checkManager) ListMessage(ctx context.Context, pipelineRunID uint) ([]*models.PRMessage, error) { - return m.dao.ListMessage(ctx, pipelineRunID) -} - -func (m *checkManager) CreateMessage(ctx context.Context, message *models.PRMessage) (*models.PRMessage, error) { - return m.dao.CreateMessage(ctx, message) -} diff --git a/pkg/pr/manager/check_test.go b/pkg/pr/manager/check_test.go new file mode 100644 index 000000000..1872052ce --- /dev/null +++ b/pkg/pr/manager/check_test.go @@ -0,0 +1,58 @@ +package manager + +import ( + "context" + "testing" + + "github.com/horizoncd/horizon/core/common" + "github.com/horizoncd/horizon/pkg/pr/models" + + "github.com/stretchr/testify/assert" +) + +func TestCheck(t *testing.T) { + checkManager := NewCheckManager(db) + + ctx := context.Background() + + // Test Create + check := &models.Check{ + Resource: common.Resource{ + Type: "clusters", + ResourceID: 123, + }, + } + createdCheck, err := checkManager.Create(ctx, check) + assert.NoError(t, err) + assert.Equal(t, createdCheck.Type, check.Type) + + // Test UpdateByID + checkRun := &models.CheckRun{ + PipilineRunID: 10, + CheckID: createdCheck.ResourceID, + Status: models.CheckStatusQueue, + } + _, err = checkManager.CreateCheckRun(ctx, checkRun) + assert.NoError(t, err) + + newCheckRun := &models.CheckRun{ + Status: models.CheckStatusInProgress, + } + err = checkManager.UpdateByID(ctx, checkRun.ID, newCheckRun) + assert.NoError(t, err) + + // Test GetByResource + checks, err := checkManager.GetByResource(ctx, common.Resource{ + Type: "clusters", + ResourceID: 123, + }) + assert.NoError(t, err) + assert.Len(t, checks, 1) + + // Test ListCheckRuns + checkRuns, err := checkManager.ListCheckRuns(ctx, checkRun.PipilineRunID) + assert.NoError(t, err) + assert.Len(t, checkRuns, 1) + assert.Equal(t, checkRuns[0].Status, models.CheckStatusInProgress) + assert.Equal(t, checkRuns[0].CheckID, createdCheck.ResourceID) +} diff --git a/pkg/pr/manager/message.go b/pkg/pr/manager/message.go index 5eb9a91e8..e7eaaaee3 100644 --- a/pkg/pr/manager/message.go +++ b/pkg/pr/manager/message.go @@ -33,5 +33,8 @@ func (m *prMessageManager) Create(ctx context.Context, prMessage *models.PRMessa func (m *prMessageManager) List(ctx context.Context, pipelineRunID uint, query *q.Query) (int, []*models.PRMessage, error) { + if query == nil { + query = &q.Query{} + } return m.dao.List(ctx, pipelineRunID, query) } diff --git a/pkg/pr/manager/message_test.go b/pkg/pr/manager/message_test.go new file mode 100644 index 000000000..6f522b16f --- /dev/null +++ b/pkg/pr/manager/message_test.go @@ -0,0 +1,45 @@ +package manager + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/horizoncd/horizon/lib/q" + "github.com/horizoncd/horizon/pkg/pr/models" +) + +func TestMessage(t *testing.T) { + prMessageManager := NewPRMessageManager(db) + + // Create some PRMessages to test with + prMessages := []*models.PRMessage{ + {PipelineRunID: 1, Content: "message 2"}, + {PipelineRunID: 2, Content: "message 3"}, + } + for _, prMessage := range prMessages { + _, err := prMessageManager.Create(context.Background(), prMessage) + assert.NoError(t, err) + } + prMessage := &models.PRMessage{PipelineRunID: 1, Content: "message 1"} + + createdPRMessage, err := prMessageManager.Create(context.Background(), prMessage) + assert.NoError(t, err) + assert.NotNil(t, createdPRMessage) + assert.Equal(t, prMessage.PipelineRunID, createdPRMessage.PipelineRunID) + assert.Equal(t, prMessage.Content, createdPRMessage.Content) + + // Test listing PRMessages for a specific PipelineRunID + totalCount, listedPRMessages, err := prMessageManager.List(context.Background(), 1, nil) + assert.NoError(t, err) + assert.Len(t, listedPRMessages, 2) + assert.Equal(t, 2, totalCount) + + // Test listing PRMessages with a query + query := &q.Query{PageSize: 1} + totalCount, listedPRMessages, err = prMessageManager.List(context.Background(), 1, query) + assert.NoError(t, err) + assert.Len(t, listedPRMessages, 1) + assert.Equal(t, 2, totalCount) +} diff --git a/pkg/pr/manager/pipelinerun.go b/pkg/pr/manager/pipelinerun.go index 2b44b1873..2e6bc5a6e 100644 --- a/pkg/pr/manager/pipelinerun.go +++ b/pkg/pr/manager/pipelinerun.go @@ -19,6 +19,7 @@ import ( "gorm.io/gorm" + "github.com/horizoncd/horizon/core/common" "github.com/horizoncd/horizon/lib/q" "github.com/horizoncd/horizon/pkg/pr/dao" "github.com/horizoncd/horizon/pkg/pr/models" @@ -60,6 +61,11 @@ func NewPipelineRunManager(db *gorm.DB) PipelineRunManager { } func (m *pipelinerunManager) Create(ctx context.Context, pipelinerun *models.Pipelinerun) (*models.Pipelinerun, error) { + currentUser, err := common.UserFromContext(ctx) + if err != nil { + return nil, err + } + pipelinerun.CreatedBy = currentUser.GetID() return m.dao.Create(ctx, pipelinerun) } diff --git a/pkg/pr/manager/pipelinerun_test.go b/pkg/pr/manager/pipelinerun_test.go index f9586b30f..9addfbbf2 100644 --- a/pkg/pr/manager/pipelinerun_test.go +++ b/pkg/pr/manager/pipelinerun_test.go @@ -21,8 +21,10 @@ import ( "testing" "time" + "github.com/horizoncd/horizon/core/common" "github.com/horizoncd/horizon/lib/orm" "github.com/horizoncd/horizon/lib/q" + userauth "github.com/horizoncd/horizon/pkg/authentication/user" codemodels "github.com/horizoncd/horizon/pkg/cluster/code" "github.com/horizoncd/horizon/pkg/pr/models" @@ -36,6 +38,11 @@ var ( ) func Test(t *testing.T) { + // nolint + ctx = context.WithValue(ctx, common.UserContextKey(), &userauth.DefaultInfo{ + Name: "Tony", + ID: uint(1), + }) pr, err := mgr.Create(ctx, &models.Pipelinerun{ ID: 0, ClusterID: 1, @@ -235,7 +242,8 @@ func TestGetFirstCanRollbackPipelinerun(t *testing.T) { } func TestMain(m *testing.M) { - if err := db.AutoMigrate(&models.Pipelinerun{}); err != nil { + if err := db.AutoMigrate(&models.Pipelinerun{}, &models.Check{}, + &models.CheckRun{}, &models.PRMessage{}); err != nil { panic(err) } ctx = context.TODO() diff --git a/pkg/pr/service/service.go b/pkg/pr/service/service.go index 3b6512d81..a2132c1d8 100644 --- a/pkg/pr/service/service.go +++ b/pkg/pr/service/service.go @@ -99,8 +99,8 @@ func (s *Service) GetCheckByResource(ctx context.Context, resourceID uint, } id = cluster.ApplicationID resources = append(resources, common.Resource{ - ID: cluster.ID, - Type: common.ResourceCluster, + ResourceID: cluster.ID, + Type: common.ResourceCluster, }) fallthrough case common.ResourceApplication: @@ -110,8 +110,8 @@ func (s *Service) GetCheckByResource(ctx context.Context, resourceID uint, } id = app.GroupID resources = append(resources, common.Resource{ - ID: app.ID, - Type: common.ResourceApplication, + ResourceID: app.ID, + Type: common.ResourceApplication, }) fallthrough case common.ResourceGroup: @@ -126,8 +126,8 @@ func (s *Service) GetCheckByResource(ctx context.Context, resourceID uint, } for _, id := range ids { resources = append(resources, common.Resource{ - ID: id, - Type: common.ResourceGroup, + ResourceID: id, + Type: common.ResourceGroup, }) } From 4504627dfe5acd47630e5c2d1297cd43d0676098 Mon Sep 17 00:00:00 2001 From: kiloson <4closetool3@gmail.com> Date: Mon, 28 Aug 2023 12:01:39 +0800 Subject: [PATCH 05/11] fix: unit test Signed-off-by: kiloson <4closetool3@gmail.com> --- .../cluster/controller_basic_v2_test.go | 64 ++++-- core/controller/cluster/models_basic_v2.go | 7 +- core/controller/pipelinerun/controller.go | 17 +- .../controller/pipelinerun/controller_test.go | 210 ++++++++++++++++++ pkg/pr/dao/check.go | 4 +- pkg/pr/manager/check_test.go | 4 +- pkg/pr/models/check.go | 4 +- pkg/templaterelease/dao/dao.go | 5 +- 8 files changed, 288 insertions(+), 27 deletions(-) diff --git a/core/controller/cluster/controller_basic_v2_test.go b/core/controller/cluster/controller_basic_v2_test.go index fa111e7ae..2ac9d0100 100644 --- a/core/controller/cluster/controller_basic_v2_test.go +++ b/core/controller/cluster/controller_basic_v2_test.go @@ -30,8 +30,8 @@ func TestCreatePipelineRun(t *testing.T) { db, _ := orm.NewSqliteDB("") if err := db.AutoMigrate(&appmodels.Application{}, &models.Cluster{}, ®ionmodels.Region{}, &membermodels.Member{}, ®istrymodels.Registry{}, - &prmodels.Pipelinerun{}, &groupmodels.Group{}, - &usermodel.User{}, &prmodels.Check{}); err != nil { + &prmodels.Pipelinerun{}, &groupmodels.Group{}, &prmodels.Check{}, + &usermodel.User{}); err != nil { panic(err) } param := managerparam.InitManager(db) @@ -41,17 +41,6 @@ func TestCreatePipelineRun(t *testing.T) { Name: "Tony", ID: uint(1), }) - // request for build deploy - r := &CreatePipelineRunRequest{ - Action: prmodels.ActionBuildDeploy, - Title: "test", - Description: "test", - Git: &BuildDeployRequestGit{ - Commit: "test", - }, - PipelinerunID: 1, - } - mockCtl := gomock.NewController(t) mockGitGetter := mock_code.NewMockGitGetter(mockCtl) mockGitGetter.EXPECT().GetCommit(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). @@ -109,6 +98,53 @@ func TestCreatePipelineRun(t *testing.T) { }, nil, nil) assert.NoError(t, err) - _, err = controller.CreatePipelineRun(ctx, clusterGit.ID, r) + // request for build deploy + requestBuildDeploy := &CreatePipelineRunRequest{ + Action: prmodels.ActionBuildDeploy, + Title: "test", + Description: "test", + Git: &BuildDeployRequestGit{ + Commit: "test", + }, + } + pipelineBuildDeploy, err := controller.CreatePipelineRun(ctx, clusterGit.ID, requestBuildDeploy) + assert.NoError(t, err) + assert.Equal(t, "ready", pipelineBuildDeploy.Status) + + mockClusterGitRepo.EXPECT().GetCluster(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(&clustergitrepo.ClusterFiles{ + PipelineJSONBlob: map[string]interface{}{}, + ApplicationJSONBlob: map[string]interface{}{}, + }, nil) + mockClusterGitRepo.EXPECT().CompareConfig(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return("diff", nil) + requestDeploy := &CreatePipelineRunRequest{ + Action: prmodels.ActionDeploy, + Title: "test", + Description: "test", + } + pipelineDeploy, err := controller.CreatePipelineRun(ctx, clusterGit.ID, requestDeploy) + assert.NoError(t, err) + assert.Equal(t, "ready", pipelineDeploy.Status) + + requestRollback := &CreatePipelineRunRequest{ + Action: prmodels.ActionRollback, + Title: "test", + Description: "test", + PipelinerunID: pipelineBuildDeploy.ID, + } + _, err = controller.CreatePipelineRun(ctx, clusterGit.ID, requestRollback) + assert.NotNil(t, err) + + _, err = param.PRMgr.Check.Create(ctx, &prmodels.Check{ + Resource: common.Resource{ + ResourceID: group.ID, + Type: common.ResourceGroup, + }, + }) + assert.NoError(t, err) + + pipelineBuildDeployPending, err := controller.CreatePipelineRun(ctx, clusterGit.ID, requestBuildDeploy) assert.NoError(t, err) + assert.Equal(t, "pending", pipelineBuildDeployPending.Status) } diff --git a/core/controller/cluster/models_basic_v2.go b/core/controller/cluster/models_basic_v2.go index e3c5fbfdb..2c5b97eda 100644 --- a/core/controller/cluster/models_basic_v2.go +++ b/core/controller/cluster/models_basic_v2.go @@ -243,7 +243,8 @@ type CreatePipelineRunRequest struct { Description string `json:"description"` Action string `json:"action"` // for build deploy - Git *BuildDeployRequestGit `json:"git,omitempty"` - ImageTag string `json:"imageTag,omitempty"` - PipelinerunID uint `json:"pipelinerunID,omitempty"` + Git *BuildDeployRequestGit `json:"git,omitempty"` + ImageTag string `json:"imageTag,omitempty"` + // for rollback + PipelinerunID uint `json:"pipelinerunID,omitempty"` } diff --git a/core/controller/pipelinerun/controller.go b/core/controller/pipelinerun/controller.go index 749b1027f..3aea82b51 100644 --- a/core/controller/pipelinerun/controller.go +++ b/core/controller/pipelinerun/controller.go @@ -359,7 +359,11 @@ func (c *controller) Execute(ctx context.Context, pipelinerunID uint, force bool return err } - if !force { + if force { + if pr.Status != string(prmodels.StatusReady) && pr.Status != string(prmodels.StatusPending) { + return perror.Wrapf(herrors.ErrParamInvalid, "pipelinerun is not ready to execute") + } + } else { if pr.Status != string(prmodels.StatusReady) { return perror.Wrapf(herrors.ErrParamInvalid, "pipelinerun is not ready to execute") } @@ -467,6 +471,14 @@ func (c *controller) execute(ctx context.Context, pr *models.Pipelinerun) error func (c *controller) Cancel(ctx context.Context, pipelinerunID uint) error { const op = "pipelinerun controller: cancel pipelinerun" defer wlog.Start(ctx, op).StopPrint() + pr, err := c.prMgr.PipelineRun.GetByID(ctx, pipelinerunID) + if err != nil { + return err + } + + if pr.Status != string(prmodels.StatusPending) && pr.Status != string(prmodels.StatusReady) { + return perror.Wrapf(herrors.ErrParamInvalid, "pipelinerun is not pending or ready to cancel") + } return c.prMgr.PipelineRun.UpdateStatusByID(ctx, pipelinerunID, prmodels.StatusCancelled) } @@ -486,7 +498,7 @@ func (c *controller) CreateCheckRun(ctx context.Context, pipelineRunID uint, CheckID: request.CheckID, Status: models.String2CheckRunStatus(request.Status), Message: request.Message, - PipilineRunID: pipelineRunID, + PipelineRunID: pipelineRunID, DetailURL: request.DetailURL, }) } @@ -505,6 +517,7 @@ func (c *controller) CreatePRMessage(ctx context.Context, pipelineRunID uint, PipelineRunID: pipelineRunID, Content: request.Content, CreatedBy: currentUser.GetID(), + UpdatedBy: currentUser.GetID(), }) } diff --git a/core/controller/pipelinerun/controller_test.go b/core/controller/pipelinerun/controller_test.go index f7f76b710..b31a932c9 100644 --- a/core/controller/pipelinerun/controller_test.go +++ b/core/controller/pipelinerun/controller_test.go @@ -20,6 +20,7 @@ import ( "os" "strconv" "testing" + "time" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" @@ -39,9 +40,11 @@ import ( applicationmodel "github.com/horizoncd/horizon/pkg/application/models" userauth "github.com/horizoncd/horizon/pkg/authentication/user" codemodels "github.com/horizoncd/horizon/pkg/cluster/code" + clustergitrepo "github.com/horizoncd/horizon/pkg/cluster/gitrepo" clustermodel "github.com/horizoncd/horizon/pkg/cluster/models" "github.com/horizoncd/horizon/pkg/cluster/tekton/collector" "github.com/horizoncd/horizon/pkg/cluster/tekton/log" + "github.com/horizoncd/horizon/pkg/config/token" envmodels "github.com/horizoncd/horizon/pkg/environmentregion/models" "github.com/horizoncd/horizon/pkg/git" groupmodels "github.com/horizoncd/horizon/pkg/group/models" @@ -51,6 +54,10 @@ import ( "github.com/horizoncd/horizon/pkg/pr/models" prmodels "github.com/horizoncd/horizon/pkg/pr/models" prservice "github.com/horizoncd/horizon/pkg/pr/service" + regionmodels "github.com/horizoncd/horizon/pkg/region/models" + registrymodels "github.com/horizoncd/horizon/pkg/registry/models" + trmodels "github.com/horizoncd/horizon/pkg/templaterelease/models" + tokenservice "github.com/horizoncd/horizon/pkg/token/service" pipelinemodel "github.com/horizoncd/horizon/pkg/pr/models" usermodel "github.com/horizoncd/horizon/pkg/user/models" @@ -386,3 +393,206 @@ func Test(t *testing.T) { err = c.StopPipelinerunForCluster(ctx, pipelinerun.ClusterID) assert.Nil(t, err) } + +func TestExecutePipelineRun(t *testing.T) { + db, _ := orm.NewSqliteDB("") + if err := db.AutoMigrate(&applicationmodel.Application{}, &clustermodel.Cluster{}, + ®ionmodels.Region{}, &membermodels.Member{}, ®istrymodels.Registry{}, + &prmodels.Pipelinerun{}, &groupmodels.Group{}, &prmodels.Check{}, + &usermodel.User{}, &trmodels.TemplateRelease{}); err != nil { + panic(err) + } + param := managerparam.InitManager(db) + ctx := context.Background() + // nolint + ctx = context.WithValue(ctx, common.UserContextKey(), &userauth.DefaultInfo{ + Name: "Tony", + ID: uint(1), + }) + mockCtl := gomock.NewController(t) + + mockTektonInterface := tektonmock.NewMockInterface(mockCtl) + + mockFactory := tektonftymock.NewMockFactory(mockCtl) + mockFactory.EXPECT().GetTekton(gomock.Any()).Return(mockTektonInterface, nil).AnyTimes() + tokenConfig := token.Config{ + JwtSigningKey: "hello", + CallbackTokenExpireIn: 24 * time.Hour, + } + + mockClusterGitRepo := clustergitrepomock.NewMockClusterGitRepo(mockCtl) + + ctrl := controller{ + prMgr: param.PRMgr, + appMgr: param.ApplicationMgr, + clusterMgr: param.ClusterMgr, + envMgr: param.EnvMgr, + regionMgr: param.RegionMgr, + tektonFty: mockFactory, + tokenSvc: tokenservice.NewService(param, tokenConfig), + tokenConfig: tokenConfig, + clusterGitRepo: mockClusterGitRepo, + templateReleaseMgr: param.TemplateReleaseMgr, + } + + _, err := param.UserMgr.Create(ctx, &usermodel.User{ + Name: "Tony", + }) + assert.NoError(t, err) + + group, err := param.GroupMgr.Create(ctx, &groupmodels.Group{ + Name: "test", + }) + assert.NoError(t, err) + + app, err := param.ApplicationMgr.Create(ctx, &applicationmodel.Application{ + Name: "test", + GroupID: group.ID, + }, nil) + assert.NoError(t, err) + + registryID, err := param.RegistryMgr.Create(ctx, ®istrymodels.Registry{ + Name: "test", + }) + assert.NoError(t, err) + + region, err := param.RegionMgr.Create(ctx, ®ionmodels.Region{ + Name: "test", + RegistryID: registryID, + }) + assert.NoError(t, err) + + cluster, err := param.ClusterMgr.Create(ctx, &clustermodel.Cluster{ + Name: "clusterGit", + ApplicationID: app.ID, + GitURL: "hello", + RegionName: region.Name, + Template: "javaapp", + TemplateRelease: "v1.0.0", + }, nil, nil) + assert.NoError(t, err) + + _, err = param.TemplateReleaseMgr.Create(ctx, &trmodels.TemplateRelease{ + TemplateName: "javaapp", + Name: "v1.0.0", + }) + assert.NoError(t, err) + + mockClusterGitRepo.EXPECT().GetCluster(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(&clustergitrepo.ClusterFiles{ + PipelineJSONBlob: map[string]interface{}{}, + ApplicationJSONBlob: map[string]interface{}{}, + }, nil).AnyTimes() + + mockTektonInterface.EXPECT().CreatePipelineRun(ctx, gomock.Any()).Return("hello", nil).AnyTimes() + + PRPending, err := param.PRMgr.PipelineRun.Create(ctx, &prmodels.Pipelinerun{ + ClusterID: cluster.ID, + Status: string(pipelinemodel.StatusPending), + }) + assert.NoError(t, err) + assert.Equal(t, string(pipelinemodel.StatusPending), PRPending.Status) + + PRReady, err := param.PRMgr.PipelineRun.Create(ctx, &prmodels.Pipelinerun{ + ClusterID: cluster.ID, + Status: string(pipelinemodel.StatusReady), + }) + assert.NoError(t, err) + assert.Equal(t, string(pipelinemodel.StatusReady), PRReady.Status) + + err = ctrl.Execute(ctx, PRReady.ID, false) + assert.NoError(t, err) + + err = ctrl.Execute(ctx, PRPending.ID, false) + assert.NotNil(t, err) + + err = ctrl.Execute(ctx, PRPending.ID, true) + assert.NoError(t, err) + + PRCancel, err := param.PRMgr.PipelineRun.Create(ctx, &prmodels.Pipelinerun{ + ClusterID: cluster.ID, + Status: string(pipelinemodel.StatusPending), + }) + assert.NoError(t, err) + + err = ctrl.Cancel(ctx, PRCancel.ID) + assert.NoError(t, err) + + err = ctrl.Cancel(ctx, PRReady.ID) + assert.NotNil(t, err) +} + +func TestCheckRun(t *testing.T) { + db, _ := orm.NewSqliteDB("") + if err := db.AutoMigrate(&prmodels.CheckRun{}); err != nil { + panic(err) + } + param := managerparam.InitManager(db) + ctx := context.Background() + // nolint + ctx = context.WithValue(ctx, common.UserContextKey(), &userauth.DefaultInfo{ + Name: "Tony", + ID: uint(1), + }) + + ctrl := controller{ + prMgr: param.PRMgr, + } + + _, err := ctrl.CreateCheckRun(ctx, 1, &CreateCheckRunRequest{ + Name: "test", + Status: string(prmodels.CheckStatusQueue), + Message: "hello", + DetailURL: "https://www.google.com", + }) + assert.NoError(t, err) + + checkRuns, err := ctrl.ListCheckRuns(ctx, 1) + assert.NoError(t, err) + assert.Equal(t, len(checkRuns), 1) +} + +func TestMessage(t *testing.T) { + db, _ := orm.NewSqliteDB("") + if err := db.AutoMigrate(&prmodels.PRMessage{}, &usermodel.User{}); err != nil { + panic(err) + } + param := managerparam.InitManager(db) + ctx := context.Background() + // nolint + ctx = context.WithValue(ctx, common.UserContextKey(), &userauth.DefaultInfo{ + Name: "Tony", + ID: uint(1), + }) + + _, err := param.UserMgr.Create(ctx, &usermodel.User{ + Name: "Tony", + }) + assert.NoError(t, err) + + ctrl := controller{ + prMgr: param.PRMgr, + userMgr: param.UserMgr, + } + + message1, err := ctrl.CreatePRMessage(ctx, 1, &CreatePrMessageRequest{ + Content: "first", + }) + assert.NoError(t, err) + assert.Equal(t, message1.Content, "first") + + time.Sleep(time.Second) + + message2, err := ctrl.CreatePRMessage(ctx, 1, &CreatePrMessageRequest{ + Content: "second", + }) + assert.NoError(t, err) + assert.Equal(t, message2.Content, "second") + + count, messages, err := ctrl.ListPRMessages(ctx, 1, &q.Query{}) + assert.NoError(t, err) + assert.Equal(t, count, 2) + assert.Equal(t, len(messages), 2) + assert.Equal(t, messages[0].Content, "first") + assert.Equal(t, messages[1].Content, "second") +} diff --git a/pkg/pr/dao/check.go b/pkg/pr/dao/check.go index 423e2aa33..462eb556f 100644 --- a/pkg/pr/dao/check.go +++ b/pkg/pr/dao/check.go @@ -28,7 +28,7 @@ func NewCheckDAO(db *gorm.DB) CheckDAO { } func (d *checkDAO) Create(ctx context.Context, check *models.Check) (*models.Check, error) { - result := d.db.WithContext(ctx).Create(check) + result := d.db.WithContext(ctx).Debug().Create(check) if result.Error != nil { return nil, herrors.NewErrInsertFailed(herrors.CheckInDB, result.Error.Error()) @@ -49,7 +49,7 @@ func (d *checkDAO) UpdateByID(ctx context.Context, checkRunID uint, newCheckRun func (d *checkDAO) GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) { var checks []*models.Check - sql := d.db.WithContext(ctx) + sql := d.db.WithContext(ctx).Debug() if len(resources) == 0 { return []*models.Check{}, nil } diff --git a/pkg/pr/manager/check_test.go b/pkg/pr/manager/check_test.go index 1872052ce..7b687cd19 100644 --- a/pkg/pr/manager/check_test.go +++ b/pkg/pr/manager/check_test.go @@ -28,7 +28,7 @@ func TestCheck(t *testing.T) { // Test UpdateByID checkRun := &models.CheckRun{ - PipilineRunID: 10, + PipelineRunID: 10, CheckID: createdCheck.ResourceID, Status: models.CheckStatusQueue, } @@ -50,7 +50,7 @@ func TestCheck(t *testing.T) { assert.Len(t, checks, 1) // Test ListCheckRuns - checkRuns, err := checkManager.ListCheckRuns(ctx, checkRun.PipilineRunID) + checkRuns, err := checkManager.ListCheckRuns(ctx, checkRun.PipelineRunID) assert.NoError(t, err) assert.Len(t, checkRuns, 1) assert.Equal(t, checkRuns[0].Status, models.CheckStatusInProgress) diff --git a/pkg/pr/models/check.go b/pkg/pr/models/check.go index d7afa8df4..46aacf124 100644 --- a/pkg/pr/models/check.go +++ b/pkg/pr/models/check.go @@ -34,7 +34,7 @@ func String2CheckRunStatus(s string) CheckRunStatus { type Check struct { global.Model - common.Resource `json:",inline" gorm:"embedded"` + common.Resource `json:",inline"` } type CheckRun struct { @@ -43,7 +43,7 @@ type CheckRun struct { CheckID uint `json:"checkId"` Status CheckRunStatus `json:"status"` Message string `json:"message"` - PipilineRunID uint `gorm:"column:pipeline_run_id" json:"pipelineRunId"` + PipelineRunID uint `gorm:"column:pipeline_run_id" json:"pipelineRunId"` DetailURL string `gorm:"column:detail_url" json:"detailUrl"` } diff --git a/pkg/templaterelease/dao/dao.go b/pkg/templaterelease/dao/dao.go index 7a43c8db7..c64d7ac62 100644 --- a/pkg/templaterelease/dao/dao.go +++ b/pkg/templaterelease/dao/dao.go @@ -18,6 +18,8 @@ import ( "context" "fmt" + "gorm.io/gorm" + herrors "github.com/horizoncd/horizon/core/errors" amodels "github.com/horizoncd/horizon/pkg/application/models" cmodel "github.com/horizoncd/horizon/pkg/cluster/models" @@ -25,7 +27,6 @@ import ( hctx "github.com/horizoncd/horizon/pkg/context" perror "github.com/horizoncd/horizon/pkg/errors" "github.com/horizoncd/horizon/pkg/templaterelease/models" - "gorm.io/gorm" ) type DAO interface { @@ -51,7 +52,7 @@ func (d dao) Create(ctx context.Context, templateRelease *models.TemplateRelease result := d.db.WithContext(ctx).Create(templateRelease) if result.Error != nil { - return nil, herrors.NewErrCreateFailed(herrors.GroupInDB, result.Error.Error()) + return nil, herrors.NewErrCreateFailed(herrors.TemplateReleaseInDB, result.Error.Error()) } return templateRelease, nil } From 6d40918d137550812a9d916903237266a38a73c2 Mon Sep 17 00:00:00 2001 From: "xu.zhu" Date: Fri, 15 Sep 2023 14:54:24 +0800 Subject: [PATCH 06/11] feat: support for external approval Signed-off-by: xu.zhu --- core/common/pipelinerun.go | 10 +- .../controller/cluster/controller_basic_v2.go | 15 ++ .../cluster/controller_internal_v2.go | 6 +- core/controller/pipelinerun/controller.go | 133 +++++++++++++++--- .../controller/pipelinerun/controller_test.go | 7 +- core/controller/pipelinerun/models.go | 13 +- core/http/api/v2/pipelinerun/apis.go | 107 +++++++++++--- core/http/api/v2/pipelinerun/routers.go | 18 ++- pkg/event/manager/manager.go | 1 + pkg/event/models/event.go | 1 + pkg/eventhandler/wlgenerator/wlgenerator.go | 66 ++++++++- pkg/pr/dao/check.go | 42 +++++- pkg/pr/dao/pipelinerun.go | 8 +- pkg/pr/manager/check.go | 15 +- pkg/pr/manager/check_test.go | 6 +- pkg/pr/service/service.go | 6 +- 16 files changed, 389 insertions(+), 65 deletions(-) diff --git a/core/common/pipelinerun.go b/core/common/pipelinerun.go index 36f9db62f..c7cdbd758 100644 --- a/core/common/pipelinerun.go +++ b/core/common/pipelinerun.go @@ -1,3 +1,11 @@ package common -const PipelineQueryByStatus = "status" +const ( + PipelineQueryByStatus = "status" + + CheckrunQueryFilter = "filter" + CheckrunQueryByStatus = "status" + CheckrunQueryByPipelinerunID = "pipelinerunID" + CheckrunQueryByCheckID = "checkID" + CheckrunQueryByDetailURL = "detailURL" +) diff --git a/core/controller/cluster/controller_basic_v2.go b/core/controller/cluster/controller_basic_v2.go index eb05fa9f1..9486e33c8 100644 --- a/core/controller/cluster/controller_basic_v2.go +++ b/core/controller/cluster/controller_basic_v2.go @@ -685,6 +685,8 @@ func (c *controller) CreatePipelineRun(ctx context.Context, clusterID uint, return nil, err } + c.recordPipelinerunCreatedEvent(ctx, pipelineRun) + firstCanRollbackPipelinerun, err := c.prMgr.PipelineRun.GetFirstCanRollbackPipelinerun(ctx, pipelineRun.ClusterID) if err != nil { return nil, err @@ -828,3 +830,16 @@ func (c *controller) createPipelineRun(ctx context.Context, clusterID uint, ConfigCommit: configCommitSHA, }, nil } + +func (c *controller) recordPipelinerunCreatedEvent(ctx context.Context, pr *prmodels.Pipelinerun) { + _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ + EventSummary: eventmodels.EventSummary{ + ResourceID: pr.ID, + ResourceType: common.ResourcePipelinerun, + EventType: eventmodels.PipelinerunCreated, + }, + }) + if err != nil { + log.Warningf(ctx, "failed to create event, err: %s", err.Error()) + } +} diff --git a/core/controller/cluster/controller_internal_v2.go b/core/controller/cluster/controller_internal_v2.go index 5faa31821..cc18ee353 100644 --- a/core/controller/cluster/controller_internal_v2.go +++ b/core/controller/cluster/controller_internal_v2.go @@ -178,8 +178,8 @@ func (c *controller) InternalDeployV2(ctx context.Context, clusterID uint, return nil, err } - // 10. record event - c.recordEvent(ctx, pr, cluster) + // 10. record cluster event + c.recordClusterEvent(ctx, pr, cluster) return &InternalDeployResponseV2{ PipelinerunID: pr.ID, @@ -187,7 +187,7 @@ func (c *controller) InternalDeployV2(ctx context.Context, clusterID uint, }, nil } -func (c *controller) recordEvent(ctx context.Context, pr *prmodels.Pipelinerun, cluster *models.Cluster) { +func (c *controller) recordClusterEvent(ctx context.Context, pr *prmodels.Pipelinerun, cluster *models.Cluster) { _, err := c.eventMgr.CreateEvent(ctx, &eventmodels.Event{ EventSummary: eventmodels.EventSummary{ ResourceType: common.ResourceCluster, diff --git a/core/controller/pipelinerun/controller.go b/core/controller/pipelinerun/controller.go index 3aea82b51..896688a21 100644 --- a/core/controller/pipelinerun/controller.go +++ b/core/controller/pipelinerun/controller.go @@ -19,6 +19,7 @@ import ( "fmt" "net/http" "strconv" + "time" "github.com/horizoncd/horizon/core/common" "github.com/horizoncd/horizon/core/config" @@ -38,7 +39,6 @@ import ( membermanager "github.com/horizoncd/horizon/pkg/member" "github.com/horizoncd/horizon/pkg/param" prmanager "github.com/horizoncd/horizon/pkg/pr/manager" - "github.com/horizoncd/horizon/pkg/pr/models" prmodels "github.com/horizoncd/horizon/pkg/pr/models" prservice "github.com/horizoncd/horizon/pkg/pr/service" regionmanager "github.com/horizoncd/horizon/pkg/region/manager" @@ -61,19 +61,20 @@ type Controller interface { StopPipelinerun(ctx context.Context, pipelinerunID uint) error StopPipelinerunForCluster(ctx context.Context, clusterID uint) error - CreateCheck(ctx context.Context, check *models.Check) (*models.Check, error) - UpdateCheckRunByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error + CreateCheck(ctx context.Context, check *prmodels.Check) (*prmodels.Check, error) + GetCheckRunByID(ctx context.Context, checkRunID uint) (*prmodels.CheckRun, error) + UpdateCheckRunByID(ctx context.Context, checkRunID uint, request *CreateOrUpdateCheckRunRequest) error - ListMessagesByPipelinerun(ctx context.Context, pipelinerunID uint, query *q.Query) (int, []*models.PRMessage, error) + ListMessagesByPipelinerun(ctx context.Context, pipelinerunID uint, query *q.Query) (int, []*prmodels.PRMessage, error) // Execute runs a pipelineRun only if its state is ready. Execute(ctx context.Context, pipelinerunID uint, force bool) error // Cancel withdraws a pipelineRun only if its state is pending. Cancel(ctx context.Context, pipelinerunID uint) error - ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) - CreateCheckRun(ctx context.Context, pipelineRunID uint, request *CreateCheckRunRequest) (*models.CheckRun, error) + ListCheckRuns(ctx context.Context, q *q.Query) ([]*prmodels.CheckRun, error) + CreateCheckRun(ctx context.Context, pipelineRunID uint, request *CreateOrUpdateCheckRunRequest) (*prmodels.CheckRun, error) ListPRMessages(ctx context.Context, pipelineRunID uint, q *q.Query) (int, []*PrMessage, error) - CreatePRMessage(ctx context.Context, pipelineRunID uint, request *CreatePrMessageRequest) (*models.PRMessage, error) + CreatePRMessage(ctx context.Context, pipelineRunID uint, request *CreatePrMessageRequest) (*prmodels.PRMessage, error) } type controller struct { @@ -328,22 +329,31 @@ func (c *controller) StopPipelinerunForCluster(ctx context.Context, clusterID ui return tektonClient.StopPipelineRun(ctx, pipelinerun.CIEventID) } -func (c *controller) CreateCheck(ctx context.Context, check *models.Check) (*models.Check, error) { +func (c *controller) CreateCheck(ctx context.Context, check *prmodels.Check) (*prmodels.Check, error) { const op = "pipelinerun controller: create check" defer wlog.Start(ctx, op).StopPrint() return c.prMgr.Check.Create(ctx, check) } -func (c *controller) UpdateCheckRunByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error { +func (c *controller) UpdateCheckRunByID(ctx context.Context, checkRunID uint, request *CreateOrUpdateCheckRunRequest) error { const op = "pipelinerun controller: update check run" defer wlog.Start(ctx, op).StopPrint() - return c.prMgr.Check.UpdateByID(ctx, checkRunID, newCheckRun) + err := c.prMgr.Check.UpdateByID(ctx, checkRunID, &prmodels.CheckRun{ + Name: request.Name, + Status: prmodels.String2CheckRunStatus(request.Status), + Message: request.Message, + DetailURL: request.DetailURL, + }) + if err != nil { + return err + } + return c.updatePrStatusByCheckrunID(ctx, checkRunID) } func (c *controller) ListMessagesByPipelinerun(ctx context.Context, - pipelinerunID uint, query *q.Query) (int, []*models.PRMessage, error) { + pipelinerunID uint, query *q.Query) (int, []*prmodels.PRMessage, error) { const op = "pipelinerun controller: list pr message" defer wlog.Start(ctx, op).StopPrint() @@ -372,7 +382,7 @@ func (c *controller) Execute(ctx context.Context, pipelinerunID uint, force bool return c.execute(ctx, pr) } -func (c *controller) execute(ctx context.Context, pr *models.Pipelinerun) error { +func (c *controller) execute(ctx context.Context, pr *prmodels.Pipelinerun) error { currentUser, err := common.UserFromContext(ctx) if err != nil { return err @@ -456,6 +466,7 @@ func (c *controller) execute(ctx context.Context, pr *models.Pipelinerun) error err = c.prMgr.PipelineRun.UpdateColumns(ctx, pr.ID, map[string]interface{}{ "ci_event_id": ciEventID, "status": prmodels.StatusRunning, + "started_at": time.Now(), }) if err != nil { return err @@ -482,29 +493,43 @@ func (c *controller) Cancel(ctx context.Context, pipelinerunID uint) error { return c.prMgr.PipelineRun.UpdateStatusByID(ctx, pipelinerunID, prmodels.StatusCancelled) } -func (c *controller) ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) { +func (c *controller) ListCheckRuns(ctx context.Context, query *q.Query) ([]*prmodels.CheckRun, error) { const op = "pipelinerun controller: list check runs" defer wlog.Start(context.Background(), op).StopPrint() - return c.prMgr.Check.ListCheckRuns(ctx, pipelineRunID) + return c.prMgr.Check.ListCheckRuns(ctx, query) +} + +func (c *controller) GetCheckRunByID(ctx context.Context, checkRunID uint) (*prmodels.CheckRun, error) { + const op = "pipelinerun controller: get check run by id" + defer wlog.Start(context.Background(), op).StopPrint() + return c.prMgr.Check.GetCheckRunByID(ctx, checkRunID) } func (c *controller) CreateCheckRun(ctx context.Context, pipelineRunID uint, - request *CreateCheckRunRequest) (*models.CheckRun, error) { + request *CreateOrUpdateCheckRunRequest) (*prmodels.CheckRun, error) { const op = "pipelinerun controller: create check run" defer wlog.Start(context.Background(), op).StopPrint() - return c.prMgr.Check.CreateCheckRun(ctx, &models.CheckRun{ + checkrun, err := c.prMgr.Check.CreateCheckRun(ctx, &prmodels.CheckRun{ Name: request.Name, CheckID: request.CheckID, - Status: models.String2CheckRunStatus(request.Status), + Status: prmodels.String2CheckRunStatus(request.Status), Message: request.Message, PipelineRunID: pipelineRunID, DetailURL: request.DetailURL, }) + if err != nil { + return nil, err + } + err = c.updatePrStatus(ctx, checkrun) + if err != nil { + return nil, err + } + return checkrun, nil } func (c *controller) CreatePRMessage(ctx context.Context, pipelineRunID uint, - request *CreatePrMessageRequest) (*models.PRMessage, error) { + request *CreatePrMessageRequest) (*prmodels.PRMessage, error) { const op = "pipelinerun controller: create pr message" defer wlog.Start(context.Background(), op).StopPrint() @@ -513,7 +538,7 @@ func (c *controller) CreatePRMessage(ctx context.Context, pipelineRunID uint, return nil, err } - return c.prMgr.Message.Create(ctx, &models.PRMessage{ + return c.prMgr.Message.Create(ctx, &prmodels.PRMessage{ PipelineRunID: pipelineRunID, Content: request.Content, CreatedBy: currentUser.GetID(), @@ -582,3 +607,73 @@ func (c *controller) ListPRMessages(ctx context.Context, } return count, result, nil } + +func (c *controller) updatePrStatusByCheckrunID(ctx context.Context, checkrunID uint) error { + Checkrun, err := c.prMgr.Check.GetCheckRunByID(ctx, checkrunID) + if err != nil { + return err + } + return c.updatePrStatus(ctx, Checkrun) +} + +func (c *controller) updatePrStatus(ctx context.Context, checkrun *prmodels.CheckRun) error { + pipelinerun, err := c.prMgr.PipelineRun.GetByID(ctx, checkrun.PipelineRunID) + if err != nil { + return err + } + if pipelinerun.Status != string(prmodels.StatusPending) { + return nil + } + prStatus, err := func() (prmodels.PipelineStatus, error) { + switch checkrun.Status { + case prmodels.CheckStatusCancelled: + return prmodels.StatusCancelled, nil + case prmodels.CheckStatusFailure: + return prmodels.StatusFailed, nil + case prmodels.CheckStatusSuccess: + return c.calculatePrSuccessStatus(ctx, pipelinerun) + default: + return prmodels.StatusPending, nil + } + }() + if err != nil { + return err + } + if prStatus == prmodels.StatusPending { + return nil + } + return c.prMgr.PipelineRun.UpdateStatusByID(ctx, checkrun.PipelineRunID, prStatus) +} + +func (c *controller) calculatePrSuccessStatus(ctx context.Context, + pipelinerun *prmodels.Pipelinerun) (prmodels.PipelineStatus, error) { + cluster, err := c.clusterMgr.GetByIDIncludeSoftDelete(ctx, pipelinerun.ClusterID) + if err != nil { + return prmodels.StatusPending, err + } + checks, err := c.prSvc.GetCheckByResource(ctx, cluster.ID, common.ResourceCluster) + if err != nil { + return prmodels.StatusPending, err + } + runs, err := c.prMgr.Check.ListCheckRuns(ctx, q.New(map[string]interface{}{ + common.CheckrunQueryByPipelinerunID: pipelinerun.ID}, + )) + if err != nil { + return prmodels.StatusPending, err + } + checkSuccessMap := make(map[uint]bool, len(checks)) + for _, run := range runs { + if run.Status != prmodels.CheckStatusSuccess { + // if one checkrun is not success, return pending + return prmodels.StatusPending, nil + } + checkSuccessMap[run.CheckID] = true + } + for _, check := range checks { + if _, ok := checkSuccessMap[check.ID]; !ok { + // if one check is not run, return pending + return prmodels.StatusPending, nil + } + } + return prmodels.StatusReady, nil +} diff --git a/core/controller/pipelinerun/controller_test.go b/core/controller/pipelinerun/controller_test.go index b31a932c9..6061d130e 100644 --- a/core/controller/pipelinerun/controller_test.go +++ b/core/controller/pipelinerun/controller_test.go @@ -539,7 +539,7 @@ func TestCheckRun(t *testing.T) { prMgr: param.PRMgr, } - _, err := ctrl.CreateCheckRun(ctx, 1, &CreateCheckRunRequest{ + _, err := ctrl.CreateCheckRun(ctx, 1, &CreateOrUpdateCheckRunRequest{ Name: "test", Status: string(prmodels.CheckStatusQueue), Message: "hello", @@ -547,7 +547,10 @@ func TestCheckRun(t *testing.T) { }) assert.NoError(t, err) - checkRuns, err := ctrl.ListCheckRuns(ctx, 1) + keyWords := make(map[string]interface{}) + keyWords[common.CheckrunQueryByPipelinerunID] = 1 + query := q.New(keyWords) + checkRuns, err := ctrl.ListCheckRuns(ctx, query) assert.NoError(t, err) assert.Equal(t, len(checkRuns), 1) } diff --git a/core/controller/pipelinerun/models.go b/core/controller/pipelinerun/models.go index 7cd2e763e..ec7b6b4c7 100644 --- a/core/controller/pipelinerun/models.go +++ b/core/controller/pipelinerun/models.go @@ -63,10 +63,11 @@ type PrMessage struct { CreatedAt time.Time `json:"createdAt"` } -type CreateCheckRunRequest struct { - Name string `json:"name"` - CheckID uint `json:"checkId"` - Status string `json:"status"` - Message string `json:"message"` - DetailURL string `json:"detailUrl"` +type CreateOrUpdateCheckRunRequest struct { + Name string `json:"name"` + CheckID uint `json:"checkId"` + Status string `json:"status"` + Message string `json:"message"` + ExternalID string `json:"externalId"` + DetailURL string `json:"detailUrl"` } diff --git a/core/http/api/v2/pipelinerun/apis.go b/core/http/api/v2/pipelinerun/apis.go index 07f5a9271..f6bcaad1b 100644 --- a/core/http/api/v2/pipelinerun/apis.go +++ b/core/http/api/v2/pipelinerun/apis.go @@ -34,6 +34,7 @@ import ( const ( _pipelinerunIDParam = "pipelinerunID" + _checkrunIDParam = "checkrunID" _clusterIDParam = "clusterID" _canRollbackParam = "canRollback" _pipelineStatus = "status" @@ -50,7 +51,7 @@ func NewAPI(prCtl prctl.Controller) *API { } func (a *API) Log(c *gin.Context) { - a.withID(c, func(prID uint) { + a.withPipelinerunID(c, func(prID uint) { l, err := a.prCtl.GetPipelinerunLog(c, uint(prID)) if err != nil { l := &collector.Log{ @@ -95,7 +96,7 @@ func (a *API) writeLog(c *gin.Context, l *collector.Log) { } func (a *API) GetDiff(c *gin.Context) { - a.withID(c, func(pipelinerunID uint) { + a.withPipelinerunID(c, func(pipelinerunID uint) { diff, err := a.prCtl.GetDiff(c, uint(pipelinerunID)) if err != nil { response.AbortWithError(c, err) @@ -106,7 +107,7 @@ func (a *API) GetDiff(c *gin.Context) { } func (a *API) Get(c *gin.Context) { - a.withID(c, func(pipelinerunID uint) { + a.withPipelinerunID(c, func(pipelinerunID uint) { resp, err := a.prCtl.GetPipelinerun(c, uint(pipelinerunID)) if err != nil { response.AbortWithError(c, err) @@ -158,7 +159,7 @@ func (a *API) List(c *gin.Context) { } func (a *API) Stop(c *gin.Context) { - a.withID(c, func(prID uint) { + a.withPipelinerunID(c, func(prID uint) { err := a.prCtl.StopPipelinerun(c, uint(prID)) if err != nil { response.AbortWithError(c, err) @@ -177,7 +178,7 @@ func (a *API) Execute(c *gin.Context) { } func (a *API) execute(c *gin.Context, force bool) { - a.withID(c, func(prID uint) { + a.withPipelinerunID(c, func(prID uint) { err := a.prCtl.Execute(c, prID, force) if err != nil { if e, ok := perror.Cause(err).(*herrors.HorizonErrNotFound); ok { @@ -192,7 +193,7 @@ func (a *API) execute(c *gin.Context, force bool) { } func (a *API) Cancel(c *gin.Context) { - a.withID(c, func(prID uint) { + a.withPipelinerunID(c, func(prID uint) { err := a.prCtl.Cancel(c, prID) if err != nil { response.AbortWithError(c, err) @@ -203,29 +204,56 @@ func (a *API) Cancel(c *gin.Context) { } func (a *API) ListCheckRuns(c *gin.Context) { - a.withID(c, func(prID uint) { - checkRuns, err := a.prCtl.ListCheckRuns(c, prID) + query := parseContext(c) + checkRuns, err := a.prCtl.ListCheckRuns(c, query) + if err != nil { + response.AbortWithError(c, err) + return + } + response.SuccessWithData(c, checkRuns) + +} + +func (a *API) CreateCheckRun(c *gin.Context) { + var req prctl.CreateOrUpdateCheckRunRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) + return + } + a.withPipelinerunID(c, func(prID uint) { + checkrun, err := a.prCtl.CreateCheckRun(c, prID, &req) if err != nil { response.AbortWithError(c, err) return } - response.SuccessWithData(c, checkRuns) + response.SuccessWithData(c, checkrun) }) } -func (a *API) CreateCheckRuns(c *gin.Context) { - var req prctl.CreateCheckRunRequest +func (a *API) GetCheckRun(c *gin.Context) { + a.withCheckrunID(c, func(id uint) { + checkrun, err := a.prCtl.GetCheckRunByID(c, id) + if err != nil { + response.AbortWithError(c, err) + return + } + response.SuccessWithData(c, checkrun) + }) +} + +func (a *API) UpdateCheckRun(c *gin.Context) { + var req prctl.CreateOrUpdateCheckRunRequest if err := c.ShouldBindJSON(&req); err != nil { response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) return } - a.withID(c, func(prID uint) { - checkrun, err := a.prCtl.CreateCheckRun(c, prID, &req) + a.withCheckrunID(c, func(id uint) { + err := a.prCtl.UpdateCheckRunByID(c, id, &req) if err != nil { response.AbortWithError(c, err) return } - response.SuccessWithData(c, checkrun) + response.Success(c) }) } @@ -236,7 +264,7 @@ func (a *API) CreatePrMessage(c *gin.Context) { return } - a.withID(c, func(prID uint) { + a.withPipelinerunID(c, func(prID uint) { checkMessage, err := a.prCtl.CreatePRMessage(c, prID, &req) if err != nil { response.AbortWithError(c, err) @@ -256,7 +284,7 @@ func (a *API) ListPrMessages(c *gin.Context) { PageNumber: pageNumber, PageSize: pageSize, } - a.withID(c, func(prID uint) { + a.withPipelinerunID(c, func(prID uint) { count, messages, err := a.prCtl.ListPRMessages(c, prID, query) if err != nil { response.AbortWithError(c, err) @@ -269,7 +297,7 @@ func (a *API) ListPrMessages(c *gin.Context) { }) } -func (a *API) withID(c *gin.Context, f func(pipelineRunID uint)) { +func (a *API) withPipelinerunID(c *gin.Context, f func(pipelineRunID uint)) { idStr := c.Param(_pipelinerunIDParam) id, err := strconv.ParseUint(idStr, 10, 0) if err != nil { @@ -278,3 +306,48 @@ func (a *API) withID(c *gin.Context, f func(pipelineRunID uint)) { } f(uint(id)) } + +func (a *API) withCheckrunID(c *gin.Context, f func(pipelineRunID uint)) { + idStr := c.Param(_checkrunIDParam) + id, err := strconv.ParseUint(idStr, 10, 0) + if err != nil { + response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) + return + } + f(uint(id)) +} + +func parseContext(c *gin.Context) *q.Query { + keywords := make(map[string]interface{}) + + filter := c.Query(common.CheckrunQueryFilter) + if filter != "" { + keywords[common.CheckrunQueryFilter] = filter + } + + status := c.Query(common.CheckrunQueryByStatus) + if status != "" { + keywords[common.CheckrunQueryByStatus] = status + } + + pipelinerunIDStr := c.Query(common.CheckrunQueryByPipelinerunID) + if pipelinerunIDStr != "" { + pipelinerunID, err := strconv.ParseUint(pipelinerunIDStr, 10, 0) + if err != nil { + response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) + return nil + } + keywords[common.CheckrunQueryByPipelinerunID] = pipelinerunID + } + + checkIDStr := c.Query(common.CheckrunQueryByCheckID) + if checkIDStr != "" { + checkID, err := strconv.ParseUint(checkIDStr, 10, 0) + if err != nil { + response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) + return nil + } + keywords[common.CheckrunQueryByCheckID] = checkID + } + return q.New(keywords) +} diff --git a/core/http/api/v2/pipelinerun/routers.go b/core/http/api/v2/pipelinerun/routers.go index 3ef501f0f..eeb09c0a8 100644 --- a/core/http/api/v2/pipelinerun/routers.go +++ b/core/http/api/v2/pipelinerun/routers.go @@ -64,15 +64,25 @@ func (api *API) RegisterRoute(engine *gin.Engine) { Pattern: fmt.Sprintf("/pipelineruns/:%v/cancel", _pipelinerunIDParam), HandlerFunc: api.Cancel, }, + { + Method: http.MethodPost, + Pattern: fmt.Sprintf("/pipelineruns/:%v/checkruns", _pipelinerunIDParam), + HandlerFunc: api.CreateCheckRun, + }, { Method: http.MethodGet, - Pattern: fmt.Sprintf("/pipelineruns/:%v/checkrun", _pipelinerunIDParam), + Pattern: fmt.Sprintf("/checkruns/:%v", _checkrunIDParam), + HandlerFunc: api.GetCheckRun, + }, + { + Method: http.MethodGet, + Pattern: fmt.Sprintf("/checkruns"), HandlerFunc: api.ListCheckRuns, }, { - Method: http.MethodPost, - Pattern: fmt.Sprintf("/pipelineruns/:%v/checkrun", _pipelinerunIDParam), - HandlerFunc: api.CreateCheckRuns, + Method: http.MethodPut, + Pattern: fmt.Sprintf("/checkruns/:%v", _checkrunIDParam), + HandlerFunc: api.UpdateCheckRun, }, { Method: http.MethodGet, diff --git a/pkg/event/manager/manager.go b/pkg/event/manager/manager.go index ee0e668d3..0ed2c3219 100644 --- a/pkg/event/manager/manager.go +++ b/pkg/event/manager/manager.go @@ -137,6 +137,7 @@ var supportedEvents = map[string]string{ models.ClusterAction: "Cluster has triggered an action", models.ClusterPodsRescheduled: "Pods has been deleted to reschedule", models.ClusterKubernetesEvent: "Kubernetes event associated with cluster has been triggered", + models.PipelinerunCreated: "New pipelinerun has been created", } func (m *manager) ListSupportEvents() map[string]string { diff --git a/pkg/event/models/event.go b/pkg/event/models/event.go index b890b2a31..5d356d3ef 100644 --- a/pkg/event/models/event.go +++ b/pkg/event/models/event.go @@ -38,6 +38,7 @@ const ( ClusterFreed string = "clusters_freed" ClusterKubernetesEvent string = "clusters_kubernetes_event" ClusterAction = "clusters_action" + PipelinerunCreated string = "pipelineruns_created" // TODO: add group events ) diff --git a/pkg/eventhandler/wlgenerator/wlgenerator.go b/pkg/eventhandler/wlgenerator/wlgenerator.go index b5a66aaf3..33ea26e05 100644 --- a/pkg/eventhandler/wlgenerator/wlgenerator.go +++ b/pkg/eventhandler/wlgenerator/wlgenerator.go @@ -20,6 +20,7 @@ import ( "fmt" "net/http" + prmodels "github.com/horizoncd/horizon/pkg/pr/models" "gopkg.in/yaml.v3" "github.com/horizoncd/horizon/core/common" @@ -33,6 +34,7 @@ import ( "github.com/horizoncd/horizon/pkg/event/models" groupmanager "github.com/horizoncd/horizon/pkg/group/manager" "github.com/horizoncd/horizon/pkg/param/managerparam" + prmanager "github.com/horizoncd/horizon/pkg/pr/manager" usermanager "github.com/horizoncd/horizon/pkg/user/manager" usermodels "github.com/horizoncd/horizon/pkg/user/models" "github.com/horizoncd/horizon/pkg/util/log" @@ -53,6 +55,7 @@ type MessageContent struct { WebhookID uint `json:"webhookID,omitempty"` Application *ApplicationInfo `json:"application,omitempty"` Cluster *ClusterInfo `json:"cluster,omitempty"` + Pipelinerun *PipelinerunInfo `json:"pipelinerun,omitempty"` EventType string `json:"eventType,omitempty"` User *usermodels.UserBasic `json:"user,omitempty"` Extra *string `json:"extra,omitempty"` @@ -60,7 +63,7 @@ type MessageContent struct { type ResourceCommonInfo struct { ID uint `json:"id"` - Name string `json:"name"` + Name string `json:"name,omitempty"` } // ApplicationInfo contains basic info of application @@ -76,6 +79,18 @@ type ClusterInfo struct { Env string `json:"env,omitempty"` } +// PipelinerunInfo contains basic info of pipelinerun +type PipelinerunInfo struct { + ResourceCommonInfo + ClusterID uint `json:"clusterID,omitempty"` + ClusterName string `json:"clusterName,omitempty"` + Action string `json:"action,omitempty"` + Title string `json:"title,omitempty"` + Description string `json:"description,omitempty"` + GitRef string `json:"gitRef,omitempty"` + GitRefType string `json:"gitRefType,omitempty"` +} + // WebhookLogGenerator generates webhook logs by events type WebhookLogGenerator struct { webhookMgr webhookmanager.Manager @@ -83,6 +98,7 @@ type WebhookLogGenerator struct { groupMgr groupmanager.Manager applicationMgr applicationmanager.Manager clusterMgr clustermanager.Manager + prMgr *prmanager.PRManager userMgr usermanager.Manager } @@ -93,6 +109,7 @@ func NewWebhookLogGenerator(manager *managerparam.Manager) *WebhookLogGenerator groupMgr: manager.GroupMgr, applicationMgr: manager.ApplicationMgr, clusterMgr: manager.ClusterMgr, + prMgr: manager.PRMgr, userMgr: manager.UserMgr, } } @@ -102,6 +119,7 @@ type messageDependency struct { event *models.Event application *applicationmodels.Application cluster *clustermodels.Cluster + pipelinerun *prmodels.Pipelinerun } // listSystemResources lists root group(0) as system resource @@ -149,6 +167,23 @@ func (w *WebhookLogGenerator) listAssociatedResourcesOfCluster(ctx context.Conte return cluster, app, resources } +// listAssociatedResourcesOfPipelinerun gets pipelinerun by id and list all the parent resources +func (w *WebhookLogGenerator) listAssociatedResourcesOfPipelinerun(ctx context.Context, + id uint) (*prmodels.Pipelinerun, *clustermodels.Cluster, map[string][]uint) { + pr, err := w.prMgr.PipelineRun.GetByID(ctx, id) + if err != nil { + log.Warningf(ctx, "pipelinerun %d is not exist", + id) + return nil, nil, nil + } + cluster, _, resources := w.listAssociatedResourcesOfCluster(ctx, pr.ClusterID) + if resources == nil { + resources = map[string][]uint{} + } + resources[common.ResourcePipelinerun] = []uint{pr.ID} + return pr, cluster, resources +} + // listAssociatedResources list all the associated resources of event to find all the webhooks func (w *WebhookLogGenerator) listAssociatedResources(ctx context.Context, e *models.Event) (*messageDependency, map[string][]uint) { @@ -156,6 +191,7 @@ func (w *WebhookLogGenerator) listAssociatedResources(ctx context.Context, resources map[string][]uint cluster *clustermodels.Cluster application *applicationmodels.Application + pr *prmodels.Pipelinerun dep = &messageDependency{} ) @@ -167,6 +203,11 @@ func (w *WebhookLogGenerator) listAssociatedResources(ctx context.Context, cluster, application, resources = w.listAssociatedResourcesOfCluster(ctx, e.ResourceID) dep.application = application dep.cluster = cluster + case common.ResourcePipelinerun: + pr, cluster, resources = w.listAssociatedResourcesOfPipelinerun(ctx, e.ResourceID) + dep.cluster = cluster + dep.pipelinerun = pr + log.Debugf(ctx, "dep: %+v", dep) default: log.Infof(ctx, "resource type %s is unsupported", e.ResourceType) @@ -226,6 +267,27 @@ func (w *WebhookLogGenerator) makeRequestBody(ctx context.Context, dep *messageD } } + if dep.event.ResourceType == common.ResourcePipelinerun && + dep.pipelinerun != nil { + message.Pipelinerun = &PipelinerunInfo{ + ResourceCommonInfo: ResourceCommonInfo{ + ID: dep.pipelinerun.ID, + }, + ClusterID: dep.pipelinerun.ClusterID, + ClusterName: func() string { + if dep.cluster != nil { + return dep.cluster.Name + } + return "" + }(), + Action: dep.pipelinerun.Action, + Title: dep.pipelinerun.Title, + Description: dep.pipelinerun.Description, + GitRef: dep.pipelinerun.GitRef, + GitRefType: dep.pipelinerun.GitRefType, + } + } + reqBody, err := json.Marshal(message) if err != nil { log.Errorf(ctx, fmt.Sprintf("failed to marshal message, error: %+v", err)) @@ -271,6 +333,7 @@ func (w *WebhookLogGenerator) Process(ctx context.Context, events []*models.Even } else if !ok { continue } + log.Debugf(ctx, "event %d matches webhook %d", event.ID, webhook.URL) // 3.2 add webhook to the list if _, ok := conditionsToCreate[event.ID]; !ok { conditionsToCreate[event.ID] = map[uint]messageDependency{} @@ -280,6 +343,7 @@ func (w *WebhookLogGenerator) Process(ctx context.Context, events []*models.Even event: event, application: dependency.application, cluster: dependency.cluster, + pipelinerun: dependency.pipelinerun, } conditionsToQuery[event.ID] = append(conditionsToQuery[event.ID], webhook.ID) } diff --git a/pkg/pr/dao/check.go b/pkg/pr/dao/check.go index 462eb556f..b85b833aa 100644 --- a/pkg/pr/dao/check.go +++ b/pkg/pr/dao/check.go @@ -2,7 +2,9 @@ package dao import ( "context" + "fmt" + "github.com/horizoncd/horizon/lib/q" "gorm.io/gorm" "github.com/horizoncd/horizon/core/common" @@ -17,7 +19,8 @@ type CheckDAO interface { UpdateByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error // GetByResource get checks by resource GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) - ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) + GetCheckRunByID(ctx context.Context, checkRunID uint) (*models.CheckRun, error) + ListCheckRuns(ctx context.Context, query *q.Query) ([]*models.CheckRun, error) CreateCheckRun(ctx context.Context, run *models.CheckRun) (*models.CheckRun, error) } @@ -38,7 +41,7 @@ func (d *checkDAO) Create(ctx context.Context, check *models.Check) (*models.Che } func (d *checkDAO) UpdateByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error { - result := d.db.WithContext(ctx).Model(&models.CheckRun{}).Where("id = ?", checkRunID).Updates(newCheckRun) + result := d.db.WithContext(ctx).Model(&models.CheckRun{}).Debug().Where("id = ?", checkRunID).Updates(newCheckRun) if result.Error != nil { return herrors.NewErrUpdateFailed(herrors.CheckInDB, result.Error.Error()) @@ -70,10 +73,26 @@ func (d *checkDAO) GetByResource(ctx context.Context, resources ...common.Resour return checks, nil } -func (d *checkDAO) ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) { +func (d *checkDAO) ListCheckRuns(ctx context.Context, query *q.Query) ([]*models.CheckRun, error) { var checkRuns []*models.CheckRun - result := d.db.Where("pipeline_run_id = ?", pipelineRunID). - Find(&checkRuns) + + statement := d.db.WithContext(ctx) + if query != nil { + for k, v := range query.Keywords { + switch k { + case common.CheckrunQueryFilter: + statement = statement.Where("name like ?", fmt.Sprintf("%%%v%%", v)) + case common.CheckrunQueryByStatus: + status := models.String2CheckRunStatus(v.(string)) + statement = statement.Where("status = ?", status) + case common.CheckrunQueryByPipelinerunID: + statement = statement.Where("pipeline_run_id = ?", v) + case common.CheckrunQueryByCheckID: + statement = statement.Where("check_id = ?", v) + } + } + } + result := statement.Debug().Find(&checkRuns) if result.RowsAffected == 0 { return []*models.CheckRun{}, nil @@ -93,3 +112,16 @@ func (d *checkDAO) CreateCheckRun(ctx context.Context, run *models.CheckRun) (*m return run, result.Error } + +func (d *checkDAO) GetCheckRunByID(ctx context.Context, checkRunID uint) (*models.CheckRun, error) { + var checkRun models.CheckRun + result := d.db.WithContext(ctx).Where("id = ?", checkRunID).Find(&checkRun) + + if result.RowsAffected == 0 { + return nil, herrors.NewErrNotFound(herrors.CheckRunInDB, "check run not found") + } + if result.Error != nil { + return nil, herrors.NewErrGetFailed(herrors.CheckRunInDB, result.Error.Error()) + } + return &checkRun, nil +} diff --git a/pkg/pr/dao/pipelinerun.go b/pkg/pr/dao/pipelinerun.go index da52a4d48..5169b02e1 100644 --- a/pkg/pr/dao/pipelinerun.go +++ b/pkg/pr/dao/pipelinerun.go @@ -180,12 +180,12 @@ func (d *pipelinerunDAO) GetByClusterID(ctx context.Context, clusterID uint, offset := query.Offset() limit := query.Limit() - sql := d.db.WithContext(ctx).Table("tb_pipelinerun").Where("cluster_id = ?", clusterID). + sql := d.db.WithContext(ctx).Debug().Table("tb_pipelinerun").Where("cluster_id = ?", clusterID). Order("created_at desc") if canRollback { // remove the first canRollback pipelinerun offset++ - sql = sql.Where("action = 'restart'").Where("status = 'ok'") + sql = sql.Where("action != 'restart'").Where("status = 'ok'") } for k, v := range query.Keywords { @@ -200,6 +200,10 @@ func (d *pipelinerunDAO) GetByClusterID(ctx context.Context, clusterID uint, if result.Error != nil { return 0, nil, herrors.NewErrGetFailed(herrors.PipelinerunInDB, result.Error.Error()) } + if canRollback && total > 0 { + // ignore the first canRollback pipelinerun + total-- + } var pipelineruns []*models.Pipelinerun result = sql.Limit(limit).Offset(offset).Find(&pipelineruns) diff --git a/pkg/pr/manager/check.go b/pkg/pr/manager/check.go index 01c4f2ac7..eb673c1a6 100644 --- a/pkg/pr/manager/check.go +++ b/pkg/pr/manager/check.go @@ -3,6 +3,7 @@ package manager import ( "context" + "github.com/horizoncd/horizon/lib/q" "gorm.io/gorm" "github.com/horizoncd/horizon/core/common" @@ -17,7 +18,8 @@ type CheckManager interface { UpdateByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error // GetByResource get checks by resource GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) - ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) + GetCheckRunByID(ctx context.Context, checkRunID uint) (*models.CheckRun, error) + ListCheckRuns(ctx context.Context, query *q.Query) ([]*models.CheckRun, error) CreateCheckRun(ctx context.Context, checkRun *models.CheckRun) (*models.CheckRun, error) } @@ -43,8 +45,15 @@ func (m *checkManager) GetByResource(ctx context.Context, resources ...common.Re return m.dao.GetByResource(ctx, resources...) } -func (m *checkManager) ListCheckRuns(ctx context.Context, pipelineRunID uint) ([]*models.CheckRun, error) { - return m.dao.ListCheckRuns(ctx, pipelineRunID) +func (m *checkManager) GetCheckRunByID(ctx context.Context, checkRunID uint) (*models.CheckRun, error) { + return m.dao.GetCheckRunByID(ctx, checkRunID) +} + +func (m *checkManager) ListCheckRuns(ctx context.Context, query *q.Query) ([]*models.CheckRun, error) { + if query == nil { + query = &q.Query{} + } + return m.dao.ListCheckRuns(ctx, query) } func (m *checkManager) CreateCheckRun(ctx context.Context, checkRun *models.CheckRun) (*models.CheckRun, error) { diff --git a/pkg/pr/manager/check_test.go b/pkg/pr/manager/check_test.go index 7b687cd19..041795630 100644 --- a/pkg/pr/manager/check_test.go +++ b/pkg/pr/manager/check_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/horizoncd/horizon/core/common" + "github.com/horizoncd/horizon/lib/q" "github.com/horizoncd/horizon/pkg/pr/models" "github.com/stretchr/testify/assert" @@ -50,7 +51,10 @@ func TestCheck(t *testing.T) { assert.Len(t, checks, 1) // Test ListCheckRuns - checkRuns, err := checkManager.ListCheckRuns(ctx, checkRun.PipelineRunID) + keyWords := make(map[string]interface{}) + keyWords[common.CheckrunQueryByPipelinerunID] = checkRun.PipelineRunID + query := q.New(keyWords) + checkRuns, err := checkManager.ListCheckRuns(ctx, query) assert.NoError(t, err) assert.Len(t, checkRuns, 1) assert.Equal(t, checkRuns[0].Status, models.CheckStatusInProgress) diff --git a/pkg/pr/service/service.go b/pkg/pr/service/service.go index a2132c1d8..682c27246 100644 --- a/pkg/pr/service/service.go +++ b/pkg/pr/service/service.go @@ -69,7 +69,7 @@ func (s *Service) OfPipelineBasic(ctx context.Context, func (s *Service) OfPipelineBasics(ctx context.Context, prs []*models.Pipelinerun, firstCanRollbackPipelinerun *models.Pipelinerun) ([]*models.PipelineBasic, error) { - var pipelineBasics []*models.PipelineBasic + pipelineBasics := make([]*models.PipelineBasic, 0, len(prs)) for _, pr := range prs { pipelineBasic, err := s.OfPipelineBasic(ctx, pr, firstCanRollbackPipelinerun) if err != nil { @@ -130,6 +130,10 @@ func (s *Service) GetCheckByResource(ctx context.Context, resourceID uint, Type: common.ResourceGroup, }) } + resources = append(resources, common.Resource{ + ResourceID: 0, + Type: common.ResourceGroup, + }) return s.manager.PRMgr.Check.GetByResource(ctx, resources...) } From 135cf6a56b260dbf6a0eb238da3735dbe36704c0 Mon Sep 17 00:00:00 2001 From: "xu.zhu" Date: Fri, 15 Sep 2023 16:47:59 +0800 Subject: [PATCH 07/11] fix: lint and ut Signed-off-by: xu.zhu --- .../cluster/controller_basic_v2_test.go | 4 +- core/controller/pipelinerun/controller.go | 6 +- .../controller/pipelinerun/controller_test.go | 64 +++++++++++++++++-- core/http/api/v2/cluster/routers.go | 2 +- core/http/api/v2/pipelinerun/apis.go | 1 - core/http/api/v2/pipelinerun/routers.go | 6 +- go.mod | 2 +- go.sum | 3 - pkg/eventhandler/wlgenerator/wlgenerator.go | 2 +- 9 files changed, 73 insertions(+), 17 deletions(-) diff --git a/core/controller/cluster/controller_basic_v2_test.go b/core/controller/cluster/controller_basic_v2_test.go index 2ac9d0100..1bff143c7 100644 --- a/core/controller/cluster/controller_basic_v2_test.go +++ b/core/controller/cluster/controller_basic_v2_test.go @@ -15,6 +15,7 @@ import ( userauth "github.com/horizoncd/horizon/pkg/authentication/user" clustergitrepo "github.com/horizoncd/horizon/pkg/cluster/gitrepo" "github.com/horizoncd/horizon/pkg/cluster/models" + eventmodels "github.com/horizoncd/horizon/pkg/event/models" "github.com/horizoncd/horizon/pkg/git" groupmodels "github.com/horizoncd/horizon/pkg/group/models" membermodels "github.com/horizoncd/horizon/pkg/member/models" @@ -31,7 +32,7 @@ func TestCreatePipelineRun(t *testing.T) { if err := db.AutoMigrate(&appmodels.Application{}, &models.Cluster{}, ®ionmodels.Region{}, &membermodels.Member{}, ®istrymodels.Registry{}, &prmodels.Pipelinerun{}, &groupmodels.Group{}, &prmodels.Check{}, - &usermodel.User{}); err != nil { + &usermodel.User{}, &eventmodels.Event{}); err != nil { panic(err) } param := managerparam.InitManager(db) @@ -61,6 +62,7 @@ func TestCreatePipelineRun(t *testing.T) { regionMgr: param.RegionMgr, clusterGitRepo: mockClusterGitRepo, commitGetter: mockGitGetter, + eventMgr: param.EventMgr, } _, err := param.UserMgr.Create(ctx, &usermodel.User{ diff --git a/core/controller/pipelinerun/controller.go b/core/controller/pipelinerun/controller.go index 896688a21..e20953e6c 100644 --- a/core/controller/pipelinerun/controller.go +++ b/core/controller/pipelinerun/controller.go @@ -72,7 +72,8 @@ type Controller interface { Cancel(ctx context.Context, pipelinerunID uint) error ListCheckRuns(ctx context.Context, q *q.Query) ([]*prmodels.CheckRun, error) - CreateCheckRun(ctx context.Context, pipelineRunID uint, request *CreateOrUpdateCheckRunRequest) (*prmodels.CheckRun, error) + CreateCheckRun(ctx context.Context, pipelineRunID uint, + request *CreateOrUpdateCheckRunRequest) (*prmodels.CheckRun, error) ListPRMessages(ctx context.Context, pipelineRunID uint, q *q.Query) (int, []*PrMessage, error) CreatePRMessage(ctx context.Context, pipelineRunID uint, request *CreatePrMessageRequest) (*prmodels.PRMessage, error) } @@ -336,7 +337,8 @@ func (c *controller) CreateCheck(ctx context.Context, check *prmodels.Check) (*p return c.prMgr.Check.Create(ctx, check) } -func (c *controller) UpdateCheckRunByID(ctx context.Context, checkRunID uint, request *CreateOrUpdateCheckRunRequest) error { +func (c *controller) UpdateCheckRunByID(ctx context.Context, checkRunID uint, + request *CreateOrUpdateCheckRunRequest) error { const op = "pipelinerun controller: update check run" defer wlog.Start(ctx, op).StopPrint() diff --git a/core/controller/pipelinerun/controller_test.go b/core/controller/pipelinerun/controller_test.go index 6061d130e..f9b4243e6 100644 --- a/core/controller/pipelinerun/controller_test.go +++ b/core/controller/pipelinerun/controller_test.go @@ -524,7 +524,9 @@ func TestExecutePipelineRun(t *testing.T) { func TestCheckRun(t *testing.T) { db, _ := orm.NewSqliteDB("") - if err := db.AutoMigrate(&prmodels.CheckRun{}); err != nil { + if err := db.AutoMigrate(&groupmodels.Group{}, &membermodels.Member{}, &applicationmodel.Application{}, + &clustermodel.Cluster{}, &prmodels.CheckRun{}, &prmodels.Pipelinerun{}, + &usermodel.User{}, &prmodels.Check{}); err != nil { panic(err) } param := managerparam.InitManager(db) @@ -536,19 +538,73 @@ func TestCheckRun(t *testing.T) { }) ctrl := controller{ - prMgr: param.PRMgr, + clusterMgr: param.ClusterMgr, + prMgr: param.PRMgr, + prSvc: prservice.NewService(param), } - _, err := ctrl.CreateCheckRun(ctx, 1, &CreateOrUpdateCheckRunRequest{ + _, err := param.UserMgr.Create(ctx, &usermodel.User{ + Name: "Tony", + }) + assert.NoError(t, err) + + group, err := param.GroupMgr.Create(ctx, &groupmodels.Group{ + Name: "test", + }) + assert.NoError(t, err) + + app, err := param.ApplicationMgr.Create(ctx, &applicationmodel.Application{ + Name: "test", + GroupID: group.ID, + }, nil) + assert.NoError(t, err) + + cluster, err := param.ClusterMgr.Create(ctx, &clustermodel.Cluster{ + Name: "cluster", + ApplicationID: app.ID, + }, nil, nil) + assert.NoError(t, err) + + // create a check under cluster + check, err := ctrl.CreateCheck(ctx, &pipelinemodel.Check{ + Resource: common.Resource{ + ResourceID: cluster.ID, + Type: "clusters", + }, + }) + assert.NoError(t, err) + + pr, err := ctrl.prMgr.PipelineRun.Create(ctx, &prmodels.Pipelinerun{ + ID: 1, + Status: string(prmodels.StatusPending), + ClusterID: cluster.ID, + }) + assert.NoError(t, err) + + _, err = ctrl.CreateCheckRun(ctx, pr.ID, &CreateOrUpdateCheckRunRequest{ Name: "test", Status: string(prmodels.CheckStatusQueue), + CheckID: check.ID, Message: "hello", DetailURL: "https://www.google.com", }) assert.NoError(t, err) + err = ctrl.UpdateCheckRunByID(ctx, 1, &CreateOrUpdateCheckRunRequest{ + Status: string(prmodels.CheckStatusSuccess), + }) + assert.NoError(t, err) + + cr, err := ctrl.GetCheckRunByID(ctx, 1) + assert.NoError(t, err) + assert.Equal(t, string(cr.Status), string(prmodels.CheckStatusSuccess)) + + prInDB, err := ctrl.GetPipelinerun(ctx, pr.ID) + assert.NoError(t, err) + assert.Equal(t, string(prInDB.Status), string(prmodels.StatusReady)) + keyWords := make(map[string]interface{}) - keyWords[common.CheckrunQueryByPipelinerunID] = 1 + keyWords[common.CheckrunQueryByPipelinerunID] = strconv.Itoa(int(pr.ID)) query := q.New(keyWords) checkRuns, err := ctrl.ListCheckRuns(ctx, query) assert.NoError(t, err) diff --git a/core/http/api/v2/cluster/routers.go b/core/http/api/v2/cluster/routers.go index fc02fc440..e08281841 100644 --- a/core/http/api/v2/cluster/routers.go +++ b/core/http/api/v2/cluster/routers.go @@ -137,7 +137,7 @@ func (api *API) RegisterRoute(engine *gin.Engine) { HandlerFunc: api.DeleteFavorite, }, { Method: http.MethodPost, - Pattern: fmt.Sprintf("/clusters/:%v/pipelinerun", common.ParamClusterID), + Pattern: fmt.Sprintf("/clusters/:%v/pipelineruns", common.ParamClusterID), HandlerFunc: api.CreatePipelineRun, }, } diff --git a/core/http/api/v2/pipelinerun/apis.go b/core/http/api/v2/pipelinerun/apis.go index f6bcaad1b..89c9ca831 100644 --- a/core/http/api/v2/pipelinerun/apis.go +++ b/core/http/api/v2/pipelinerun/apis.go @@ -211,7 +211,6 @@ func (a *API) ListCheckRuns(c *gin.Context) { return } response.SuccessWithData(c, checkRuns) - } func (a *API) CreateCheckRun(c *gin.Context) { diff --git a/core/http/api/v2/pipelinerun/routers.go b/core/http/api/v2/pipelinerun/routers.go index eeb09c0a8..64162ff2a 100644 --- a/core/http/api/v2/pipelinerun/routers.go +++ b/core/http/api/v2/pipelinerun/routers.go @@ -76,7 +76,7 @@ func (api *API) RegisterRoute(engine *gin.Engine) { }, { Method: http.MethodGet, - Pattern: fmt.Sprintf("/checkruns"), + Pattern: "/checkruns", HandlerFunc: api.ListCheckRuns, }, { @@ -86,12 +86,12 @@ func (api *API) RegisterRoute(engine *gin.Engine) { }, { Method: http.MethodGet, - Pattern: fmt.Sprintf("/pipelineruns/:%v/message", _pipelinerunIDParam), + Pattern: fmt.Sprintf("/pipelineruns/:%v/messages", _pipelinerunIDParam), HandlerFunc: api.ListPrMessages, }, { Method: http.MethodPost, - Pattern: fmt.Sprintf("/pipelineruns/:%v/message", _pipelinerunIDParam), + Pattern: fmt.Sprintf("/pipelineruns/:%v/messages", _pipelinerunIDParam), HandlerFunc: api.CreatePrMessage, }, } diff --git a/go.mod b/go.mod index 37016a03c..3a2a86603 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/go-redis/redis/v8 v8.3.3 github.com/golang-jwt/jwt/v4 v4.4.3 github.com/golang/mock v1.6.0 - github.com/google/go-containerregistry v0.1.3 // indirect + github.com/google/go-containerregistry v0.1.3 github.com/google/go-github/v41 v41.0.0 github.com/google/uuid v1.2.0 github.com/gorilla/mux v1.8.0 diff --git a/go.sum b/go.sum index 38839e8b3..8486f3319 100644 --- a/go.sum +++ b/go.sum @@ -1252,7 +1252,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.0/go.mod h1:D8He9yQNgCq6Z5 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2 h1:g+4J5sZg6osfvEfkRZxJ1em0VT95/UOZgi/l7zi1/oE= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/mbilski/exhaustivestruct v1.1.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= @@ -2588,7 +2587,6 @@ k8s.io/client-go v0.20.10 h1:TgAL2pqcNWMH4eZoS9Uw0BLh2lu5a2A4pmegjp5pmsk= k8s.io/client-go v0.20.10/go.mod h1:fFg+aLoasv/R+xiVaWjxeqGFYltzgQcOQzkFaSRfnJ0= k8s.io/cloud-provider v0.20.10/go.mod h1:8HQ0NgW661PiH+QK1BPYD0QorpaxOXQs1ZsMfOe3uc0= k8s.io/cluster-bootstrap v0.20.10/go.mod h1:D+cqd8iJYeajaIUBUca4J3f/87L4qiFvMPzM5qs8x1o= -k8s.io/code-generator v0.20.10 h1:xENIQkVW8G2chwm0/HNwNIR3gcbF2XADK+jVS9/UCTE= k8s.io/code-generator v0.20.10/go.mod h1:i6FmG+QxaLxvJsezvZp0q/gAEzzOz3U53KFibghWToU= k8s.io/component-base v0.20.10 h1:QNlekT6M2zBb4feHHmZ+YHZHcDbhbrYS7xHHY+v+kOE= k8s.io/component-base v0.20.10/go.mod h1:ZKOEin1xu68aJzxgzl5DZSp5J1IrjAOPlPN90/t6OI8= @@ -2602,7 +2600,6 @@ k8s.io/gengo v0.0.0-20191108084044-e500ee069b5c/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20200205140755-e0e292d8aa12/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20201113003025-83324d819ded h1:JApXBKYyB7l9xx+DK7/+mFjC7A9Bt5A93FPvFD0HIFE= k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/heapster v1.2.0-beta.1/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM= k8s.io/helm v2.17.0+incompatible h1:Bpn6o1wKLYqKM3+Osh8e+1/K2g/GsQJ4F4yNF2+deao= diff --git a/pkg/eventhandler/wlgenerator/wlgenerator.go b/pkg/eventhandler/wlgenerator/wlgenerator.go index 33ea26e05..e2d29dd11 100644 --- a/pkg/eventhandler/wlgenerator/wlgenerator.go +++ b/pkg/eventhandler/wlgenerator/wlgenerator.go @@ -333,7 +333,7 @@ func (w *WebhookLogGenerator) Process(ctx context.Context, events []*models.Even } else if !ok { continue } - log.Debugf(ctx, "event %d matches webhook %d", event.ID, webhook.URL) + log.Debugf(ctx, "event %d matches webhook %s", event.ID, webhook.URL) // 3.2 add webhook to the list if _, ok := conditionsToCreate[event.ID]; !ok { conditionsToCreate[event.ID] = map[uint]messageDependency{} From 8a3b99e1c1c61919b3e2ae9bf7343b7f25d98674 Mon Sep 17 00:00:00 2001 From: "xu.zhu" Date: Wed, 20 Sep 2023 16:53:39 +0800 Subject: [PATCH 08/11] fix: review Signed-off-by: xu.zhu --- core/common/const.go | 4 + core/controller/pipelinerun/controller.go | 20 ++- .../controller/pipelinerun/controller_test.go | 7 +- core/http/api/v2/pipelinerun/apis.go | 15 +- core/http/api/v2/pipelinerun/routers.go | 2 +- .../pipelinerun/manager/mock_check_manager.go | 131 ++++++++++++++++++ pkg/member/service/service.go | 23 ++- pkg/member/service/service_test.go | 15 +- pkg/pr/dao/check.go | 25 +--- pkg/pr/manager/check.go | 13 +- pkg/pr/manager/check_test.go | 8 +- pkg/pr/models/check.go | 6 +- pkg/rbac/auth.go | 2 +- 13 files changed, 204 insertions(+), 67 deletions(-) create mode 100644 mock/pkg/pipelinerun/manager/mock_check_manager.go diff --git a/core/common/const.go b/core/common/const.go index 402251879..3ff1df7cd 100644 --- a/core/common/const.go +++ b/core/common/const.go @@ -93,6 +93,10 @@ const ( // use the pipeline's cluster's member info ResourcePipelinerun = "pipelineruns" + // ResourceCheckrun currently checkruns do not have direct member info, will + // use the member info of the clusters that they belong to + ResourceCheckrun = "checkruns" + // ResourceOauthApps currently oauthapp do not have direct member info, will // use the oauthapp's groups member info ResourceOauthApps = "oauthapps" diff --git a/core/controller/pipelinerun/controller.go b/core/controller/pipelinerun/controller.go index e20953e6c..200c4fcd2 100644 --- a/core/controller/pipelinerun/controller.go +++ b/core/controller/pipelinerun/controller.go @@ -71,7 +71,7 @@ type Controller interface { // Cancel withdraws a pipelineRun only if its state is pending. Cancel(ctx context.Context, pipelinerunID uint) error - ListCheckRuns(ctx context.Context, q *q.Query) ([]*prmodels.CheckRun, error) + ListCheckRuns(ctx context.Context, pipelinerunID uint) ([]*prmodels.CheckRun, error) CreateCheckRun(ctx context.Context, pipelineRunID uint, request *CreateOrUpdateCheckRunRequest) (*prmodels.CheckRun, error) ListPRMessages(ctx context.Context, pipelineRunID uint, q *q.Query) (int, []*PrMessage, error) @@ -495,22 +495,22 @@ func (c *controller) Cancel(ctx context.Context, pipelinerunID uint) error { return c.prMgr.PipelineRun.UpdateStatusByID(ctx, pipelinerunID, prmodels.StatusCancelled) } -func (c *controller) ListCheckRuns(ctx context.Context, query *q.Query) ([]*prmodels.CheckRun, error) { +func (c *controller) ListCheckRuns(ctx context.Context, pipelinerunID uint) ([]*prmodels.CheckRun, error) { const op = "pipelinerun controller: list check runs" - defer wlog.Start(context.Background(), op).StopPrint() - return c.prMgr.Check.ListCheckRuns(ctx, query) + defer wlog.Start(ctx, op).StopPrint() + return c.prMgr.Check.ListCheckRuns(ctx, pipelinerunID) } func (c *controller) GetCheckRunByID(ctx context.Context, checkRunID uint) (*prmodels.CheckRun, error) { const op = "pipelinerun controller: get check run by id" - defer wlog.Start(context.Background(), op).StopPrint() + defer wlog.Start(ctx, op).StopPrint() return c.prMgr.Check.GetCheckRunByID(ctx, checkRunID) } func (c *controller) CreateCheckRun(ctx context.Context, pipelineRunID uint, request *CreateOrUpdateCheckRunRequest) (*prmodels.CheckRun, error) { const op = "pipelinerun controller: create check run" - defer wlog.Start(context.Background(), op).StopPrint() + defer wlog.Start(ctx, op).StopPrint() checkrun, err := c.prMgr.Check.CreateCheckRun(ctx, &prmodels.CheckRun{ Name: request.Name, @@ -533,7 +533,7 @@ func (c *controller) CreateCheckRun(ctx context.Context, pipelineRunID uint, func (c *controller) CreatePRMessage(ctx context.Context, pipelineRunID uint, request *CreatePrMessageRequest) (*prmodels.PRMessage, error) { const op = "pipelinerun controller: create pr message" - defer wlog.Start(context.Background(), op).StopPrint() + defer wlog.Start(ctx, op).StopPrint() currentUser, err := common.UserFromContext(ctx) if err != nil { @@ -551,7 +551,7 @@ func (c *controller) CreatePRMessage(ctx context.Context, pipelineRunID uint, func (c *controller) ListPRMessages(ctx context.Context, pipelineRunID uint, query *q.Query) (int, []*PrMessage, error) { const op = "pipelinerun controller: list pr messages" - defer wlog.Start(context.Background(), op).StopPrint() + defer wlog.Start(ctx, op).StopPrint() count, messages, err := c.prMgr.Message.List(ctx, pipelineRunID, query) if err != nil { @@ -657,9 +657,7 @@ func (c *controller) calculatePrSuccessStatus(ctx context.Context, if err != nil { return prmodels.StatusPending, err } - runs, err := c.prMgr.Check.ListCheckRuns(ctx, q.New(map[string]interface{}{ - common.CheckrunQueryByPipelinerunID: pipelinerun.ID}, - )) + runs, err := c.prMgr.Check.ListCheckRuns(ctx, pipelinerun.ID) if err != nil { return prmodels.StatusPending, err } diff --git a/core/controller/pipelinerun/controller_test.go b/core/controller/pipelinerun/controller_test.go index f9b4243e6..1987bbbd9 100644 --- a/core/controller/pipelinerun/controller_test.go +++ b/core/controller/pipelinerun/controller_test.go @@ -583,7 +583,7 @@ func TestCheckRun(t *testing.T) { _, err = ctrl.CreateCheckRun(ctx, pr.ID, &CreateOrUpdateCheckRunRequest{ Name: "test", - Status: string(prmodels.CheckStatusQueue), + Status: string(prmodels.CheckStatusPending), CheckID: check.ID, Message: "hello", DetailURL: "https://www.google.com", @@ -603,10 +603,7 @@ func TestCheckRun(t *testing.T) { assert.NoError(t, err) assert.Equal(t, string(prInDB.Status), string(prmodels.StatusReady)) - keyWords := make(map[string]interface{}) - keyWords[common.CheckrunQueryByPipelinerunID] = strconv.Itoa(int(pr.ID)) - query := q.New(keyWords) - checkRuns, err := ctrl.ListCheckRuns(ctx, query) + checkRuns, err := ctrl.ListCheckRuns(ctx, pr.ID) assert.NoError(t, err) assert.Equal(t, len(checkRuns), 1) } diff --git a/core/http/api/v2/pipelinerun/apis.go b/core/http/api/v2/pipelinerun/apis.go index 89c9ca831..83be3c546 100644 --- a/core/http/api/v2/pipelinerun/apis.go +++ b/core/http/api/v2/pipelinerun/apis.go @@ -204,13 +204,14 @@ func (a *API) Cancel(c *gin.Context) { } func (a *API) ListCheckRuns(c *gin.Context) { - query := parseContext(c) - checkRuns, err := a.prCtl.ListCheckRuns(c, query) - if err != nil { - response.AbortWithError(c, err) - return - } - response.SuccessWithData(c, checkRuns) + a.withPipelinerunID(c, func(pipelinerunID uint) { + checkRuns, err := a.prCtl.ListCheckRuns(c, pipelinerunID) + if err != nil { + response.AbortWithError(c, err) + return + } + response.SuccessWithData(c, checkRuns) + }) } func (a *API) CreateCheckRun(c *gin.Context) { diff --git a/core/http/api/v2/pipelinerun/routers.go b/core/http/api/v2/pipelinerun/routers.go index 64162ff2a..f3ccc6722 100644 --- a/core/http/api/v2/pipelinerun/routers.go +++ b/core/http/api/v2/pipelinerun/routers.go @@ -76,7 +76,7 @@ func (api *API) RegisterRoute(engine *gin.Engine) { }, { Method: http.MethodGet, - Pattern: "/checkruns", + Pattern: fmt.Sprintf("/pipelineruns/:%v/checkruns", _pipelinerunIDParam), HandlerFunc: api.ListCheckRuns, }, { diff --git a/mock/pkg/pipelinerun/manager/mock_check_manager.go b/mock/pkg/pipelinerun/manager/mock_check_manager.go new file mode 100644 index 000000000..00b21b837 --- /dev/null +++ b/mock/pkg/pipelinerun/manager/mock_check_manager.go @@ -0,0 +1,131 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: check.go + +// Package mock_manager is a generated GoMock package. +package mock_manager + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + common "github.com/horizoncd/horizon/core/common" + models "github.com/horizoncd/horizon/pkg/pr/models" +) + +// MockCheckManager is a mock of CheckManager interface. +type MockCheckManager struct { + ctrl *gomock.Controller + recorder *MockCheckManagerMockRecorder +} + +// MockCheckManagerMockRecorder is the mock recorder for MockCheckManager. +type MockCheckManagerMockRecorder struct { + mock *MockCheckManager +} + +// NewMockCheckManager creates a new mock instance. +func NewMockCheckManager(ctrl *gomock.Controller) *MockCheckManager { + mock := &MockCheckManager{ctrl: ctrl} + mock.recorder = &MockCheckManagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockCheckManager) EXPECT() *MockCheckManagerMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockCheckManager) Create(ctx context.Context, check *models.Check) (*models.Check, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", ctx, check) + ret0, _ := ret[0].(*models.Check) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create. +func (mr *MockCheckManagerMockRecorder) Create(ctx, check interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockCheckManager)(nil).Create), ctx, check) +} + +// CreateCheckRun mocks base method. +func (m *MockCheckManager) CreateCheckRun(ctx context.Context, checkRun *models.CheckRun) (*models.CheckRun, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateCheckRun", ctx, checkRun) + ret0, _ := ret[0].(*models.CheckRun) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateCheckRun indicates an expected call of CreateCheckRun. +func (mr *MockCheckManagerMockRecorder) CreateCheckRun(ctx, checkRun interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCheckRun", reflect.TypeOf((*MockCheckManager)(nil).CreateCheckRun), ctx, checkRun) +} + +// GetByResource mocks base method. +func (m *MockCheckManager) GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx} + for _, a := range resources { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetByResource", varargs...) + ret0, _ := ret[0].([]*models.Check) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetByResource indicates an expected call of GetByResource. +func (mr *MockCheckManagerMockRecorder) GetByResource(ctx interface{}, resources ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx}, resources...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByResource", reflect.TypeOf((*MockCheckManager)(nil).GetByResource), varargs...) +} + +// GetCheckRunByID mocks base method. +func (m *MockCheckManager) GetCheckRunByID(ctx context.Context, checkRunID uint) (*models.CheckRun, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCheckRunByID", ctx, checkRunID) + ret0, _ := ret[0].(*models.CheckRun) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCheckRunByID indicates an expected call of GetCheckRunByID. +func (mr *MockCheckManagerMockRecorder) GetCheckRunByID(ctx, checkRunID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCheckRunByID", reflect.TypeOf((*MockCheckManager)(nil).GetCheckRunByID), ctx, checkRunID) +} + +// ListCheckRuns mocks base method. +func (m *MockCheckManager) ListCheckRuns(ctx context.Context, pipelinerunID uint) ([]*models.CheckRun, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListCheckRuns", ctx, pipelinerunID) + ret0, _ := ret[0].([]*models.CheckRun) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListCheckRuns indicates an expected call of ListCheckRuns. +func (mr *MockCheckManagerMockRecorder) ListCheckRuns(ctx, pipelinerunID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListCheckRuns", reflect.TypeOf((*MockCheckManager)(nil).ListCheckRuns), ctx, pipelinerunID) +} + +// UpdateByID mocks base method. +func (m *MockCheckManager) UpdateByID(ctx context.Context, checkRunID uint, newCheckRun *models.CheckRun) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateByID", ctx, checkRunID, newCheckRun) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateByID indicates an expected call of UpdateByID. +func (mr *MockCheckManagerMockRecorder) UpdateByID(ctx, checkRunID, newCheckRun interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateByID", reflect.TypeOf((*MockCheckManager)(nil).UpdateByID), ctx, checkRunID, newCheckRun) +} diff --git a/pkg/member/service/service.go b/pkg/member/service/service.go index 210808ee0..1e7d27efa 100644 --- a/pkg/member/service/service.go +++ b/pkg/member/service/service.go @@ -170,6 +170,19 @@ func (s *service) getOauthAppMember(ctx context.Context, clientID string) (*mode return s.getMember(ctx, common.ResourceGroup, app.OwnerID, models.MemberUser, currentUser.GetID()) } +func (s *service) getCheckrunMember(ctx context.Context, checkrunID uint) (*models.Member, error) { + checkrun, err := s.prMgr.Check.GetCheckRunByID(ctx, checkrunID) + if err != nil { + return nil, err + } + if checkrun == nil { + msg := fmt.Sprintf("checkrun does not found, checkrunID = %d", checkrunID) + log.Warningf(ctx, msg) + return nil, herror.NewErrNotFound(herror.MemberInfoInDB, msg) + } + return s.getPipelinerunMember(ctx, checkrun.PipelineRunID) +} + func (s *service) getPipelinerunMember(ctx context.Context, pipelinerunID uint) (*models.Member, error) { currentUser, err := common.UserFromContext(ctx) if err != nil { @@ -238,12 +251,16 @@ func (s *service) GetMemberOfResource(ctx context.Context, return nil, err } var memberInfo *models.Member - if resourceType == common.ResourcePipelinerun { + switch resourceType { + case common.ResourceCheckrun: + resourceID, _ := strconv.Atoi(resourceIDStr) + memberInfo, err = s.getCheckrunMember(ctx, uint(resourceID)) + case common.ResourcePipelinerun: resourceID, _ := strconv.Atoi(resourceIDStr) memberInfo, err = s.getPipelinerunMember(ctx, uint(resourceID)) - } else if resourceType == common.ResourceOauthApps { + case common.ResourceOauthApps: memberInfo, err = s.getOauthAppMember(ctx, resourceIDStr) - } else { + default: resourceID, _ := strconv.Atoi(resourceIDStr) memberInfo, err = s.getMember(ctx, resourceType, uint(resourceID), models.MemberUser, currentUser.GetID()) } diff --git a/pkg/member/service/service_test.go b/pkg/member/service/service_test.go index 7e239acab..ab535fc9a 100644 --- a/pkg/member/service/service_test.go +++ b/pkg/member/service/service_test.go @@ -630,7 +630,7 @@ func TestListApplicationInstanceMember(t *testing.T) { // ret: sph(3), jerry(2), cat(4) // // nolint -func TestGetPipelinerunMember(t *testing.T) { +func TestGetPipelinerunAndCheckrunMember(t *testing.T) { createEnv(t) mockCtrl := gomock.NewController(t) @@ -652,6 +652,7 @@ func TestGetPipelinerunMember(t *testing.T) { ID: 1, } pipelineRunID uint = 23123 + checkrunID uint = 12138 ) users := []usermodels.User{ { @@ -732,6 +733,12 @@ func TestGetPipelinerunMember(t *testing.T) { ClusterID: cluster4ID, }, nil).AnyTimes() + checkMockManager := pipelinemock.NewMockCheckManager(mockCtrl) + checkMockManager.EXPECT().GetCheckRunByID(gomock.Any(), checkrunID). + Return(&pipelinemodels.CheckRun{ + PipelineRunID: pipelineRunID, + }, nil).AnyTimes() + roleSvc := rolemock.NewMockService(mockCtrl) originService := &service{ memberManager: manager.MemberMgr, @@ -740,6 +747,7 @@ func TestGetPipelinerunMember(t *testing.T) { applicationClusterManager: clusterManager, prMgr: &prmanager.PRManager{ PipelineRun: pipelineMockManager, + Check: checkMockManager, }, roleService: roleSvc, userManager: manager.UserMgr, @@ -808,6 +816,11 @@ func TestGetPipelinerunMember(t *testing.T) { assert.Nil(t, err) assert.True(t, PostMemberEqualsMember(postMembers[3], members)) + members, err = s.GetMemberOfResource(ctx, common.ResourceCheckrun, + strconv.FormatUint(uint64(checkrunID), 10)) + assert.NoError(t, err) + assert.True(t, PostMemberEqualsMember(postMembers[3], members)) + members, err = s.UpdateMember(ctx, members.ID, roleservice.Maintainer) assert.Nil(t, err) assert.Equal(t, roleservice.Maintainer, members.Role) diff --git a/pkg/pr/dao/check.go b/pkg/pr/dao/check.go index b85b833aa..6db8b51f7 100644 --- a/pkg/pr/dao/check.go +++ b/pkg/pr/dao/check.go @@ -2,9 +2,7 @@ package dao import ( "context" - "fmt" - "github.com/horizoncd/horizon/lib/q" "gorm.io/gorm" "github.com/horizoncd/horizon/core/common" @@ -20,7 +18,7 @@ type CheckDAO interface { // GetByResource get checks by resource GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) GetCheckRunByID(ctx context.Context, checkRunID uint) (*models.CheckRun, error) - ListCheckRuns(ctx context.Context, query *q.Query) ([]*models.CheckRun, error) + ListCheckRuns(ctx context.Context, pipelinerunID uint) ([]*models.CheckRun, error) CreateCheckRun(ctx context.Context, run *models.CheckRun) (*models.CheckRun, error) } @@ -73,26 +71,9 @@ func (d *checkDAO) GetByResource(ctx context.Context, resources ...common.Resour return checks, nil } -func (d *checkDAO) ListCheckRuns(ctx context.Context, query *q.Query) ([]*models.CheckRun, error) { +func (d *checkDAO) ListCheckRuns(ctx context.Context, pipelinerunID uint) ([]*models.CheckRun, error) { var checkRuns []*models.CheckRun - - statement := d.db.WithContext(ctx) - if query != nil { - for k, v := range query.Keywords { - switch k { - case common.CheckrunQueryFilter: - statement = statement.Where("name like ?", fmt.Sprintf("%%%v%%", v)) - case common.CheckrunQueryByStatus: - status := models.String2CheckRunStatus(v.(string)) - statement = statement.Where("status = ?", status) - case common.CheckrunQueryByPipelinerunID: - statement = statement.Where("pipeline_run_id = ?", v) - case common.CheckrunQueryByCheckID: - statement = statement.Where("check_id = ?", v) - } - } - } - result := statement.Debug().Find(&checkRuns) + result := d.db.Where("pipeline_run_id = ?", pipelinerunID).Find(&checkRuns) if result.RowsAffected == 0 { return []*models.CheckRun{}, nil diff --git a/pkg/pr/manager/check.go b/pkg/pr/manager/check.go index eb673c1a6..b81be32e5 100644 --- a/pkg/pr/manager/check.go +++ b/pkg/pr/manager/check.go @@ -3,7 +3,6 @@ package manager import ( "context" - "github.com/horizoncd/horizon/lib/q" "gorm.io/gorm" "github.com/horizoncd/horizon/core/common" @@ -11,6 +10,9 @@ import ( "github.com/horizoncd/horizon/pkg/pr/models" ) +// nolint +// +//go:generate mockgen -source=$GOFILE -destination=../../../mock/pkg/pipelinerun/manager/mock_check_manager.go type CheckManager interface { // Create create a check Create(ctx context.Context, check *models.Check) (*models.Check, error) @@ -19,7 +21,7 @@ type CheckManager interface { // GetByResource get checks by resource GetByResource(ctx context.Context, resources ...common.Resource) ([]*models.Check, error) GetCheckRunByID(ctx context.Context, checkRunID uint) (*models.CheckRun, error) - ListCheckRuns(ctx context.Context, query *q.Query) ([]*models.CheckRun, error) + ListCheckRuns(ctx context.Context, pipelinerunID uint) ([]*models.CheckRun, error) CreateCheckRun(ctx context.Context, checkRun *models.CheckRun) (*models.CheckRun, error) } @@ -49,11 +51,8 @@ func (m *checkManager) GetCheckRunByID(ctx context.Context, checkRunID uint) (*m return m.dao.GetCheckRunByID(ctx, checkRunID) } -func (m *checkManager) ListCheckRuns(ctx context.Context, query *q.Query) ([]*models.CheckRun, error) { - if query == nil { - query = &q.Query{} - } - return m.dao.ListCheckRuns(ctx, query) +func (m *checkManager) ListCheckRuns(ctx context.Context, pipelinerunID uint) ([]*models.CheckRun, error) { + return m.dao.ListCheckRuns(ctx, pipelinerunID) } func (m *checkManager) CreateCheckRun(ctx context.Context, checkRun *models.CheckRun) (*models.CheckRun, error) { diff --git a/pkg/pr/manager/check_test.go b/pkg/pr/manager/check_test.go index 041795630..04741cc51 100644 --- a/pkg/pr/manager/check_test.go +++ b/pkg/pr/manager/check_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/horizoncd/horizon/core/common" - "github.com/horizoncd/horizon/lib/q" "github.com/horizoncd/horizon/pkg/pr/models" "github.com/stretchr/testify/assert" @@ -31,7 +30,7 @@ func TestCheck(t *testing.T) { checkRun := &models.CheckRun{ PipelineRunID: 10, CheckID: createdCheck.ResourceID, - Status: models.CheckStatusQueue, + Status: models.CheckStatusPending, } _, err = checkManager.CreateCheckRun(ctx, checkRun) assert.NoError(t, err) @@ -51,10 +50,7 @@ func TestCheck(t *testing.T) { assert.Len(t, checks, 1) // Test ListCheckRuns - keyWords := make(map[string]interface{}) - keyWords[common.CheckrunQueryByPipelinerunID] = checkRun.PipelineRunID - query := q.New(keyWords) - checkRuns, err := checkManager.ListCheckRuns(ctx, query) + checkRuns, err := checkManager.ListCheckRuns(ctx, checkRun.PipelineRunID) assert.NoError(t, err) assert.Len(t, checkRuns, 1) assert.Equal(t, checkRuns[0].Status, models.CheckStatusInProgress) diff --git a/pkg/pr/models/check.go b/pkg/pr/models/check.go index 46aacf124..0eacd6b15 100644 --- a/pkg/pr/models/check.go +++ b/pkg/pr/models/check.go @@ -8,7 +8,7 @@ import ( type CheckRunStatus string const ( - CheckStatusQueue CheckRunStatus = "Queue" + CheckStatusPending CheckRunStatus = "Pending" CheckStatusInProgress CheckRunStatus = "InProgress" CheckStatusSuccess CheckRunStatus = "Success" CheckStatusFailure CheckRunStatus = "Failure" @@ -16,7 +16,7 @@ const ( ) var CheckRunStatusArr = [...]CheckRunStatus{ - CheckStatusQueue, + CheckStatusPending, CheckStatusInProgress, CheckStatusSuccess, CheckStatusFailure, @@ -29,7 +29,7 @@ func String2CheckRunStatus(s string) CheckRunStatus { return status } } - return CheckStatusQueue + return CheckStatusPending } type Check struct { diff --git a/pkg/rbac/auth.go b/pkg/rbac/auth.go index 2abfd29b3..749fb3aef 100644 --- a/pkg/rbac/auth.go +++ b/pkg/rbac/auth.go @@ -68,7 +68,7 @@ func (a *authorizer) Authorize(ctx context.Context, attr auth.Attributes) (auth. return auth.DecisionAllow, AdminAllow, nil } - // TODO(tom): members and pipelineruns and environments need to add to auth check + // TODO(tom): members, users, accesstokens and environments need to add to auth check if attr.IsResourceRequest() && (attr.GetResource() == "members" || attr.GetResource() == "environments" || attr.GetResource() == "users" || attr.GetResource() == "personalaccesstokens" || From 6cb1bb9fd4193f12901a702f27473ddbfc1ec4bc Mon Sep 17 00:00:00 2001 From: "xu.zhu" Date: Wed, 20 Sep 2023 17:04:44 +0800 Subject: [PATCH 09/11] fix: lint and ut Signed-off-by: xu.zhu --- core/common/pipelinerun.go | 6 ----- core/http/api/v2/pipelinerun/apis.go | 35 ---------------------------- 2 files changed, 41 deletions(-) diff --git a/core/common/pipelinerun.go b/core/common/pipelinerun.go index c7cdbd758..929c2456b 100644 --- a/core/common/pipelinerun.go +++ b/core/common/pipelinerun.go @@ -2,10 +2,4 @@ package common const ( PipelineQueryByStatus = "status" - - CheckrunQueryFilter = "filter" - CheckrunQueryByStatus = "status" - CheckrunQueryByPipelinerunID = "pipelinerunID" - CheckrunQueryByCheckID = "checkID" - CheckrunQueryByDetailURL = "detailURL" ) diff --git a/core/http/api/v2/pipelinerun/apis.go b/core/http/api/v2/pipelinerun/apis.go index 83be3c546..37cb3ee8f 100644 --- a/core/http/api/v2/pipelinerun/apis.go +++ b/core/http/api/v2/pipelinerun/apis.go @@ -316,38 +316,3 @@ func (a *API) withCheckrunID(c *gin.Context, f func(pipelineRunID uint)) { } f(uint(id)) } - -func parseContext(c *gin.Context) *q.Query { - keywords := make(map[string]interface{}) - - filter := c.Query(common.CheckrunQueryFilter) - if filter != "" { - keywords[common.CheckrunQueryFilter] = filter - } - - status := c.Query(common.CheckrunQueryByStatus) - if status != "" { - keywords[common.CheckrunQueryByStatus] = status - } - - pipelinerunIDStr := c.Query(common.CheckrunQueryByPipelinerunID) - if pipelinerunIDStr != "" { - pipelinerunID, err := strconv.ParseUint(pipelinerunIDStr, 10, 0) - if err != nil { - response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) - return nil - } - keywords[common.CheckrunQueryByPipelinerunID] = pipelinerunID - } - - checkIDStr := c.Query(common.CheckrunQueryByCheckID) - if checkIDStr != "" { - checkID, err := strconv.ParseUint(checkIDStr, 10, 0) - if err != nil { - response.AbortWithRequestError(c, common.InvalidRequestParam, err.Error()) - return nil - } - keywords[common.CheckrunQueryByCheckID] = checkID - } - return q.New(keywords) -} From d5056710a992852f1ac0cb6e81753e4ad414620e Mon Sep 17 00:00:00 2001 From: "xu.zhu" Date: Wed, 20 Sep 2023 21:46:47 +0800 Subject: [PATCH 10/11] fix: bugs Signed-off-by: xu.zhu --- core/controller/pipelinerun/controller.go | 6 +++++- core/http/api/v2/cluster/apis_basic.go | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/core/controller/pipelinerun/controller.go b/core/controller/pipelinerun/controller.go index 200c4fcd2..51fc0d60c 100644 --- a/core/controller/pipelinerun/controller.go +++ b/core/controller/pipelinerun/controller.go @@ -441,6 +441,10 @@ func (c *controller) execute(ctx context.Context, pr *prmodels.Pipelinerun) erro case codemodels.GitRefTypeBranch: prGit.Branch = pr.GitRef } + pipelineJSONBlob := make(map[string]interface{}) + if clusterFiles.PipelineJSONBlob != nil { + pipelineJSONBlob = clusterFiles.PipelineJSONBlob + } ciEventID, err := tektonClient.CreatePipelineRun(ctx, &tekton.PipelineRun{ Action: pr.Action, @@ -453,7 +457,7 @@ func (c *controller) execute(ctx context.Context, pr *prmodels.Pipelinerun) erro ImageURL: pr.ImageURL, Operator: currentUser.GetEmail(), PipelinerunID: pr.ID, - PipelineJSONBlob: clusterFiles.PipelineJSONBlob, + PipelineJSONBlob: pipelineJSONBlob, Region: cluster.RegionName, RegionID: regionEntity.ID, Template: cluster.Template, diff --git a/core/http/api/v2/cluster/apis_basic.go b/core/http/api/v2/cluster/apis_basic.go index 0e01b1dd7..22299eb77 100644 --- a/core/http/api/v2/cluster/apis_basic.go +++ b/core/http/api/v2/cluster/apis_basic.go @@ -549,6 +549,11 @@ func (a *API) CreatePipelineRun(c *gin.Context) { response.AbortWithRPCError(c, rpcerror.NotFoundError.WithErrMsg(err.Error())) return } + if perror.Cause(err) == herrors.ErrClusterNoChange || perror.Cause(err) == herrors.ErrShouldBuildDeployFirst { + log.WithFiled(c, "op", op).Errorf("%+v", err) + response.AbortWithRPCError(c, rpcerror.BadRequestError.WithErrMsg(err.Error())) + return + } log.WithFiled(c, "op", op).Errorf("%+v", err) response.AbortWithRPCError(c, rpcerror.InternalError.WithErrMsg(err.Error())) return From a5203e3d87a39ac4eef4d05bc41950c9e7fa3334 Mon Sep 17 00:00:00 2001 From: "xu.zhu" Date: Thu, 21 Sep 2023 17:18:18 +0800 Subject: [PATCH 11/11] fix: sql Signed-off-by: xu.zhu --- db/20230817.sql | 2 +- db/migrations/20230817_add_check.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db/20230817.sql b/db/20230817.sql index 40dd64566..6082d8aa2 100644 --- a/db/20230817.sql +++ b/db/20230817.sql @@ -55,7 +55,7 @@ CREATE TABLE `tb_pr_msg` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `pipeline_run_id` bigint(20) unsigned NOT NULL COMMENT 'pipeline run id', - `content` text NOT NULL DEFAULT '' COMMENT 'content of message', + `content` text NOT NULL COMMENT 'content of message', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator', diff --git a/db/migrations/20230817_add_check.sql b/db/migrations/20230817_add_check.sql index ecad1a9f1..0ded0a943 100644 --- a/db/migrations/20230817_add_check.sql +++ b/db/migrations/20230817_add_check.sql @@ -41,7 +41,7 @@ CREATE TABLE `tb_pr_msg` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `pipeline_run_id` bigint(20) unsigned NOT NULL COMMENT 'pipeline run id', - `content` text NOT NULL DEFAULT '' COMMENT 'content of message', + `content` text NOT NULL COMMENT 'content of message', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `created_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'creator',