You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by GitBox <gi...@apache.org> on 2022/09/13 03:17:13 UTC

[GitHub] [incubator-devlake] likyh opened a new pull request, #3052: feat: finish pipeline and issue webhook

likyh opened a new pull request, #3052:
URL: https://github.com/apache/incubator-devlake/pull/3052

   # Summary
   
   finish pipeline and issue webhook
   
   ### Does this close any open issues?
   Closes #3023
   
   ### test
   
   #### post a pipeline
   curl http://127.0.0.1:8080/plugins/webhook/1/cicd_pipeline -X 'POST' -d '{"platform":"gitlab","id":"A123123","result":"ABORT","status":"DONE","type":"CI/CD","duration_sec":1,"created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00"}'
   ```{"success":true,"message":"success"}```
   
   #### post issue
   curl http://127.0.0.1:8080/plugins/webhook/1/issue -X 'POST' -d '{"board_key":"DLK","url":"","issue_key":"DLK-1235","title":"a feature from DLK","description":s":"TODO","original_status":"created","story_point":0,"resolution_date":null,"created_date":"2020-01-01T12:00:00+00:00","updated_date":null,"lead_time_minutes":0,"parent_issue_key":"DLK-1200","priority":"","original_estimate_minutes":0,"time_spent_minutes":0,"time_remaining_minutes":0,"creator_id":"user1131","creator_name":"Nick name 1","assignee_id":"user1132","assignee_name":"Nick name 2","severity":"","component":""}'
   ```{"success":true,"message":"success"}```
   
   #### close issue
   curl http://12/DLK/DLK-1235/close -X 'POST'


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] klesh merged pull request #3052: feat: finish pipeline and issue webhook

Posted by GitBox <gi...@apache.org>.
klesh merged PR #3052:
URL: https://github.com/apache/incubator-devlake/pull/3052


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on a diff in pull request #3052: feat: finish pipeline and issue webhook

Posted by GitBox <gi...@apache.org>.
likyh commented on code in PR #3052:
URL: https://github.com/apache/incubator-devlake/pull/3052#discussion_r973741454


##########
plugins/webhook/api/cicd_pipeline.go:
##########
@@ -18,41 +18,202 @@ limitations under the License.
 package api
 
 import (
+	"fmt"
 	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models/domainlayer"
+	"github.com/apache/incubator-devlake/models/domainlayer/devops"
+	"github.com/apache/incubator-devlake/models/domainlayer/ticket"
 	"github.com/apache/incubator-devlake/plugins/core"
+	"github.com/apache/incubator-devlake/plugins/core/dal"
+	"github.com/apache/incubator-devlake/plugins/helper"
 	"github.com/apache/incubator-devlake/plugins/webhook/models"
+	"github.com/go-playground/validator/v10"
 	"net/http"
 	"time"
 )
 
-type WebhookPipelineRequest struct {
-	Id           string     `validate:"required"`
-	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT"`
+type WebhookTaskRequest struct {
+	// PipelineName can be filled by any string unique in one pipeline
+	PipelineName string `mapstructure:"pipeline_name" validate:"required"`
+
+	Name         string     `validate:"required"` // Name should be unique in one pipeline
+	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT IN_PROGRESS"`
 	Status       string     `validate:"oneof=IN_PROGRESS DONE"`
 	Type         string     `validate:"oneof=CI CD CI/CD"`
-	CreatedDate  time.Time  `mapstructure:"created_date" validate:"required"`
+	StartedDate  time.Time  `mapstructure:"created_date" validate:"required"`
 	FinishedDate *time.Time `mapstructure:"finished_date"`
 
-	Repo      string `validate:"required"`
+	RepoId    string `mapstructure:"repo_id" validate:"required"` // RepoId should be unique string
 	Branch    string
 	CommitSha string `mapstructure:"commit_sha"`
 }
 
-// PostCicdPipeline
+// PostCicdTask
 // @Summary create pipeline by webhook
-// @Description Create pipeline by webhook, example: {"id":"A123123","result":"one of SUCCESS/FAILURE/ABORT","status":"one of IN_PROGRESS/DONE","type":"CI/CD","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}
+// @Description Create pipeline by webhook.<br/>
+// @Description example1: {"pipeline_name":"A123","name":"unit-test","result":"IN_PROGRESS","status":"IN_PROGRESS","type":"CI","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo_id":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}<br/>
+// @Description example2: {"pipeline_name":"A123","name":"unit-test","result":"SUCCESS","status":"DONE","type":"CI/CD","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo_id":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}<br/>
+// @Description When request webhook first time for each pipeline, it will be created.
+// @Description So we suggest request before task start and after pipeline finish.
+// @Description Remember fill all data to request after pipeline finish.
 // @Tags plugins/webhook
-// @Param body body WebhookPipelineRequest true "json body"
+// @Param body body WebhookTaskRequest true "json body"
 // @Success 200
 // @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 403  {string} errcode.Error "Forbidden"
 // @Failure 500  {string} errcode.Error "Internal Error"
-// @Router /plugins/webhook/:connectionId/cicd_pipelines [POST]
-func PostCicdPipeline(input *core.ApiResourceInput) (*core.ApiResourceOutput, errors.Error) {
+// @Router /plugins/webhook/:connectionId/cicd_tasks [POST]
+func PostCicdTask(input *core.ApiResourceInput) (*core.ApiResourceOutput, errors.Error) {
 	connection := &models.WebhookConnection{}
 	err := connectionHelper.First(connection, input.Params)
 	if err != nil {
 		return nil, err
 	}
-	// TODO save pipeline
+	// get request
+	request := &WebhookTaskRequest{}
+	err = helper.DecodeMapStruct(input.Body, request)
+	if err != nil {
+		return &core.ApiResourceOutput{Body: err.Error(), Status: http.StatusBadRequest}, nil
+	}
+	// validate
+	vld = validator.New()
+	err = errors.BadInput.Wrap(vld.Struct(request), `input json error`)
+	if err != nil {
+		return &core.ApiResourceOutput{Body: err.Error(), Status: http.StatusBadRequest}, nil
+	}
+
+	db := basicRes.GetDal()
+	pipelineId := fmt.Sprintf("%s:%d:%s", "webhook", connection.ID, request.PipelineName)
+	domainCicdTask := &devops.CICDTask{
+		DomainEntity: domainlayer.DomainEntity{
+			Id: fmt.Sprintf("%s:%d:%s:%s", "webhook", connection.ID, request.PipelineName, request.Name),
+		},
+		PipelineId:   pipelineId,
+		Name:         request.Name,
+		Result:       request.Result,
+		Status:       request.Status,
+		Type:         request.Type,
+		StartedDate:  request.StartedDate,
+		FinishedDate: request.FinishedDate,
+	}
+	if domainCicdTask.FinishedDate != nil {
+		domainCicdTask.DurationSec = uint64(domainCicdTask.FinishedDate.Sub(domainCicdTask.StartedDate).Seconds())
+	}
+
+	domainPipeline := &devops.CICDPipeline{}
+	err = db.First(domainPipeline, dal.Where("id = ?", pipelineId))
+	if err != nil {
+		domainPipeline = &devops.CICDPipeline{
+			DomainEntity: domainlayer.DomainEntity{
+				Id: pipelineId,
+			},
+			Name:         request.PipelineName,
+			Result:       ``,
+			Status:       `IN_PROGRESS`,
+			Type:         ``,
+			CreatedDate:  request.StartedDate,
+			FinishedDate: nil,
+		}
+	} else if domainPipeline.Status == `DONE` {
+		return nil, errors.Forbidden.New(`can not receive this task because pipeline has already been done.`)
+	}
+
+	domainPipelineRepo := &devops.CiCDPipelineCommit{
+		PipelineId: pipelineId,
+		CommitSha:  request.CommitSha,
+		Branch:     request.Branch,
+		RepoId:     request.RepoId,
+	}
+
+	// save
+	err = db.CreateOrUpdate(domainCicdTask)
+	if err != nil {
+		return nil, err
+	}
+	err = db.CreateOrUpdate(domainPipeline)
+	if err != nil {
+		return nil, err
+	}
+	err = db.CreateOrUpdate(domainPipelineRepo)
+	if err != nil {
+		return nil, err
+	}
+
 	return &core.ApiResourceOutput{Body: nil, Status: http.StatusOK}, nil
 }
+
+// PostPipelineFinish
+// @Summary set pipeline's status to DONE
+// @Description set pipeline's status to DONE and cal duration
+// @Tags plugins/webhook
+// @Success 200
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /plugins/webhook/:connectionId/cicd_pipeline/:pipelineName/finish [POST]
+func PostPipelineFinish(input *core.ApiResourceInput) (*core.ApiResourceOutput, errors.Error) {
+	connection := &models.WebhookConnection{}
+	err := connectionHelper.First(connection, input.Params)
+	if err != nil {
+		return nil, err
+	}
+
+	db := basicRes.GetDal()
+	pipelineId := fmt.Sprintf("%s:%d:%s", "webhook", connection.ID, input.Params[`pipelineName`])
+	println(pipelineId)
+	domainPipeline := &devops.CICDPipeline{}
+	err = db.First(domainPipeline, dal.Where("id = ?", pipelineId))
+	if err != nil {
+		return nil, errors.NotFound.Wrap(err, `pipeline not found`)
+	}
+
+	domainTasks := []devops.CICDTask{}
+	err = db.All(&domainTasks, dal.Where("pipeline_id = ?", pipelineId))
+	if err != nil {
+		return nil, errors.NotFound.Wrap(err, `tasks not found`)
+	}
+	typeHasCi, typeHasCd, result := getTypeAndResultFromTasks(domainTasks)
+	if typeHasCi && typeHasCd {
+		domainPipeline.Type = `CI/CD`
+	} else if typeHasCi {
+		domainPipeline.Type = `CI`
+	} else if typeHasCd {
+		domainPipeline.Type = `CD`
+	}
+	domainPipeline.Result = result
+	domainPipeline.Status = ticket.DONE
+	now := time.Now()
+	domainPipeline.FinishedDate = &now
+	domainPipeline.DurationSec = uint64(domainPipeline.FinishedDate.Sub(domainPipeline.CreatedDate).Seconds())
+
+	// save
+	err = db.Update(domainPipeline)
+	if err != nil {
+		return nil, err
+	}
+
+	return &core.ApiResourceOutput{Body: nil, Status: http.StatusOK}, nil
+}
+
+func getTypeAndResultFromTasks(domainTasks []devops.CICDTask) (typeHasCi bool, typeHasCd bool, result string) {
+	typeHasCi = false
+	typeHasCd = false
+	result = `SUCCESS`
+	for _, domainTask := range domainTasks {
+		if domainTask.Type == `CI/CD` {

Review Comment:
   fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] klesh commented on a diff in pull request #3052: feat: finish pipeline and issue webhook

Posted by GitBox <gi...@apache.org>.
klesh commented on code in PR #3052:
URL: https://github.com/apache/incubator-devlake/pull/3052#discussion_r971593073


##########
plugins/webhook/api/cicd_pipeline.go:
##########
@@ -53,6 +58,51 @@ func PostCicdPipeline(input *core.ApiResourceInput) (*core.ApiResourceOutput, er
 	if err != nil {
 		return nil, err
 	}
-	// TODO save pipeline
+	// get request
+	request := &WebhookPipelineRequest{}
+	err = helper.DecodeMapStruct(input.Body, request)
+	if err != nil {
+		return &core.ApiResourceOutput{Body: err.Error(), Status: http.StatusBadRequest}, nil
+	}
+	// validate
+	vld = validator.New()
+	err = errors.Convert(vld.Struct(request))
+	if err != nil {
+		return &core.ApiResourceOutput{Body: err.Error(), Status: http.StatusBadRequest}, nil
+	}
+
+	db := basicRes.GetDal()
+	domainPipeline := &devops.CICDPipeline{
+		DomainEntity: domainlayer.DomainEntity{
+			Id: fmt.Sprintf("%s:%d:%s:%s:%s:%s", "webhook", connection.ID, request.Repo, request.Branch, request.CommitSha, request.Id),
+		},
+		Name:         request.Id,

Review Comment:
   Why use different naming? can we rename `request.Id` to `Name`?
   



##########
plugins/webhook/api/cicd_pipeline.go:
##########
@@ -18,9 +18,14 @@ limitations under the License.
 package api
 

Review Comment:
   According to the latest discussion, we decided `deployment` should be a `type` of `cicd_tasks`.
   We have to rename this webhook to  `cicd_tasks`



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] klesh commented on a diff in pull request #3052: feat: finish pipeline and issue webhook

Posted by GitBox <gi...@apache.org>.
klesh commented on code in PR #3052:
URL: https://github.com/apache/incubator-devlake/pull/3052#discussion_r972634803


##########
plugins/webhook/api/cicd_pipeline.go:
##########
@@ -18,41 +18,202 @@ limitations under the License.
 package api
 
 import (
+	"fmt"
 	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models/domainlayer"
+	"github.com/apache/incubator-devlake/models/domainlayer/devops"
+	"github.com/apache/incubator-devlake/models/domainlayer/ticket"
 	"github.com/apache/incubator-devlake/plugins/core"
+	"github.com/apache/incubator-devlake/plugins/core/dal"
+	"github.com/apache/incubator-devlake/plugins/helper"
 	"github.com/apache/incubator-devlake/plugins/webhook/models"
+	"github.com/go-playground/validator/v10"
 	"net/http"
 	"time"
 )
 
-type WebhookPipelineRequest struct {
-	Id           string     `validate:"required"`
-	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT"`
+type WebhookTaskRequest struct {
+	// PipelineName can be filled by any string unique in one pipeline
+	PipelineName string `mapstructure:"pipeline_name" validate:"required"`
+
+	Name         string     `validate:"required"` // Name should be unique in one pipeline
+	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT IN_PROGRESS"`
 	Status       string     `validate:"oneof=IN_PROGRESS DONE"`
 	Type         string     `validate:"oneof=CI CD CI/CD"`
-	CreatedDate  time.Time  `mapstructure:"created_date" validate:"required"`
+	StartedDate  time.Time  `mapstructure:"created_date" validate:"required"`
 	FinishedDate *time.Time `mapstructure:"finished_date"`
 
-	Repo      string `validate:"required"`
+	RepoId    string `mapstructure:"repo_id" validate:"required"` // RepoId should be unique string
 	Branch    string
 	CommitSha string `mapstructure:"commit_sha"`
 }
 
-// PostCicdPipeline
+// PostCicdTask
 // @Summary create pipeline by webhook
-// @Description Create pipeline by webhook, example: {"id":"A123123","result":"one of SUCCESS/FAILURE/ABORT","status":"one of IN_PROGRESS/DONE","type":"CI/CD","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}
+// @Description Create pipeline by webhook.<br/>
+// @Description example1: {"pipeline_name":"A123","name":"unit-test","result":"IN_PROGRESS","status":"IN_PROGRESS","type":"CI","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo_id":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}<br/>

Review Comment:
   The `type` field should be updated to one of `TEST,LINT,BUILD,DEPLOYMENT`, and must not be empty



##########
plugins/webhook/api/cicd_pipeline.go:
##########
@@ -18,41 +18,202 @@ limitations under the License.
 package api
 
 import (
+	"fmt"
 	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models/domainlayer"
+	"github.com/apache/incubator-devlake/models/domainlayer/devops"
+	"github.com/apache/incubator-devlake/models/domainlayer/ticket"
 	"github.com/apache/incubator-devlake/plugins/core"
+	"github.com/apache/incubator-devlake/plugins/core/dal"
+	"github.com/apache/incubator-devlake/plugins/helper"
 	"github.com/apache/incubator-devlake/plugins/webhook/models"
+	"github.com/go-playground/validator/v10"
 	"net/http"
 	"time"
 )
 
-type WebhookPipelineRequest struct {
-	Id           string     `validate:"required"`
-	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT"`
+type WebhookTaskRequest struct {
+	// PipelineName can be filled by any string unique in one pipeline
+	PipelineName string `mapstructure:"pipeline_name" validate:"required"`
+
+	Name         string     `validate:"required"` // Name should be unique in one pipeline
+	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT IN_PROGRESS"`
 	Status       string     `validate:"oneof=IN_PROGRESS DONE"`
 	Type         string     `validate:"oneof=CI CD CI/CD"`

Review Comment:
   The `type` field should be updated to one of `TEST,LINT,BUILD,DEPLOYMENT`, and must not be empty



##########
plugins/webhook/api/cicd_pipeline.go:
##########
@@ -18,41 +18,202 @@ limitations under the License.
 package api
 
 import (
+	"fmt"
 	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models/domainlayer"
+	"github.com/apache/incubator-devlake/models/domainlayer/devops"
+	"github.com/apache/incubator-devlake/models/domainlayer/ticket"
 	"github.com/apache/incubator-devlake/plugins/core"
+	"github.com/apache/incubator-devlake/plugins/core/dal"
+	"github.com/apache/incubator-devlake/plugins/helper"
 	"github.com/apache/incubator-devlake/plugins/webhook/models"
+	"github.com/go-playground/validator/v10"
 	"net/http"
 	"time"
 )
 
-type WebhookPipelineRequest struct {
-	Id           string     `validate:"required"`
-	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT"`
+type WebhookTaskRequest struct {
+	// PipelineName can be filled by any string unique in one pipeline
+	PipelineName string `mapstructure:"pipeline_name" validate:"required"`
+
+	Name         string     `validate:"required"` // Name should be unique in one pipeline
+	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT IN_PROGRESS"`
 	Status       string     `validate:"oneof=IN_PROGRESS DONE"`
 	Type         string     `validate:"oneof=CI CD CI/CD"`
-	CreatedDate  time.Time  `mapstructure:"created_date" validate:"required"`
+	StartedDate  time.Time  `mapstructure:"created_date" validate:"required"`
 	FinishedDate *time.Time `mapstructure:"finished_date"`
 
-	Repo      string `validate:"required"`
+	RepoId    string `mapstructure:"repo_id" validate:"required"` // RepoId should be unique string
 	Branch    string
 	CommitSha string `mapstructure:"commit_sha"`
 }
 
-// PostCicdPipeline
+// PostCicdTask
 // @Summary create pipeline by webhook
-// @Description Create pipeline by webhook, example: {"id":"A123123","result":"one of SUCCESS/FAILURE/ABORT","status":"one of IN_PROGRESS/DONE","type":"CI/CD","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}
+// @Description Create pipeline by webhook.<br/>
+// @Description example1: {"pipeline_name":"A123","name":"unit-test","result":"IN_PROGRESS","status":"IN_PROGRESS","type":"CI","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo_id":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}<br/>
+// @Description example2: {"pipeline_name":"A123","name":"unit-test","result":"SUCCESS","status":"DONE","type":"CI/CD","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo_id":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}<br/>
+// @Description When request webhook first time for each pipeline, it will be created.
+// @Description So we suggest request before task start and after pipeline finish.
+// @Description Remember fill all data to request after pipeline finish.
 // @Tags plugins/webhook
-// @Param body body WebhookPipelineRequest true "json body"
+// @Param body body WebhookTaskRequest true "json body"
 // @Success 200
 // @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 403  {string} errcode.Error "Forbidden"
 // @Failure 500  {string} errcode.Error "Internal Error"
-// @Router /plugins/webhook/:connectionId/cicd_pipelines [POST]
-func PostCicdPipeline(input *core.ApiResourceInput) (*core.ApiResourceOutput, errors.Error) {
+// @Router /plugins/webhook/:connectionId/cicd_tasks [POST]
+func PostCicdTask(input *core.ApiResourceInput) (*core.ApiResourceOutput, errors.Error) {
 	connection := &models.WebhookConnection{}
 	err := connectionHelper.First(connection, input.Params)
 	if err != nil {
 		return nil, err
 	}
-	// TODO save pipeline
+	// get request
+	request := &WebhookTaskRequest{}
+	err = helper.DecodeMapStruct(input.Body, request)
+	if err != nil {
+		return &core.ApiResourceOutput{Body: err.Error(), Status: http.StatusBadRequest}, nil
+	}
+	// validate
+	vld = validator.New()
+	err = errors.BadInput.Wrap(vld.Struct(request), `input json error`)
+	if err != nil {
+		return &core.ApiResourceOutput{Body: err.Error(), Status: http.StatusBadRequest}, nil
+	}
+
+	db := basicRes.GetDal()
+	pipelineId := fmt.Sprintf("%s:%d:%s", "webhook", connection.ID, request.PipelineName)
+	domainCicdTask := &devops.CICDTask{
+		DomainEntity: domainlayer.DomainEntity{
+			Id: fmt.Sprintf("%s:%d:%s:%s", "webhook", connection.ID, request.PipelineName, request.Name),
+		},
+		PipelineId:   pipelineId,
+		Name:         request.Name,
+		Result:       request.Result,
+		Status:       request.Status,
+		Type:         request.Type,
+		StartedDate:  request.StartedDate,
+		FinishedDate: request.FinishedDate,
+	}
+	if domainCicdTask.FinishedDate != nil {
+		domainCicdTask.DurationSec = uint64(domainCicdTask.FinishedDate.Sub(domainCicdTask.StartedDate).Seconds())
+	}
+
+	domainPipeline := &devops.CICDPipeline{}
+	err = db.First(domainPipeline, dal.Where("id = ?", pipelineId))
+	if err != nil {
+		domainPipeline = &devops.CICDPipeline{
+			DomainEntity: domainlayer.DomainEntity{
+				Id: pipelineId,
+			},
+			Name:         request.PipelineName,
+			Result:       ``,
+			Status:       `IN_PROGRESS`,
+			Type:         ``,
+			CreatedDate:  request.StartedDate,
+			FinishedDate: nil,
+		}
+	} else if domainPipeline.Status == `DONE` {
+		return nil, errors.Forbidden.New(`can not receive this task because pipeline has already been done.`)
+	}
+
+	domainPipelineRepo := &devops.CiCDPipelineCommit{
+		PipelineId: pipelineId,
+		CommitSha:  request.CommitSha,
+		Branch:     request.Branch,
+		RepoId:     request.RepoId,
+	}
+
+	// save
+	err = db.CreateOrUpdate(domainCicdTask)
+	if err != nil {
+		return nil, err
+	}
+	err = db.CreateOrUpdate(domainPipeline)
+	if err != nil {
+		return nil, err
+	}
+	err = db.CreateOrUpdate(domainPipelineRepo)
+	if err != nil {
+		return nil, err
+	}
+
 	return &core.ApiResourceOutput{Body: nil, Status: http.StatusOK}, nil
 }
+
+// PostPipelineFinish
+// @Summary set pipeline's status to DONE
+// @Description set pipeline's status to DONE and cal duration
+// @Tags plugins/webhook
+// @Success 200
+// @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 500  {string} errcode.Error "Internal Error"
+// @Router /plugins/webhook/:connectionId/cicd_pipeline/:pipelineName/finish [POST]
+func PostPipelineFinish(input *core.ApiResourceInput) (*core.ApiResourceOutput, errors.Error) {
+	connection := &models.WebhookConnection{}
+	err := connectionHelper.First(connection, input.Params)
+	if err != nil {
+		return nil, err
+	}
+
+	db := basicRes.GetDal()
+	pipelineId := fmt.Sprintf("%s:%d:%s", "webhook", connection.ID, input.Params[`pipelineName`])
+	println(pipelineId)
+	domainPipeline := &devops.CICDPipeline{}
+	err = db.First(domainPipeline, dal.Where("id = ?", pipelineId))
+	if err != nil {
+		return nil, errors.NotFound.Wrap(err, `pipeline not found`)
+	}
+
+	domainTasks := []devops.CICDTask{}
+	err = db.All(&domainTasks, dal.Where("pipeline_id = ?", pipelineId))
+	if err != nil {
+		return nil, errors.NotFound.Wrap(err, `tasks not found`)
+	}
+	typeHasCi, typeHasCd, result := getTypeAndResultFromTasks(domainTasks)
+	if typeHasCi && typeHasCd {
+		domainPipeline.Type = `CI/CD`
+	} else if typeHasCi {
+		domainPipeline.Type = `CI`
+	} else if typeHasCd {
+		domainPipeline.Type = `CD`
+	}
+	domainPipeline.Result = result
+	domainPipeline.Status = ticket.DONE
+	now := time.Now()
+	domainPipeline.FinishedDate = &now
+	domainPipeline.DurationSec = uint64(domainPipeline.FinishedDate.Sub(domainPipeline.CreatedDate).Seconds())
+
+	// save
+	err = db.Update(domainPipeline)
+	if err != nil {
+		return nil, err
+	}
+
+	return &core.ApiResourceOutput{Body: nil, Status: http.StatusOK}, nil
+}
+
+func getTypeAndResultFromTasks(domainTasks []devops.CICDTask) (typeHasCi bool, typeHasCd bool, result string) {
+	typeHasCi = false
+	typeHasCd = false
+	result = `SUCCESS`
+	for _, domainTask := range domainTasks {
+		if domainTask.Type == `CI/CD` {

Review Comment:
   Note that the cicd_tasks Type has been changed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on a diff in pull request #3052: feat: finish pipeline and issue webhook

Posted by GitBox <gi...@apache.org>.
likyh commented on code in PR #3052:
URL: https://github.com/apache/incubator-devlake/pull/3052#discussion_r973741525


##########
plugins/webhook/api/cicd_pipeline.go:
##########
@@ -18,41 +18,202 @@ limitations under the License.
 package api
 
 import (
+	"fmt"
 	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models/domainlayer"
+	"github.com/apache/incubator-devlake/models/domainlayer/devops"
+	"github.com/apache/incubator-devlake/models/domainlayer/ticket"
 	"github.com/apache/incubator-devlake/plugins/core"
+	"github.com/apache/incubator-devlake/plugins/core/dal"
+	"github.com/apache/incubator-devlake/plugins/helper"
 	"github.com/apache/incubator-devlake/plugins/webhook/models"
+	"github.com/go-playground/validator/v10"
 	"net/http"
 	"time"
 )
 
-type WebhookPipelineRequest struct {
-	Id           string     `validate:"required"`
-	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT"`
+type WebhookTaskRequest struct {
+	// PipelineName can be filled by any string unique in one pipeline
+	PipelineName string `mapstructure:"pipeline_name" validate:"required"`
+
+	Name         string     `validate:"required"` // Name should be unique in one pipeline
+	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT IN_PROGRESS"`
 	Status       string     `validate:"oneof=IN_PROGRESS DONE"`
 	Type         string     `validate:"oneof=CI CD CI/CD"`

Review Comment:
   fixed



##########
plugins/webhook/api/cicd_pipeline.go:
##########
@@ -18,41 +18,202 @@ limitations under the License.
 package api
 
 import (
+	"fmt"
 	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models/domainlayer"
+	"github.com/apache/incubator-devlake/models/domainlayer/devops"
+	"github.com/apache/incubator-devlake/models/domainlayer/ticket"
 	"github.com/apache/incubator-devlake/plugins/core"
+	"github.com/apache/incubator-devlake/plugins/core/dal"
+	"github.com/apache/incubator-devlake/plugins/helper"
 	"github.com/apache/incubator-devlake/plugins/webhook/models"
+	"github.com/go-playground/validator/v10"
 	"net/http"
 	"time"
 )
 
-type WebhookPipelineRequest struct {
-	Id           string     `validate:"required"`
-	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT"`
+type WebhookTaskRequest struct {
+	// PipelineName can be filled by any string unique in one pipeline
+	PipelineName string `mapstructure:"pipeline_name" validate:"required"`
+
+	Name         string     `validate:"required"` // Name should be unique in one pipeline
+	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT IN_PROGRESS"`
 	Status       string     `validate:"oneof=IN_PROGRESS DONE"`
 	Type         string     `validate:"oneof=CI CD CI/CD"`
-	CreatedDate  time.Time  `mapstructure:"created_date" validate:"required"`
+	StartedDate  time.Time  `mapstructure:"created_date" validate:"required"`
 	FinishedDate *time.Time `mapstructure:"finished_date"`
 
-	Repo      string `validate:"required"`
+	RepoId    string `mapstructure:"repo_id" validate:"required"` // RepoId should be unique string
 	Branch    string
 	CommitSha string `mapstructure:"commit_sha"`
 }
 
-// PostCicdPipeline
+// PostCicdTask
 // @Summary create pipeline by webhook
-// @Description Create pipeline by webhook, example: {"id":"A123123","result":"one of SUCCESS/FAILURE/ABORT","status":"one of IN_PROGRESS/DONE","type":"CI/CD","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}
+// @Description Create pipeline by webhook.<br/>
+// @Description example1: {"pipeline_name":"A123","name":"unit-test","result":"IN_PROGRESS","status":"IN_PROGRESS","type":"CI","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo_id":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}<br/>

Review Comment:
   fixed, `oneof` contains not empty



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] likyh commented on pull request #3052: feat: finish pipeline and issue webhook

Posted by GitBox <gi...@apache.org>.
likyh commented on PR #3052:
URL: https://github.com/apache/incubator-devlake/pull/3052#issuecomment-1250336755

   use new type(); add environment for tasks (pipeline's environment will always empty).
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-devlake] klesh commented on a diff in pull request #3052: feat: finish pipeline and issue webhook

Posted by GitBox <gi...@apache.org>.
klesh commented on code in PR #3052:
URL: https://github.com/apache/incubator-devlake/pull/3052#discussion_r973863262


##########
plugins/webhook/api/cicd_pipeline.go:
##########
@@ -18,41 +18,199 @@ limitations under the License.
 package api
 
 import (
+	"fmt"
 	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/models/domainlayer"
+	"github.com/apache/incubator-devlake/models/domainlayer/devops"
+	"github.com/apache/incubator-devlake/models/domainlayer/ticket"
 	"github.com/apache/incubator-devlake/plugins/core"
+	"github.com/apache/incubator-devlake/plugins/core/dal"
+	"github.com/apache/incubator-devlake/plugins/helper"
 	"github.com/apache/incubator-devlake/plugins/webhook/models"
+	"github.com/go-playground/validator/v10"
 	"net/http"
 	"time"
 )
 
-type WebhookPipelineRequest struct {
-	Id           string     `validate:"required"`
-	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT"`
+type WebhookTaskRequest struct {
+	// PipelineName can be filled by any string unique in one pipeline
+	PipelineName string `mapstructure:"pipeline_name" validate:"required"`
+
+	Name         string     `validate:"required"` // Name should be unique in one pipeline
+	Result       string     `validate:"oneof=SUCCESS FAILURE ABORT IN_PROGRESS"`
 	Status       string     `validate:"oneof=IN_PROGRESS DONE"`
-	Type         string     `validate:"oneof=CI CD CI/CD"`
-	CreatedDate  time.Time  `mapstructure:"created_date" validate:"required"`
+	Type         string     `validate:"oneof=TEST LINT BUILD DEPLOYMENT"`
+	Environment  string     `validate:"oneof=PRODUCTION STAGING TESTING"`
+	StartedDate  time.Time  `mapstructure:"created_date" validate:"required"`
 	FinishedDate *time.Time `mapstructure:"finished_date"`
 
-	Repo      string `validate:"required"`
+	RepoId    string `mapstructure:"repo_id" validate:"required"` // RepoId should be unique string
 	Branch    string
 	CommitSha string `mapstructure:"commit_sha"`
 }
 
-// PostCicdPipeline
+// PostCicdTask
 // @Summary create pipeline by webhook
-// @Description Create pipeline by webhook, example: {"id":"A123123","result":"one of SUCCESS/FAILURE/ABORT","status":"one of IN_PROGRESS/DONE","type":"CI/CD","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}
+// @Description Create pipeline by webhook.<br/>
+// @Description example1: {"pipeline_name":"A123","name":"unit-test","result":"IN_PROGRESS","status":"IN_PROGRESS","type":"TEST","environment":"PRODUCTION","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo_id":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}<br/>
+// @Description example2: {"pipeline_name":"A123","name":"unit-test","result":"SUCCESS","status":"DONE","type":"DEPLOYMENT","environment":"PRODUCTION","created_date":"2020-01-01T12:00:00+00:00","finished_date":"2020-01-01T12:59:59+00:00","repo_id":"devlake","branch":"main","commit_sha":"015e3d3b480e417aede5a1293bd61de9b0fd051d"}<br/>
+// @Description When request webhook first time for each pipeline, it will be created.
+// @Description So we suggest request before task start and after pipeline finish.
+// @Description Remember fill all data to request after pipeline finish.
 // @Tags plugins/webhook
-// @Param body body WebhookPipelineRequest true "json body"
+// @Param body body WebhookTaskRequest true "json body"
 // @Success 200
 // @Failure 400  {string} errcode.Error "Bad Request"
+// @Failure 403  {string} errcode.Error "Forbidden"
 // @Failure 500  {string} errcode.Error "Internal Error"
-// @Router /plugins/webhook/:connectionId/cicd_pipelines [POST]
-func PostCicdPipeline(input *core.ApiResourceInput) (*core.ApiResourceOutput, errors.Error) {
+// @Router /plugins/webhook/:connectionId/cicd_tasks [POST]
+func PostCicdTask(input *core.ApiResourceInput) (*core.ApiResourceOutput, errors.Error) {
 	connection := &models.WebhookConnection{}
 	err := connectionHelper.First(connection, input.Params)
 	if err != nil {
 		return nil, err
 	}
-	// TODO save pipeline
+	// get request
+	request := &WebhookTaskRequest{}
+	err = helper.DecodeMapStruct(input.Body, request)
+	if err != nil {
+		return &core.ApiResourceOutput{Body: err.Error(), Status: http.StatusBadRequest}, nil
+	}
+	// validate
+	vld = validator.New()
+	err = errors.Convert(vld.Struct(request))
+	if err != nil {
+		return nil, errors.BadInput.Wrap(vld.Struct(request), `input json error`)
+	}
+
+	db := basicRes.GetDal()
+	pipelineId := fmt.Sprintf("%s:%d:%s", "webhook", connection.ID, request.PipelineName)
+	domainCicdTask := &devops.CICDTask{
+		DomainEntity: domainlayer.DomainEntity{
+			Id: fmt.Sprintf("%s:%d:%s:%s", "webhook", connection.ID, request.PipelineName, request.Name),
+		},
+		PipelineId:   pipelineId,
+		Name:         request.Name,
+		Result:       request.Result,
+		Status:       request.Status,
+		Type:         request.Type,
+		Environment:  request.Environment,
+		StartedDate:  request.StartedDate,
+		FinishedDate: request.FinishedDate,
+	}
+	if domainCicdTask.FinishedDate != nil {
+		domainCicdTask.DurationSec = uint64(domainCicdTask.FinishedDate.Sub(domainCicdTask.StartedDate).Seconds())
+	}
+
+	domainPipeline := &devops.CICDPipeline{}
+	err = db.First(domainPipeline, dal.Where("id = ?", pipelineId))
+	if err != nil {
+		domainPipeline = &devops.CICDPipeline{
+			DomainEntity: domainlayer.DomainEntity{
+				Id: pipelineId,
+			},
+			Name:         request.PipelineName,
+			Result:       ``,
+			Status:       `IN_PROGRESS`,
+			Type:         ``,
+			CreatedDate:  request.StartedDate,
+			FinishedDate: nil,
+		}
+	} else if domainPipeline.Status == `DONE` {
+		return nil, errors.Forbidden.New(`can not receive this task because pipeline has already been done.`)
+	}
+
+	domainPipelineRepo := &devops.CiCDPipelineCommit{

Review Comment:
   Please rename this to `commit` rather than `repo`



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@devlake.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org