Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: support for pipelinerun checks #193

Merged
merged 11 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion core/common/pipelinerun.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
package common

const PipelineQueryByStatus = "status"
const (
PipelineQueryByStatus = "status"

CheckrunQueryFilter = "filter"
CheckrunQueryByStatus = "status"
CheckrunQueryByPipelinerunID = "pipelinerunID"
CheckrunQueryByCheckID = "checkID"
CheckrunQueryByDetailURL = "detailURL"
)
15 changes: 15 additions & 0 deletions core/controller/cluster/controller_basic_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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())
}
}
6 changes: 3 additions & 3 deletions core/controller/cluster/controller_internal_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,16 +178,16 @@ 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,
Commit: configCommit.Gitops,
}, 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,
Expand Down
133 changes: 114 additions & 19 deletions core/controller/pipelinerun/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"fmt"
"net/http"
"strconv"
"time"

"github.com/horizoncd/horizon/core/common"
"github.com/horizoncd/horizon/core/config"
Expand All @@ -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"
Expand All @@ -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 {
Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -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 {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method controller.execute has 79 lines of code (exceeds 50 allowed). Consider refactoring.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method controller.execute has 12 return statements (exceeds 4 allowed).

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method controller.execute has 83 lines of code (exceeds 50 allowed). Consider refactoring.

currentUser, err := common.UserFromContext(ctx)
if err != nil {
return err
Expand Down Expand Up @@ -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
Expand All @@ -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()
xuzhu-591 marked this conversation as resolved.
Show resolved Hide resolved
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()
xuzhu-591 marked this conversation as resolved.
Show resolved Hide resolved

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()

Expand All @@ -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(),
Expand Down Expand Up @@ -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 {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method controller.updatePrStatus has 5 return statements (exceeds 4 allowed).

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,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method controller.calculatePrSuccessStatus has 6 return statements (exceeds 4 allowed).

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
}
7 changes: 5 additions & 2 deletions core/controller/pipelinerun/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,15 +539,18 @@ 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",
DetailURL: "https://www.google.com",
})
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)
}
Expand Down
13 changes: 7 additions & 6 deletions core/controller/pipelinerun/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
Loading