This is an automated email from the ASF dual-hosted git repository.

abeizn pushed a commit to branch feat#6162-webhook
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/feat#6162-webhook by this push:
     new 2c3b424ed feat: allow deployment webhook to push deployments to 
multiple repos in one request
2c3b424ed is described below

commit 2c3b424ed13675738a064c637bb4aed850d0284a
Author: abeizn <[email protected]>
AuthorDate: Wed Nov 29 14:14:15 2023 +0800

    feat: allow deployment webhook to push deployments to multiple repos in one 
request
---
 .../domainlayer/devops/cicd_deployment_commit.go   |   3 +-
 ...27_add_commit_msg_to_cicd_deployment_commits.go |  52 ++++++
 backend/core/models/migrationscripts/register.go   |   1 +
 backend/plugins/webhook/api/deployments.go         | 178 +++++++++++++++------
 4 files changed, 185 insertions(+), 49 deletions(-)

diff --git a/backend/core/models/domainlayer/devops/cicd_deployment_commit.go 
b/backend/core/models/domainlayer/devops/cicd_deployment_commit.go
index 398dfe96a..cdc5c1783 100644
--- a/backend/core/models/domainlayer/devops/cicd_deployment_commit.go
+++ b/backend/core/models/domainlayer/devops/cicd_deployment_commit.go
@@ -38,6 +38,7 @@ type CicdDeploymentCommit struct {
        FinishedDate                  *time.Time
        DurationSec                   *float64
        CommitSha                     string 
`gorm:"primaryKey;type:varchar(255)"`
+       CommitMsg                     string
        RefName                       string `gorm:"type:varchar(255)"` // to 
delete?
        RepoId                        string `gorm:"type:varchar(255)"`
        RepoUrl                       string `gorm:"index;not null"`
@@ -64,6 +65,6 @@ func (cicdDeploymentCommit CicdDeploymentCommit) 
ToDeployment() *CICDDeployment
                CreatedDate:    cicdDeploymentCommit.CreatedDate,
                StartedDate:    cicdDeploymentCommit.StartedDate,
                FinishedDate:   cicdDeploymentCommit.FinishedDate,
-               DurationSec:    cicdDeploymentCommit.DurationSec,
+               DurationSec:    cicdDeploymentCommit.DurationSec,       
        }
 }
diff --git 
a/backend/core/models/migrationscripts/20231127_add_commit_msg_to_cicd_deployment_commits.go
 
b/backend/core/models/migrationscripts/20231127_add_commit_msg_to_cicd_deployment_commits.go
new file mode 100644
index 000000000..087ec8a9d
--- /dev/null
+++ 
b/backend/core/models/migrationscripts/20231127_add_commit_msg_to_cicd_deployment_commits.go
@@ -0,0 +1,52 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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.
+*/
+
+package migrationscripts
+
+import (
+       "github.com/apache/incubator-devlake/core/context"
+       "github.com/apache/incubator-devlake/core/errors"
+       "github.com/apache/incubator-devlake/core/plugin"
+)
+
+var _ plugin.MigrationScript = (*addCommitMsg)(nil)
+
+type cicdDeploymentCommit20231127 struct {
+       CommitMsg string
+}
+
+func (cicdDeploymentCommit20231127) TableName() string {
+       return "cicd_deployment_commits"
+}
+
+type addCommitMsg struct{}
+
+func (u *addCommitMsg) Up(basicRes context.BasicRes) errors.Error {
+       db := basicRes.GetDal()
+       if err := db.AutoMigrate(&cicdDeploymentCommit20231127{}); err != nil {
+               return err
+       }
+       return nil
+}
+
+func (*addCommitMsg) Version() uint64 {
+       return 20231127142100
+}
+
+func (*addCommitMsg) Name() string {
+       return "add commit_msg to cicd_deployment_commit table"
+}
diff --git a/backend/core/models/migrationscripts/register.go 
b/backend/core/models/migrationscripts/register.go
index 440125bb6..c329ec8c1 100644
--- a/backend/core/models/migrationscripts/register.go
+++ b/backend/core/models/migrationscripts/register.go
@@ -98,5 +98,6 @@ func All() []plugin.MigrationScript {
                new(removePositionFromPullRequestComments),
                new(changeDurationSecToFloat64),
                new(addOriginalStatusAndResultToDevOpsTables),
+               new(addCommitMsg),
        }
 }
diff --git a/backend/plugins/webhook/api/deployments.go 
b/backend/plugins/webhook/api/deployments.go
index dd2177296..f8966f4c3 100644
--- a/backend/plugins/webhook/api/deployments.go
+++ b/backend/plugins/webhook/api/deployments.go
@@ -20,11 +20,13 @@ package api
 import (
        "crypto/md5"
        "fmt"
-       "github.com/apache/incubator-devlake/helpers/dbhelper"
-       "github.com/go-playground/validator/v10"
        "net/http"
+       "strings"
        "time"
 
+       "github.com/apache/incubator-devlake/helpers/dbhelper"
+       "github.com/go-playground/validator/v10"
+
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/apache/incubator-devlake/core/models/domainlayer"
        "github.com/apache/incubator-devlake/core/models/domainlayer/devops"
@@ -36,18 +38,31 @@ import (
 type WebhookDeployTaskRequest struct {
        PipelineId string `mapstructure:"pipeline_id"`
        // RepoUrl should be unique string, fill url or other unique data
-       RepoId    string `mapstructure:"repo_id"`
-       RepoUrl   string `mapstructure:"repo_url" validate:"required"`
-       CommitSha string `mapstructure:"commit_sha" validate:"required"`
-       RefName   string `mapstructure:"ref_name"`
-       Result    string `mapstructure:"result"`
+       RepoId string `mapstructure:"repo_id"`
+       Result string `mapstructure:"result"`
        // start_time and end_time is more readable for users,
        // StartedDate and FinishedDate is same as columns in db.
        // So they all keep.
        CreatedDate  *time.Time `mapstructure:"create_time"`
        StartedDate  *time.Time `mapstructure:"start_time" validate:"required"`
        FinishedDate *time.Time `mapstructure:"end_time"`
+       RepoUrl      string     `mapstructure:"repo_url"`
        Environment  string     `validate:"omitempty,oneof=PRODUCTION STAGING 
TESTING DEVELOPMENT"`
+       Name         string     `mapstructure:"name"`
+       RefName      string     `mapstructure:"ref_name"`
+       CommitSha    string     `mapstructure:"commit_sha"`
+       CommitMsg    string     `mapstructure:"commit_msg"`
+       // DeploymentCommits is used for multiple commits in one deployment
+       DeploymentCommits []DeploymentCommit `mapstructure:"deploymentCommits" 
validate:"omitempty,dive"`
+}
+
+type DeploymentCommit struct {
+       RepoUrl     string `mapstructure:"repo_url" validate:"required"`
+       Environment string `validate:"omitempty,oneof=PRODUCTION STAGING 
TESTING DEVELOPMENT"`
+       Name        string `mapstructure:"name"`
+       RefName     string `mapstructure:"ref_name"`
+       CommitSha   string `mapstructure:"commit_sha" validate:"required"`
+       CommitMsg   string `mapstructure:"commit_msg"`
 }
 
 // PostDeploymentCicdTask
@@ -62,7 +77,7 @@ type WebhookDeployTaskRequest struct {
 // @Failure 400  {string} errcode.Error "Bad Request"
 // @Failure 403  {string} errcode.Error "Forbidden"
 // @Failure 500  {string} errcode.Error "Internal Error"
-// @Router /plugins/webhook/:connectionId/deployments [POST]
+// @Router /plugins/webhook/connections/:connectionId/deployments [POST]
 func PostDeploymentCicdTask(input *plugin.ApiResourceInput) 
(*plugin.ApiResourceOutput, errors.Error) {
        connection := &models.WebhookConnection{}
        err := connectionHelper.First(connection, input.Params)
@@ -84,19 +99,12 @@ func PostDeploymentCicdTask(input *plugin.ApiResourceInput) 
(*plugin.ApiResource
        txHelper := dbhelper.NewTxHelper(basicRes, &err)
        defer txHelper.End()
        tx := txHelper.Begin()
-       urlHash16 := fmt.Sprintf("%x", md5.Sum([]byte(request.RepoUrl)))[:16]
-       scopeId := fmt.Sprintf("%s:%d", "webhook", connection.ID)
-       deploymentCommitId := fmt.Sprintf("%s:%d:%s:%s", "webhook", 
connection.ID, urlHash16, request.CommitSha)
+
        pipelineId := request.PipelineId
-       if pipelineId == "" {
-               pipelineId = deploymentCommitId
-       }
+       scopeId := fmt.Sprintf("%s:%d", "webhook", connection.ID)
        if request.CreatedDate == nil {
                request.CreatedDate = request.StartedDate
        }
-       if request.Environment == "" {
-               request.Environment = devops.PRODUCTION
-       }
        if request.FinishedDate == nil {
                now := time.Now()
                request.FinishedDate = &now
@@ -105,39 +113,113 @@ func PostDeploymentCicdTask(input 
*plugin.ApiResourceInput) (*plugin.ApiResource
                request.Result = devops.RESULT_SUCCESS
        }
        duration := request.FinishedDate.Sub(*request.StartedDate).Seconds()
-
-       // create a deployment_commit record
-       deploymentCommit := &devops.CicdDeploymentCommit{
-               DomainEntity: domainlayer.DomainEntity{
-                       Id: deploymentCommitId,
-               },
-               CicdDeploymentId: pipelineId,
-               CicdScopeId:      scopeId,
-               Name:             fmt.Sprintf(`deployment for %s`, 
request.CommitSha),
-               Result:           request.Result,
-               Status:           devops.STATUS_DONE,
-               OriginalResult:   request.Result,
-               OriginalStatus:   devops.STATUS_DONE,
-               Environment:      request.Environment,
-               CreatedDate:      *request.CreatedDate,
-               StartedDate:      request.StartedDate,
-               FinishedDate:     request.FinishedDate,
-               DurationSec:      &duration,
-               CommitSha:        request.CommitSha,
-               RefName:          request.RefName,
-               RepoId:           request.RepoId,
-               RepoUrl:          request.RepoUrl,
-       }
-       err = tx.CreateOrUpdate(deploymentCommit)
-       if err != nil {
-               logger.Error(err, "create deployment commit")
-               return nil, err
+       name := request.Name
+       if name == "" {
+               if request.DeploymentCommits == nil {
+                       name = fmt.Sprintf(`deployment for %s`, 
request.CommitSha)
+               } else {
+                       commit_sha_list := []string{}
+                       for _, commit := range request.DeploymentCommits {
+                               commit_sha_list = append(commit_sha_list, 
commit.CommitSha)
+                       }
+                       name = fmt.Sprintf(`deployment for %s`, 
strings.Join(commit_sha_list, ","))
+               }
        }
 
-       // create a deployment record
-       if err = tx.CreateOrUpdate(deploymentCommit.ToDeployment()); err != nil 
{
-               logger.Error(err, "create deployment")
-               return nil, err
+       if request.DeploymentCommits == nil {
+               if request.CommitSha == "" || request.RepoUrl == "" {
+                       return nil, errors.Convert(fmt.Errorf("commit_sha or 
repo_url is required"))
+               }
+               urlHash16 := fmt.Sprintf("%x", 
md5.Sum([]byte(request.RepoUrl)))[:16]
+               deploymentCommitId := fmt.Sprintf("%s:%d:%s:%s", "webhook", 
connection.ID, urlHash16, request.CommitSha)
+               if pipelineId == "" {
+                       pipelineId = deploymentCommitId
+               }
+               if request.Environment == "" {
+                       request.Environment = devops.PRODUCTION
+               }
+
+               // create a deployment_commit record
+               deploymentCommit := &devops.CicdDeploymentCommit{
+                       DomainEntity: domainlayer.DomainEntity{
+                               Id: deploymentCommitId,
+                       },
+                       CicdDeploymentId: pipelineId,
+                       CicdScopeId:      scopeId,
+                       Name:             name,
+                       Result:           request.Result,
+                       Status:           devops.STATUS_DONE,
+                       OriginalResult:   request.Result,
+                       OriginalStatus:   devops.STATUS_DONE,
+                       CreatedDate:      *request.CreatedDate,
+                       StartedDate:      request.StartedDate,
+                       FinishedDate:     request.FinishedDate,
+                       DurationSec:      &duration,
+                       RepoId:           request.RepoId,
+                       RepoUrl:          request.RepoUrl,
+                       Environment:      request.Environment,
+                       RefName:          request.RefName,
+                       CommitSha:        request.CommitSha,
+                       CommitMsg:        request.CommitMsg,
+               }
+               err = tx.CreateOrUpdate(deploymentCommit)
+               if err != nil {
+                       logger.Error(err, "create deployment commit")
+                       return nil, err
+               }
+
+               // create a deployment record
+               if err = tx.CreateOrUpdate(deploymentCommit.ToDeployment()); 
err != nil {
+                       logger.Error(err, "create deployment")
+                       return nil, err
+               }
+       } else {
+               for _, commit := range request.DeploymentCommits {
+                       urlHash16 := fmt.Sprintf("%x", 
md5.Sum([]byte(commit.RepoUrl)))[:16]
+                       deploymentCommitId := fmt.Sprintf("%s:%d:%s:%s", 
"webhook", connection.ID, urlHash16, commit.CommitSha)
+                       if pipelineId == "" {
+                               pipelineId = deploymentCommitId
+                       }
+                       if commit.Environment == "" {
+                               commit.Environment = devops.PRODUCTION
+                       }
+                       // create a deployment_commit record
+                       deploymentCommit := &devops.CicdDeploymentCommit{
+                               DomainEntity: domainlayer.DomainEntity{
+                                       Id: deploymentCommitId,
+                               },
+                               CicdDeploymentId: pipelineId,
+                               CicdScopeId:      scopeId,
+                               Result:           request.Result,
+                               Status:           devops.STATUS_DONE,
+                               OriginalResult:   request.Result,
+                               OriginalStatus:   devops.STATUS_DONE,
+                               CreatedDate:      *request.CreatedDate,
+                               StartedDate:      request.StartedDate,
+                               FinishedDate:     request.FinishedDate,
+                               DurationSec:      &duration,
+                               RepoId:           request.RepoId,
+                               Name:             fmt.Sprintf(`deployment for 
%s`, commit.CommitSha),
+                               RepoUrl:          commit.RepoUrl,
+                               Environment:      commit.Environment,
+                               RefName:          commit.RefName,
+                               CommitSha:        commit.CommitSha,
+                               CommitMsg:        commit.CommitMsg,
+                       }
+                       err = tx.CreateOrUpdate(deploymentCommit)
+                       if err != nil {
+                               logger.Error(err, "create deployment commit")
+                               return nil, err
+                       }
+
+                       // create a deployment record
+                       deploymentCommit.Name = name
+                       if err = 
tx.CreateOrUpdate(deploymentCommit.ToDeployment()); err != nil {
+                               logger.Error(err, "create deployment")
+                               return nil, err
+                       }
+               }
+
        }
 
        return &plugin.ApiResourceOutput{Body: nil, Status: http.StatusOK}, nil

Reply via email to